1. 程式人生 > >常見限流方案設計與實現

常見限流方案設計與實現

高併發系統設計的3個利器:快取、限流、降級,本文就限流相關演算法,分析其設計與實現。

從分散式角度來看,限流可分為分散式限流(比如基於Sentinel或者Redis的叢集限流)和單機限流。從演算法實現角度來看,限流演算法可分為漏桶演算法、令牌桶演算法和滑動時間視窗演算法。下面主要分析這3種限流演算法和分散式限流實現方案。

漏桶演算法

把請求比作是水,水來了都先放進桶裡,並以恆定速度出水(處理請求),當水流量過大會導致桶溢位,即拒絕服務。請求的最大處理速度也就是水從漏桶流出的速度。

基於漏桶(桶+恆定處理速率),可以起到對請求整流效果。漏桶演算法可基於執行緒池來實現,執行緒池使用固定容量的阻塞佇列+固定個數的處理執行緒來實現;最簡單且最常見的漏桶思想的實現就是基於SynchronousQueue的執行緒池,其相當於一個空桶+固定處理執行緒 : )。

注意:原生的漏桶演算法以恆定速度出水(處理請求),但是實際場景中請求的處理耗時可能不相等,為了實現恆定速率,一般都是限定同時處理請求的最大執行緒數。

令牌桶演算法

很多場景中,需要允許某種程度的突發請求,請求的最大速度也就是所有桶大小。這時候漏桶演算法就不合適了,令牌桶演算法更為適合。

令牌桶演算法的原理是系統以恆定的速率產生令牌,然後把令牌放到令牌桶中,令牌桶有一個容量,當令牌桶滿了的時候,再向其中放令牌,那麼多餘的令牌會被丟棄;當想要處理一個請求的時候,需要從令牌桶中取出一個令牌,如果此時令牌桶中沒有令牌,那麼則拒絕該請求。

令牌桶演算法的一個實現方案是:起一個Timer執行緒以固定頻率往桶中放令牌,桶滿時令牌溢位,業務執行緒在獲取令牌時直接從桶中獲取即可。該方案容易理解,但是需要一個Timer執行緒,資源佔用較重。

令牌桶演算法還有一種實現方案不需要用Timer執行緒,這個經典實現就是Guava中的RateLimiterRateLimiter實現原理如下:

  1. startTick記錄RateLimiter初始化時的時間戳(單位ns),後續nowMicros(當前時間點)都是取(System.nanoTime()-startTick)/1000;
  2. nextFreeTicketMicros記錄下次可獲取令牌的開始時間點,在RateLimiter初始化和獲取到令牌之後會進行更新;
  3. 如果nowMicros大於等於nextFreeTicketMicros,表示可以獲取令牌;如果nowMicros大於nextFreeTicketMicros,會計算二者差值併除以放一個令牌的週期,然後賦值給storedPermits
    欄位(表示當前桶中令牌數,注意不能超過桶容量);
  4. 然後storedPermits減去當前需要令牌數,如果此時要獲取令牌數大於storedPermits,那麼會將nextFreeTicketMicros再往後推進(要獲取令牌 - storedPermits) * 放一個令牌的週期 的時間。

更具體的步驟及程式碼實現可參考RateLimiter原始碼,這裡不再贅述。

從步驟4可以看出,初始化一個RateLimiter.create(100),是可以執行rateLimiter.tryAcquire(200)的,只不多會將nextFreeTicketMicros再往後推進而已。

滑動時間視窗演算法

滑動時間視窗演算法就是根據當前時間獲取對應的時間視窗,時間視窗儲存有流量相關的統計值,根據該統計值判斷是否觸發流控。

一般來說,時間視窗可以迴圈複用,在複用時重新初始化即可,具體實現可參考sentinel的滑動視窗實現。滑動時間視窗能夠支援的瞬時流量最大可為該視窗上限,而令牌桶演算法能夠支援的瞬時流量最大為桶大小;注意,滑動時間視窗演算法中獲取token數量一次最大不能超過視窗上限,而RateLimiter實現的令牌桶可以支援一次獲取超過桶大小的token。

分散式限流

上述所說的幾種限流都是單臺機器上的限流演算法,有些場景下我們還需要分散式限流,一種是基於Redis做分散式限流,另一種類似於Sentinel分散式限流。

Sentinel

Sentinel分散式限流是啟動一個token server伺服器,其他sentinel client端就是token client端,當做限流操作時,從token server獲取token,獲取成功表示未觸發限流;否則表示觸發了限流;通訊出現異常,可配置降級走本地Sentinel限流機制。分散式限流文件:Sentinel叢集流控

sentinel的分散式限流是token client呼叫以下方法到服務端獲取token,相當於是每次都會獲取acquireCount個token:

