一、固定窗口
所謂固定窗口限流即時(shí)間窗口的起始和結(jié)束時(shí)間是固定的,在固定時(shí)間段內(nèi)允許要求的請求數(shù)量訪問,超過則拒絕;當(dāng)固定時(shí)間段結(jié)束后,再重新開始下一個(gè)時(shí)間段進(jìn)行計(jì)數(shù)。
我們可以根據(jù)當(dāng)前的時(shí)間,以分鐘為時(shí)間段,每分鐘都生成一個(gè)key,用來inc,當(dāng)達(dá)到請求數(shù)量就返回一些友好信息。
固定窗口
/**
* @author: AngJie
* @create: 2022-07-26 14:41
**/
@RestController
@RequestMapping("/redisTest")
public class RedisTestController {
@Autowired
private RedisTemplate redisTemplate;
private static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm");
@GetMapping("/Fixed")
public String testFixedWindow() {
String now = formatter.format(LocalDateTime.now());
Long count = redisTemplate.opsForValue().increment(now + ":fixed");
if (count > 5) {
return "不好意思,服務(wù)器正忙,請一分鐘后再試......";
} else {
return "服務(wù)端正在處理";
}
}
}
?
該方式優(yōu)點(diǎn)是比較簡單粗暴,缺點(diǎn)是不夠靈活,對于邊界問題不能夠處理,如設(shè)置的時(shí)間段剛開始時(shí)流量占滿了設(shè)置的最大次數(shù),后面一段時(shí)間則不能夠再進(jìn)行訪問,必須等該時(shí)間段過了后才可以再次訪問。
二、滑動窗口
針對固定窗口限流的問題,可以采用滑動窗口來優(yōu)化改善。所謂滑動窗口即設(shè)置的時(shí)間窗口的起始和結(jié)束時(shí)間是不斷變化的,時(shí)間差值不變,允許的請求數(shù)量不變。
我們可以將請求打造成一個(gè)zset數(shù)組,當(dāng)每一次請求進(jìn)來的時(shí)候,value保持唯一,可以用UUID生成,而score可以用當(dāng)前時(shí)間戳表示,因?yàn)閟core我們可以用來計(jì)算當(dāng)前時(shí)間戳之內(nèi)有多少的請求數(shù)量。而zset數(shù)據(jù)結(jié)構(gòu)也提供了zrange方法讓我們可以很輕易的獲取到2個(gè)時(shí)間戳內(nèi)有多少請求。
/**
* @author: AngJie
* @create: 2022-07-26 14:41
**/
@RestController
@RequestMapping("/redisTest")
public class RedisTestController {
@Autowired
private RedisTemplate redisTemplate;
@GetMapping("/Sliding")
public String testSlidingWindow() {
Long currentTime = System.currentTimeMillis();
System.out.println(currentTime);
if (redisTemplate.hasKey("limit")) {
// intervalTime是限流的時(shí)間
Long intervalTime = 60000L;
Integer count = redisTemplate.opsForZSet().rangeByScore("limit", currentTime - intervalTime, currentTime).size();
System.out.println(count);
if (count != null && count > 5) {
return "每分鐘最多只能訪問5次";
}
}
redisTemplate.opsForZSet().add("limit", UUID.randomUUID().toString(), currentTime);
return "訪問成功";
}
}
?
通過上述代碼可以做到滑動窗口的效果,并且能保證每N秒內(nèi)至多M個(gè)請求,缺點(diǎn)就是zset的數(shù)據(jù)結(jié)構(gòu)會越來越大。實(shí)現(xiàn)方式相對也是比較簡單的。
三、令牌桶
Redisson可以實(shí)現(xiàn)很多東西,在Redis的基礎(chǔ)上,Redisson做了超多的封裝,不僅可以用來實(shí)現(xiàn)分布式鎖,還可以幫助我們實(shí)現(xiàn)令牌桶限流。
RateLimter主要作用就是可以限制調(diào)用接口的次數(shù)。主要原理就是調(diào)用接口之前,需要擁有指定個(gè)令牌。限流器每秒會產(chǎn)生X個(gè)令牌放入令牌桶,調(diào)用接口需要去令牌桶里面拿令牌。如果令牌被其它請求拿完了,那么自然而然,當(dāng)前請求就調(diào)用不到指定的接口。
RateLimter實(shí)現(xiàn)限流文章來源:http://www.zghlxwxcb.cn/news/detail-677507.html
/**
* @author: AngJie
* @create: 2022-07-26 14:41
**/
@RestController
@RequestMapping("/redisTest")
public class RedisTestController {
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private Redisson redisson;
@GetMapping("/Token")
public String testTokenBucket() {
RRateLimiter rateLimiter = redisson.getRateLimiter("myRateLimiter");
// 最大流速 = 每10秒鐘產(chǎn)生1個(gè)令牌
rateLimiter.trySetRate(RateType.OVERALL, 1, 10, RateIntervalUnit.SECONDS);
//需要1個(gè)令牌
if (rateLimiter.tryAcquire(1)) {
return "令牌桶里面有可使用的令牌";
}
return "不好意思,請過十秒鐘再來~~~~~~~";
}
}
?文章來源地址http://www.zghlxwxcb.cn/news/detail-677507.html
到了這里,關(guān)于Redis實(shí)現(xiàn)限流的三種方式的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!