網站首頁 編程語言 正文
限流算法
常見的限流算法
- 計數器算法
- 漏桶算法
- 令牌桶算法
計數器算法
??顧名思義,計數器算法是指在一定的時間窗口內允許的固定數量的請求.比如,2s內允許10個請求,30s內允許100個請求等等.如果設置的時間粒度越細,那么相對而言限流就會越平滑,控制的粒度就會更細.
場景分析
試想,如果設置的粒度比較粗會出現什么樣的問題呢?如下圖設置一個?1000/3s?的限流計數統計.
圖中的限流策略為3s內允許的最大請求量為1000,那么會出現2個極端:
?
極端情況1:
- 第1s請流量為10,??
- 第2s請流量為10,??
- 第3s請流量突然激增到980.這意味著在這一刻,有大量的請求蜂擁而至,假設服務每秒能處理的
上線為800/1s,但是此刻卻有超過這個量級的請求量,那么后果是不堪設想的.
極端情況2:??
- 第1s請流量突然就達到990,
- 留給后續第2s,3s的可請求數量就非常少了,可能會出現大量的拒絕請求.
結論:
如果用統計計數算法,盡量保持粒度切割精細.
算法實現
redis的ttl特性完美的滿足了這一需求,將時間窗口設置為key的失效時間,然后將key的值每次請求+1即可.偽代碼實現思路:
//1.判斷是否存在該key
if(EXIT(key)){
// 1.1自增后判斷是否大于最大值,并返回結果
if(INCR(key) > maxPermit){
return false;
}
return true;
}
//2.不存在key,則設置key初始值為1,失效時間為3秒
SET(KEY,1);
EXPIRE(KEY,3);
漏銅算法
漏桶算法核心概念:
- 桶的容量是固定的,并且水流以一個固定的速率流出;
- 流入的水流可以是任意速率;
- 如果流入的水流超出了桶的容量,則后續流入的水流溢出(請求被丟棄)。
- 如果桶內沒有水,則不需要流出
缺點:
不難想象漏桶算法并不能很好的應對突發的流量限制,在某一個時間段流量激增,則漏桶算法處理就比較無能為力.這個時候就需要用到和他相反設計的令牌桶算法
令牌桶算法:
如上圖所示,整個請求流程一目了然.簡單概括如下:
1.用戶請求資源時首選從桶里獲取令牌,如果有令牌則放行,如此同時桶里的令牌數量-1
2.于此同時,以一定的速率往桶里加入令牌,這個速度是可根據實際場景隨意設置.
算法實現
var key; var maxPermit;//桶的容量,即最大請求限制 var expire;//失效時間 var bucketInterval;//每次向桶里添加令牌的時間間隔 var bucketNum;//每次向桶里添加令牌的個數 var lastTimeKey = key +"last";//標記上一次操作時間 //判斷是否存在該key if(EXIT(key)){ var value = GET(key); var diffTime = now() - lastTimeKey; // 1.1判斷是否超出時間間隔 if(diffTime > bucketInterval){ // 1.2根據時間間隔,計算出應該向桶里添加令牌的個數 local maxValue = value+math.floor(diff/interval)*step; if (maxValue > limit) value = limit; else value = maxValue; //設置key的值及操作時間 SET(key,value); SET(lastTimeKey,now()); } // 2.1在時間間隔內,判斷桶里是否有值 if(value <= 0){ reurn false; }else{ // 2.2 減1 DECR(key); } reture true; } //2.不存在key,則設置key初始值為maxPermit-1 SET(key,maxPermit-1); EXPIRE(lastTimeKey,now());
上面實現代碼只是偽代碼,提供的是一種思路而已. 仔細想來其中某個環節其實并不完美.大家可以參考Guava的ratelimit實現思路,他的限流就是基于令牌桶算法,但是比較遺憾的是在單機下的限流.
思考:??
就是時間間隔如果過長的話,一次性向桶里添加的令牌數量則是桶的最大容量!那么某個時間的瞬間請求過來,服務器的壓力是非常大的.
所以此處增加令牌數可以設置的稍微合理些,哪怕間隔時間再長!
原文鏈接:https://segmentfault.com/a/1190000017078491
相關推薦
- 2022-10-07 基于Python實現文本文件轉Excel_python
- 2023-07-16 spring boot 支持跨域配置
- 2022-12-19 Python?完美解決?Import?“模塊“?could?not?be?resolved?...的
- 2022-09-29 Go語言select語句用法示例_Golang
- 2022-09-09 Python?OpenCV?Hough直線檢測算法的原理實現_python
- 2022-10-22 Kotlin基礎通關之字符串與數字類型_Android
- 2022-05-21 云原生技術kubernetes之volumes容器的使用_云其它
- 2022-02-13 C語言-操作符(詳細)和表達式求值
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支