分佈式系統爲了保證系統穩定性,在服務治理的限流中會根據不一樣場景進行限流操做,常見的限流算法有:html
令牌桶:可容忍必定突發流量的速率的限流,令牌桶算法的原理是系統以恆定的速率產生令牌,而後把令牌放到令牌桶中,令牌桶有一個容量,當令牌桶滿了的時候,再向其中放令牌,那麼多餘的令牌會被丟棄;當想要處理一個請求的時候,須要從令牌桶中取出一個令牌,若是此時令牌桶中沒有令牌,那麼則拒絕該請求。java
漏斗:固定速率限流,能夠啓動整流做用。node
在分析sentinel限流以前,咱們先看下sentinel是什麼,官網說明以下:算法
隨着微服務的流行,服務和服務之間的穩定性變得愈來愈重要。Sentinel 是面向分佈式服務架構的流量控制組件,主要以流量爲切入點,從流量控制、熔斷降級、系統自適應保護等多個維度來幫助您保障微服務的穩定性。架構
從限流角度來看,sentinel的限流有2種控制維度,一個是qps,一個是併發數。併發
qps這個很好理解,也就是每秒處理請求量,當超過設定閾值時,會進行流控,策略有以下幾種:拒絕、排隊(必定時長)等。app
併發數這個就是當前線程運行數,相似於hystrix,只不過sentinel是進行線程個數統計判斷是否達到線程設定值,而hystrix是根據不一樣線程池來作的。分佈式
sentinel中處理流程是一個責任鏈,不一樣功能的邏輯抽象成不一樣的ProcessorSlot
組合在一塊兒,好比有限流的FlowSlot、打日誌的LogSot、數據統計的StatisticSlot。下面重點看限流的com.alibaba.csp.sentinel.slots.block.flow.FlowSlot
:ide
public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count, boolean prioritized, Object... args) throws Throwable { // 是否觸發限流檢查 checkFlow(resourceWrapper, context, node, count, prioritized); // 繼續往下一個節點走 fireEntry(context, resourceWrapper, node, count, prioritized, args); } public void checkFlow(Function<String, Collection<FlowRule>> ruleProvider, ResourceWrapper resource, Context context, DefaultNode node, int count, boolean prioritized) throws BlockException { Collection<FlowRule> rules = ruleProvider.apply(resource.getName()); for (FlowRule rule : rules) { // 多個限流規則檢查 if (!canPassCheck(rule, context, node, count, prioritized)) { throw new FlowException(rule.getLimitApp(), rule); } } } // canPassCheck -> passLocalCheck private static boolean passLocalCheck(FlowRule rule, Context context, DefaultNode node, int acquireCount, boolean prioritized) { return rule.getRater().canPass(selectedNode, acquireCount, prioritized); }
canPass校驗目前有如下幾種實現類:微服務
這幾個實現類分別使用了以下幾種限流算法:
DefaultController:令牌桶
RateLimiterController:漏斗
WarmUpController:冷啓動的令牌桶
WarmUpRateLimiterController:冷啓動的漏斗
sentinel中統計信息,好比qps、pass、block等信息都是在滑動時間窗口中維護的,好比時間戳是910時,統計信息會往對應800-1000的時間窗口更新,當時間戳是1001時,因爲時間窗口只有5個(每一個200ms),所以會複用第一個時間窗口,在使用前會先進行初始化該窗口統計值。
對於默認的流控實現 DefaultController
,其是根據時間窗口的統計值是否達到了限流值來決定是否限流的,這也是把它歸爲令牌桶算法的緣由。漏斗算法實現RateLimiterController
,會記錄上一次正常經過的時間戳信息(latestPassedTime),當判斷是否限流時,會根據當前時間-latestPassedTime
是否大於間隔值,大於的話表示能夠正常經過,小於的話表示剛剛已經有流程正常經過,這次須要排隊等待,等待時間爲指望時間戳-當前時間戳
,併發場景下,多個線程可能都會走到等待這裏,所以須要(cas操做)判斷當前需等待時間是否大於某個值,大於的話直接進行限流,再也不排隊等待。
冷啓動限流算法,即預熱/冷啓動方式。當系統長期處於低水位的狀況下,當流量忽然增長時,直接把系統拉昇到高水位可能瞬間把系統壓垮。經過"冷啓動",讓經過的流量緩慢增長,在必定時間內逐漸增長到閾值上限,給冷系統一個預熱的時間,避免冷系統被壓垮。
sentinel中一般冷啓動的過程系統容許經過的 QPS 曲線以下圖所示:
冷啓動的兩種模式,令牌桶和漏斗大同小異,只不過在流量較大時,冷啓動過程 令牌桶走勢相似於階梯向上直到設定的限流值,漏洞走勢相似於幾個斜線向上之道設定的限流值。
關於sentinel更多的知識可參考官方文檔:https://sentinelguard.io/zh-cn/docs/introduction.html
推薦閱讀