//獲取令牌Token, 引數規則Id,獲取令牌數,優先順序 
TokenResult requestToken(Long ruleId, int acquireCount, boolean prioritized); 

基於Redis限流

基於Redis做限流操作,使用lua指令碼保證命令原子性,比如qps設定為10,如果key不存在,就設定key過期時間1s,value=1;如果value小於10,則自增value;value達到10觸發流控。示例lua程式碼如下:

local key = "rate.limit:" .. KEYS[1]
local limit = tonumber(ARGV[1])
local expire_time = ARGV[2]

local is_exists = redis.call("EXISTS", key)
if is_exists == 1 then
    if redis.call("INCR", key) > limit then
        return 0
    else
        return 1
    end
else
    redis.call("SET", key, 1)
    redis.call("EXPIRE", key, expire_time)
    return 1
end

常用的限流演算法有漏桶、令牌桶和滑動視窗,根據具體場景可選擇不同限流演算法;如果需要叢集限流,可選用Sentinel或者基於Redis做分散式限流。

關於Sentinel,估計挺多小夥伴還不知道Sentinel是個什麼東東,Sentinel是一個以流量為切入點,從流量控制、熔斷降級、系統負載保護等多個維度保護服務的穩定性的框架。github地址為:https://github.com/alibaba/Sentinel。

筆者整理了一份《Sentinel不完全指南》,需要的小夥伴可以關注「TopCoder」公眾號傳送 sentinel來獲取,《Sentinel不完全指南》和Sentinel官方文件,二者互為補充,結合起來學習Sentinel效果更好呦 : )

歡迎小夥伴關注【TopCoder】閱讀更多精彩好文。

相關推薦

常見方案設計實現

高併發系統設計的3個利器:快取、限流、降級,本文就限流相關演算法,分析其設計與實現。 從分散式角度來看,限流可分為分散式限流(比如基於Sentinel或者Redis的叢集限流)和單機限流。從演算法實現角度來看,限流演算法可分為漏桶演算法、令牌桶演算法和滑動時間視窗演算法。下面主要分析這3種限流演算法和分散式限

常見演算法研究實現

一、限流場景        很多做服務介面的人或多或少的遇到這樣的場景,由於業務應用系統的負載能力有限,為了防止非預期的請求對系統壓力過大而拖垮業務應用系統。也就是面對大流量時,如何進行流量控制?服務介面的流量控制策略:分流、降級、限流等。本文討論下限流策略,雖然降低了服務

狼廠項目實踐:通用檢索框架準實時設計實現

機制 oop 定期 函數 時也 維護 次數 業務需求 一是 背景 檢索對實時性的要求很高,不僅是對索引建立、結果召回、策略幹擾等核心部分,也包括數據錄入的部分。檢索的數據流主要包括全量數據與增量數據,其中全量數據是在運行前就已經生成好的,在檢索進程運行開始時就直接解析加載了

分散式系統演算法分析實現

一、限流的關鍵作用 對於大型網際網路架構中,限流的設計是必不可少的一個環節。在給定的時間內, 客戶端請求次數過多, 伺服器就會攔截掉部分請求,避免請求流量過大造成資料庫負載高的問題。   二、常見限流演算法利弊分析 計數器限流 計數器限流主要有固定視窗計數器和滑動視窗計數器。固定視窗計數器即:在單位

通用工作引擎核心的設計實現

【摘要】:工作流技術是當前計算機應用領域的一個研究熱點,利用工作流技術對企業進行業務過程的建模和分析不僅可以規範化企業的業務流程,發現業務流程中不合理和低效的環節,進而對企業的業務過程進行優化重組,達到全面提高企業運作效率的目的,而且所建立的業務過程模型本身就是企業非常重要的知識庫和規則庫,可以成為指導企業實

jQuery架構設計實現(2.1.4版本)

需要 引入 hasclass 8.4 uri and hub 組織 移除 市面上的jQuery書太多了,良莠不齊,看了那麽多總覺得少點什麽 對"幹貨",我不喜歡就事論事的寫代碼,我想把自己所學的知識點,代碼技巧,設計思想,代碼模式能很好的表達出來,所以考慮通過分析jQuer

畢業設計-證券宣傳手機微網站的設計實現

