阿里面向分布式服務(wù)架構(gòu)的流量控制組件開源了
作者宿何,阿里巴巴高級開發(fā)工程師
Sentinel (https://github.com/alibaba/Sentinel)是阿里巴巴開源的,面向分布式服務(wù)架構(gòu)的流量控制組件,主要以流量為切入點,從限流、流量整形、熔斷降級、系統(tǒng)自適應(yīng)保護等多個維度來幫助開發(fā)者保障微服務(wù)的穩(wěn)定性。Sentinel 承接了阿里巴巴近 10 年的雙十一大促流量的核心場景,例如秒殺、冷啟動、消息削峰填谷、集群流量控制、實時熔斷下游不可用服務(wù)等,是保障微服務(wù)高可用的利器,原生支持 Java/Go/C++ 等多種語言,并且提供 Istio/Envoy/SOFA MOSN 全局流控支持來為 Service Mesh 提供高可用防護的能力。
近期,Sentinel Go 0.4.0 (https://github.com/alibaba/sentinel-golang/releases/tag/v0.4.0)正式發(fā)布,帶來了熱點參數(shù)流控特性(https://github.com/alibaba/sentinel-golang/wiki/%E7%83%AD%E7%82%B9%E5%8F%82%E6%95%B0%E9%99%90%E6%B5%81),可以自動識別統(tǒng)計傳入?yún)?shù)中的“熱點”參數(shù)值并分別進行流控,對于防刷、熱點商品訪問頻次控制等場景非常有用,是高可用流量防護中重要的一環(huán)。下面我們來了解一下熱點參數(shù)流控的場景和原理。
01
熱點流量防護介紹
流量是隨機的,不可預(yù)測的。為了防止被大流量打垮,我們通常會對核心接口配置限流規(guī)則,但有的場景下配置普通的流控規(guī)則是不夠的。我們來看這樣一種場景——大促峰值的時候,總是會有不少“熱點”商品,這些熱點商品的瞬時訪問量非常高。一般情況下,我們可以事先預(yù)測一波熱點商品,并對這些商品信息進行緩存“預(yù)熱”,以便在出現(xiàn)大量訪問時可以快速返回而不會都打到 DB 上。但每次大促都會涌現(xiàn)出一些“黑馬”商品,這些“黑馬”商品是我們無法事先預(yù)測的,沒有被預(yù)熱。當這些“黑馬”商品訪問量激增時,大量的請求會擊穿緩存,直接打到 DB 層,導(dǎo)致 DB 訪問緩慢,擠占正常商品請求的資源池,最后可能會導(dǎo)致系統(tǒng)掛掉。這時候,利用 Sentinel 的熱點參數(shù)流量控制能力,自動識別熱點參數(shù)并控制每個熱點值的訪問 QPS 或并發(fā)量,可以有效地防止過“熱”的參數(shù)訪問擠占正常的調(diào)用資源。

再比如有的場景下我們希望限制每個用戶調(diào)用某個 API 的頻率,將 API 名稱+userId 作為埋點資源名顯然是不合適的。這時候我們可以在給 API 埋點的時候通過 WithArgs(xxx) 將 userId 作為參數(shù)傳入到 API 埋點中,然后配置熱點規(guī)則即可針對每個用戶分別限制調(diào)用頻率;同時,Sentinel 也支持針對某些具體值單獨配置限流值,進行精細化流控。
熱點參數(shù)埋點/規(guī)則示例:
// 埋點示例e, b := sentinel.Entry("my-api", sentinel.WithArgs(rand.Uint32()%3000, "sentinel", uuid.New().String()))// 規(guī)則示例_, err = hotspot.LoadRules([]*hotspot.Rule{{Resource: "my-api",MetricType: hotspot.QPS, // 請求量模式ControlBehavior: hotspot.Reject,ParamIndex: 0, // 參數(shù)索引,0 即為第一個參數(shù)Threshold: 50, // 針對每個熱點參數(shù)值的閾值BurstCount: 0,DurationInSec: 1, // 統(tǒng)計窗口時長,這里為 1sSpecificItems: map[hotspot.SpecificValue]int64{// 支持針對某個具體值單獨配置限流值,比如這里針對數(shù)值 9 限制請求量=0(不允許通過){ValKind: hotspot.KindInt, ValStr: "9"}: 0,},},})
Sentinel Go 提供的 RPC 框架整合模塊(如 Dubbo、gRPC)均會自動將 RPC 調(diào)用的參數(shù)列表附帶在埋點中,用戶可以直接針對相應(yīng)的參數(shù)位置配置熱點流控規(guī)則。目前熱點規(guī)則僅支持基本類型和字符串類型,后續(xù)社區(qū)會進一步進行完善,支持更多的類型。
Sentinel Go 的熱點流量控制基于緩存淘汰機制+令牌桶機制實現(xiàn)。Sentinel 通過淘汰機制(如 LRU、LFU、ARC 策略等)來識別熱點參數(shù),通過令牌桶機制來控制每個熱點參數(shù)的訪問量。目前 0.4.0 版本采用 LRU 策略統(tǒng)計熱點參數(shù),在后續(xù)的版本中社區(qū)會引入更多的緩存淘汰機制來適配不同的場景。
02
高可用流量防護最佳實踐
在服務(wù)提供方(Service Provider)的場景下,我們需要保護服務(wù)提供方不被流量洪峰打垮。我們通常根據(jù)服務(wù)提供方的服務(wù)能力進行流量控制,或針對特定的服務(wù)調(diào)用方進行限制。為了保護服務(wù)提供方不被激增的流量拖垮影響穩(wěn)定性,我們可以結(jié)合前期的容量評估,通過 Sentinel 配置 QPS 模式的流控規(guī)則,當每秒的請求量超過設(shè)定的閾值時,會自動拒絕多余的請求。同時可以結(jié)合熱點參數(shù)流控進行細粒度的流量防護。
在服務(wù)調(diào)用端(Service Consumer)的場景下,我們需要保護服務(wù)調(diào)用方不被不穩(wěn)定的依賴服務(wù)拖垮。借助 Sentinel 的信號量隔離策略(并發(fā)數(shù)流控規(guī)則),限制某個服務(wù)調(diào)用的并發(fā)量,防止大量慢調(diào)用擠占正常請求的資源;同時,借助熔斷降級規(guī)則,當異常比率或業(yè)務(wù)慢調(diào)用比例超過某個閾值后將調(diào)用自動熔斷,直到一段時間過后再嘗試恢復(fù)。熔斷期間我們可以提供默認的處理邏輯(fallback),熔斷期間的調(diào)用都會返回 fallback 的結(jié)果,而不會再去嘗試本已非常不穩(wěn)定的服務(wù)。需要注意的是,即使服務(wù)調(diào)用方引入了熔斷降級機制,我們還是需要在 HTTP 或 RPC 客戶端配置請求超時時間,來做一個兜底的保護。

在一些請求突刺的場景中,比如 MQ 客戶端消費消息的場景,我們可能不希望將多余的消息直接拒絕(重投),而是讓這些過量的消息排隊逐步處理。這就是“削峰填谷”的場景。我們可以利用 Sentinel 流控規(guī)則中的“勻速+排隊等待”控制效果來處理這種場景,以固定的間隔時間讓請求通過,超出預(yù)設(shè)量的請求排隊等待。這種方式適合用于請求以突刺狀來到,這個時候我們不希望一下子把所有的請求都通過,這樣可能會把系統(tǒng)壓垮;同時我們也期待系統(tǒng)以穩(wěn)定的速度,逐步處理這些請求,以起到“削峰填谷”的效果,而不是直接拒絕所有多余的請求。

同時 Sentinel Go 還提供 全局維度的系統(tǒng)自適應(yīng)保護能力(https://github.com/alibaba/sentinel-golang/wiki/%E7%B3%BB%E7%BB%9F%E8%87%AA%E9%80%82%E5%BA%94%E6%B5%81%E6%8E%A7),結(jié)合系統(tǒng)的 Load、CPU 使用率以及服務(wù)的入口 QPS、響應(yīng)時間和并發(fā)量等幾個維度的監(jiān)控指標,通過自適應(yīng)的流控策略,讓系統(tǒng)的入口流量和系統(tǒng)的負載達到一個平衡,讓系統(tǒng)盡可能跑在最大吞吐量的同時保證系統(tǒng)整體的穩(wěn)定性。系統(tǒng)規(guī)則可以作為整個服務(wù)的一個兜底防護策略,保障服務(wù)不掛。

03
Let's start hacking!
Sentinel Go 版本正在快速演進中,我們非常歡迎感興趣的開發(fā)者參與貢獻,一起來主導(dǎo)未來版本的演進。Sentinel Go 版本的演進離不開社區(qū)的貢獻。若您有意愿參與貢獻,歡迎聯(lián)系我們加入 Sentinel 貢獻小組一起成長(Sentinel 開源討論釘釘群:30150716)。我們會定期給活躍貢獻者寄送小禮品,核心貢獻者可以提名為 committer,一起主導(dǎo)社區(qū)的演進。同時,也歡迎大家通過 AHAS Sentinel 控制臺(點擊閱讀原文) 來快速體驗 Sentinel 的能力。Now let's start hacking!
