Redis 限流的 3 種方式,還有誰不會!
1第一種:基于Redis的setnx的操作
2第二種:基于Redis的數(shù)據(jù)結(jié)構(gòu)zset
public?Response?limitFlow(){
????Long?currentTime?=?new?Date().getTime();
????System.out.println(currentTime);
????if(redisTemplate.hasKey("limit"))?{
????????Integer?count?=?redisTemplate.opsForZSet().rangeByScore("limit",?currentTime?-??intervalTime,?currentTime).size();????????//?intervalTime是限流的時間?
????????System.out.println(count);
????????if?(count?!=?null?&&?count?>?5)?{
????????????return?Response.ok("每分鐘最多只能訪問5次");
????????}
????}
????redisTemplate.opsForZSet().add("limit",UUID.randomUUID().toString(),currentTime);
????return?Response.ok("訪問成功");
}
通過上述代碼可以做到滑動窗口的效果,并且能保證每N秒內(nèi)至多M個請求,缺點就是zset的數(shù)據(jù)結(jié)構(gòu)會越來越大。實現(xiàn)方式相對也是比較簡單的。
3第三種:基于Redis的令牌桶算法
//?輸出令牌
public?Response?limitFlow2(Long?id){
????Object?result?=?redisTemplate.opsForList().leftPop("limit_list");
????if(result?==?null){
????????return?Response.ok("當前令牌桶中無令牌");
????}
????return?Response.ok(articleDescription2);
}
再依靠Java的定時任務(wù),定時往List中rightPush令牌,當然令牌也需要唯一性,所以我這里還是用UUID進行了生成
//?10S的速率往令牌桶中添加UUID,只為保證唯一性
@Scheduled(fixedDelay?=?10_000,initialDelay?=?0)
public?void?setIntervalTimeTask(){
????redisTemplate.opsForList().rightPush("limit_list",UUID.randomUUID().toString());
}
綜上,代碼實現(xiàn)起始都不是很難,針對這些限流方式我們可以在AOP或者filter中加入以上代碼,用來做到接口的限流,最終保護你的網(wǎng)站。
有問題歡迎留言探討。
評論
圖片
表情