信息 browser .com 接受 熱點 互聯網 計算機網絡 業務 結構 本文介紹基於.net的證券公司宣傳微網站手機網頁的設計與實現方法。 隨著計算機技術的快速發展,基於Web的計算機網絡金融、證券宣傳或交易網站已成為現代金融理財發展的熱點,B/S(Browser/Se

MVC實戰之排球計分(四)—— View設計實現

service family 角色 元素 需要 rom 之前 con xsl (view)視圖 視圖是用戶看到並與之交互的界面。對老式的Web應用程序來說,視圖就是由HTML元素組成的界面,在新式的Web應用程序中,HTML依舊在視圖中扮演著重要的角色,但一些新的技術已層出

MVC實戰之排球計分(五)—— Controller的設計實現

需要 strong 技術 ret web src alt 點擊 cnblogs 控制器 控制器接受用戶的輸入並調用模型和視圖去完成用戶的需求。所以當單擊Web頁面中的超鏈接和發送HTML表單時, 控制器本身不輸出任何東西和做任何處理。它只是接收請求並決定調用哪個模型構件去處

stm32視頻教程分享:心率檢測儀的設計實現

stm32視頻教程分享:心率檢測儀的設計與實現 STM32系列是基於專為要求高性能、低成本、低功耗的嵌入式應用專門設計的ARM Cortex-M3內核。 本項目主要講述了通過心律傳感器采集我們的心律數據,然後通過串口傳送到上位機中,上位機用Qt

MVC之排球比賽計分程序 ——(四)視圖的設計實現

元素 role view logs image 技術 size 之前 log (view)視圖 視圖是用戶看到並與之交互的界面。對老式的Web應用程序來說,視圖就是由HTML元素組成的界面,在新式的Web應用程序中,HTML依舊在視圖中扮演著重要的角色,但一些新的技術

MVC之排球比賽計分程序 ——(三)model類的設計實現

比賽 用戶 count class 包括 result 控制 類的設計 可能 實體類是現實實體在計算機中的表示。它貫穿於整個架構,負擔著在各層次及模塊間傳遞數據的職責。一般來說,實體類可以分為“貧血實體類”和“充血實體類”,前者僅僅保存實體的屬性,而後者還包含一些實體間的關

模型類的設計實現(四)

介紹 傳遞數據 規則 添加 play using ota 實體類 重要 實體類是現實實體在計算機中的表示。它貫穿於整個架構,負擔著在各層次及模塊間傳遞數據的職責。 一般來說,實體類可以分為“貧血實體類”和“充血實體類”,前者僅僅保存實體的屬性,而後者還包含一些實體間的關系與

jQuery技術內幕:深入解析jQuery架構設計實現原理

源碼 att root 功能 技術內幕 瀏覽器 sel 緩存 callbacks jQuery源碼(jquery-1.7.1.js)的總體結構:(function( window, undefined ) {// 構造jQuery對象 var jQuery = (fun

軟件設計實現

一個 基礎 建模 分析 解決 是什麽 哪些 模型 動態 我們寫軟件就是要解決用戶的需求,我麽需要表達和傳遞下面的信息,在“需求分析”階段,我們要搞清楚在問題領域中的現實世界中,都有哪些實體,如何抽象出我們真正的關心的屬性,實體之間的關系是什麽,在這個基礎上,用戶的需求是什麽

自己主動升級系統的設計實現(續2) -- 添加斷點續傳功能 (附最新源代碼)

blog down 決定 top lin dom itl com 關於 一.緣起      之前已經寫了兩篇關於自己主動升級系統OAUS的設計與實現的文章(第一篇、第二篇)。在為OAUS服務端添加自己主動檢測文件變更的功能(這樣每次部署版本號升級時,能夠節省非常多時間。

隊列順序存儲 - 設計實現 - API函數

http 出隊 插入 tmp .cpp tdi tree 順序 位置 隊列是一種特殊的線性表 隊列僅在線性表的兩端進行操作 隊頭(Front):取出數據元素的一端 隊尾(Rear):插入數據元素的一端 隊列不同意在中間部位進行操作! queu

IM系統中聊天記錄模塊的設計實現

人的 dex auto 由於 模型 速度 開發 構造 qlite  看到很多開發IM系統的朋友都想實現聊天記錄存儲和查詢這一不可或缺的功能,這裏我就把自己前段時間為傲瑞通(OrayTalk)開發聊天記錄模塊的經驗分享出來,供需要的朋友參考下。 一.總體設計 1.存儲位置  

視頻教程免費分享:嵌入式stm32項目開發之心率檢測儀的設計實現

視頻教程免費分享:嵌入式stm32項目開發之心率檢測儀的設計與實現 本課程主要基於心率檢測儀的設計與實現講解STM32開發技術,STM32開發板廣泛應用於儀器儀表、家用電器、醫用設備、航空航天、專用設備的智能化管理、機器人及過程控制等領域,完成數據監控、數據處理、數據傳遞等功

《Linux內核設計實現》讀書筆記(八)- 中斷下半部的處理

sym dmesg 重新編譯 warn dad style lsp 之前 res 在前一章也提到過,之所以中斷會分成上下兩部分,是由於中斷對時限的要求非常高,需要盡快的響應硬件。 主要內容: 中斷下半部處理 實現中斷下半部的機制 總結中斷下半部的實現 中斷實現