令牌桶、漏斗、冷啟動限流在sentinel的應用

luoxn28發表於2021-01-30

 分散式系統為了保證系統穩定性,在服務治理的限流中會根據不同場景進行限流操作,常見的限流演算法有:

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

  • 漏斗:固定速率限流,可以啟動整流作用。

在分析sentinel限流之前,我們先看下sentinel是什麼,官網說明如下:

隨著微服務的流行,服務和服務之間的穩定性變得越來越重要。Sentinel 是面向分散式服務架構的流量控制元件,主要以流量為切入點,從流量控制、熔斷降級、系統自適應保護等多個維度來幫助您保障微服務的穩定性。

從限流角度來看,sentinel的限流有2種控制維度,一個是qps,一個是併發數。

qps這個很好理解,也就是每秒處理請求量,當超過設定閾值時,會進行流控,策略有如下幾種:拒絕、排隊(一定時長)等。

併發數這個就是當前執行緒執行數,類似於hystrix,只不過sentinel是進行執行緒個數統計判斷是否達到執行緒設定值,而hystrix是根據不同執行緒池來做的。

sentinel中處理流程是一個責任鏈,不同功能的邏輯抽象成不同的ProcessorSlot組合在一起,比如有限流的FlowSlot、打日誌的LogSot、資料統計的StatisticSlot。下面重點看限流的com.alibaba.csp.sentinel.slots.block.flow.FlowSlot

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

 

 推薦閱讀 

相關文章