做者 | 趙奕豪git
微服務的穩定性一直是開發者很是關注的話題。隨着業務從單體架構向分佈式架構演進以及部署方式的變化,服務之間的依賴關係變得愈來愈複雜,業務系統也面臨着巨大的高可用挑戰。github
在生產環境中你們可能遇到過如下不穩定的狀況:golang
這些不穩定的場景可能會致使嚴重後果,但不少時候咱們又容易忽視這些與流量/依賴相關的高可用防禦。你們可能想問:如何預防這些不穩定因素帶來的影響?如何針對流量進行高可用的防禦?如何保障服務「穩如磐石」?這時候咱們就要請出服務高可用保障的利器 —— Sentinel。web
Sentinel 是阿里巴巴開源的,面向分佈式服務架構的流量控制組件,主要以流量爲切入點,從限流、流量整形、熔斷降級、系統自適應保護等多個維度來幫助開發者保障微服務的穩定性。Sentinel 承接了阿里巴巴近 10 年的雙十一大促流量的核心場景,例如秒殺、冷啓動、消息削峯填谷、集羣流量控制、實時熔斷下游不可用服務等,是保障微服務高可用的利器,原生支持 Java/Go/C++ 等多種語言,而且提供 Istio/Envoy 全局流控支持來爲 Service Mesh 提供高可用防禦的能力。算法
在今年年初,社區宣佈了 Sentinel Go 版本的發佈,爲 Go 語言的微服務提供流控降級、系統自適應保護等特性的原生支持,標誌着 Sentinel 朝着多元化與雲原生邁出了重要的一步。在這半年的時間內,社區推出了近 10 個版本,逐步對齊了限流、熔斷降級、系統自適應流控、熱點防禦等核心能力;同時社區也在不斷擴充開源生態,目前已提供 go-micro、gRPC、Dubbo、Gin 等框架的適配模塊,使用這些框架的開發者能夠很是簡單快速地接入 Sentinel。數據庫
Sentinel 裏面有兩個核心的抽象概念:資源和規則:緩存
Sentinel 底層經過高性能的滑動窗口進行秒級調用指標統計,結合 token bucket, leaky bucket 和自適應流控算法來透出核心的高可用防禦能力。架構
那麼咱們如何利用 Sentinel Go 來保證咱們微服務的穩定性?下面咱們來看幾個典型的場景。併發
流量是很是隨機性的、不可預測的。前一秒可能還風平浪靜,後一秒可能就出現流量洪峯了(例如雙十一零點的場景)。然而咱們系統的容量老是有限的,若是忽然而來的流量超過了系統的承受能力,就可能會致使請求處理不過來,堆積的請求處理緩慢,CPU/Load 飆高,最後致使系統崩潰。框架
所以,咱們須要針對這種突發的流量來進行限制,在儘量處理請求的同時來保障服務不被打垮,這就是流量控制。流量控制的場景是很是通用的,像脈衝流量類的場景都是適用的。
一般在 Web 入口或服務提供方(Service Provider)的場景下,咱們須要保護服務提供方自身不被流量洪峯打垮。這時候一般根據服務提供方的服務能力進行流量控制,或針對特定的服務調用方進行限制。咱們能夠結合前期壓測評估核心接口的承受能力,配置 QPS 模式的流控規則,當每秒的請求量超過設定的閾值時,會自動拒絕多餘的請求。
下面是最簡單的一個 Sentinel 限流規則的配置示例:
_, err = flow.LoadRules([]*flow.FlowRule{ { Resource: "some-service", // 埋點資源名 MetricType: flow.QPS, // QPS 模式 Count: 10, // QPS 閾值爲 10,即該請求單機每秒不超過 10 次 ControlBehavior: flow.Reject, // 控制效果爲直接拒絕,不排隊 }, })
近期發佈的 Sentinel Go 0.6.0 版本帶來了一種新的流控場景:Warm-Up 預熱流控。當系統長期處於低水位的狀況下,流量忽然增長時,直接把系統拉昇到高水位可能瞬間把系統壓垮。好比剛啓動的服務,數據庫鏈接池可能還未初始化,緩存也處於空的狀態,這時候激增的流量很是容易致使服務崩潰。若是採用傳統的限流模式,不加以平滑/削峯限制,其實也是有被打掛的風險的(好比一瞬間併發很高)。
針對這種場景,咱們就能夠利用 Sentinel 的 Warm-Up 流控模式,控制經過的流量緩慢增長,在必定時間內逐漸增長到閾值上限,而不是在一瞬間所有放行,同時結合請求間隔控制+排隊的控制效果 來防止大量請求都在同一時刻被處理。這樣能夠給冷系統一個預熱的時間,避免冷系統被壓垮。
一個服務經常會調用別的模塊,多是另外的一個遠程服務、數據庫,或者第三方 API 等。例如,支付的時候,可能須要遠程調用銀聯提供的 API;查詢某個商品的價格,可能須要進行數據庫查詢。然而,這個被依賴服務的穩定性是不能保證的。若是依賴的服務出現了不穩定的狀況,請求的響應時間變長,那麼調用服務的方法的響應時間也會變長,線程會產生堆積,最終可能耗盡業務自身的線程池,服務自己也變得不可用。
現代微服務架構都是分佈式的,由很是多的服務組成。不一樣服務之間相互調用,組成複雜的調用鏈路。以上的問題在鏈路調用中會產生放大的效果。複雜鏈路上的某一環不穩定,就可能會層層級聯,最終致使整個鏈路都不可用。
Sentinel Go 提供如下的能力避免慢調用等不穩定因素形成不可用:
Sentinel Go 熔斷降級特性基於熔斷器模式的思想,在服務出現不穩定因素(如響應時間變長,錯誤率上升)的時候暫時切斷服務的調用,等待一段時間再進行嘗試。一方面防止給不穩定服務「雪上加霜」,另外一方面保護服務的調用方不被拖垮。Sentinel 支持兩種熔斷策略:基於響應時間(慢調用比例)和基於錯誤(錯誤比例/錯誤數),能夠有效地針對各類不穩定的場景進行防禦。
注意熔斷器模式通常適用於弱依賴調用,即降級後不影響業務主流程,開發者須要設計好降級後的 fallback 邏輯和返回值。另外須要注意的是,即便服務調用方引入了熔斷降級機制,咱們仍是須要在 HTTP 或 RPC 客戶端配置請求超時時間,來作一個兜底的防禦。
流量是隨機的,不可預測的。爲了防止被大流量打垮,咱們一般會對核心接口配置限流規則,但有的場景下配置普通的流控規則是不夠的。
咱們來看這樣一種場景——大促峯值的時候,老是會有很多「熱點」商品,這些熱點商品的瞬時訪問量很是高。通常狀況下,咱們能夠事先預測一波熱點商品,並對這些商品信息進行緩存「預熱」,以便在出現大量訪問時能夠快速返回而不會都打到 DB 上。但每次大促都會涌現出一些「黑馬」商品,這些「黑馬」商品是咱們沒法事先預測的,沒有被預熱。
當這些「黑馬」商品訪問量激增時,大量的請求會擊穿緩存,直接打到 DB 層,致使 DB 訪問緩慢,擠佔正常商品請求的資源池,最後可能會致使系統掛掉。這時候,利用 Sentinel 的熱點參數流量控制能力,自動識別熱點參數並控制每一個熱點值的訪問 QPS 或併發量,能夠有效地防止過「熱」的參數訪問擠佔正常的調用資源。
再好比有的場景下咱們但願限制每一個用戶調用某個 API 的頻率,將 API 名稱+userId 做爲埋點資源名顯然是不合適的。這時候咱們能夠在給 API 埋點的時候經過 WithArgs(xxx) 將 userId 做爲參數傳入到 API 埋點中,而後配置熱點規則便可針對每一個用戶分別限制調用頻率;同時,Sentinel 也支持針對某些具體值單獨配置限流值,進行精細化流控。像其餘規則同樣,熱點流控規則一樣支持經過動態數據源進行動態配置。
Sentinel Go 提供的 RPC 框架整合模塊(如 Dubbo、gRPC)均會自動將 RPC 調用的參數列表附帶在埋點中,用戶能夠直接針對相應的參數位置配置熱點流控規則。注意若是須要配置具體值限流,受類型系統限制,目前僅支持基本類型和 string 類型。
Sentinel Go 的熱點流量控制基於緩存淘汰機制+令牌桶機制實現。Sentinel 經過淘汰機制(如 LRU、LFU、ARC 策略等)來識別熱點參數,經過令牌桶機制來控制每一個熱點參數的訪問量。目前的 Sentinel Go 版本採用 LRU 策略統計熱點參數,在後續的版本中社區會引入更多的緩存淘汰機制來適配不一樣的場景。
有了以上的流量防禦場景,是否是就萬事無憂了呢?其實不是的,不少時候咱們沒法事先就準確評估某個接口的準確容量,甚至沒法預知核心接口的流量特徵(如是否有脈衝狀況),這時候靠事先配置的規則可能沒法有效地保護當前服務節點;一些狀況下咱們可能忽然發現機器的 Load 和 CPU usage 等開始飈高,但卻沒有辦法很快的確認到是什麼緣由形成的,也來不及處理異常。
這個時候咱們其實須要作的是快速止損,先經過一些自動化的兜底防禦手段,將瀕臨崩潰的微服務「拉」回來。針對這些狀況,Sentinel Go 提供了一種獨有的系統自適應保護規則,結合系統指標和服務容量,自適應動態調整流量。
Sentinel 系統自適應保護策略借鑑了 TCP BBR 算法的思想,結合系統的 Load、CPU 使用率以及服務的入口 QPS、響應時間和併發量等幾個維度的監控指標,經過自適應的流控策略,讓系統的入口流量和系統的負載達到一個平衡,讓系統儘量跑在最大吞吐量的同時保證系統總體的穩定性。系統規則能夠做爲整個服務的一個兜底防禦策略,保障服務不掛,對 CPU 密集型的場景會有比較好的效果。同時,社區也在結合自動化控制理論和強化學習等手段,來更好地完善自適應流控的效果和適用場景。
瞭解了以上的高可用防禦的場景,相信你們對微服務容錯與穩定性保障的手段有了新的體會。你們能夠動手玩起來,接入 Sentinel Go 來體驗這些能力,讓微服務「穩如磐石」。
同時 Sentinel 的演進也離不開社區的貢獻。Sentinel Go 1.0 GA 版本即將在近期發佈,帶來更多雲原生相關的特性。咱們很是歡迎感興趣的開發者參與貢獻,一塊兒來主導將來版本的演進。咱們鼓勵任何形式的貢獻,包括但不限於:
開發者能夠在 GitHub 上面的 good first issue 列表上挑選感興趣的 issue 來參與討論和貢獻。咱們會重點關注積極參與貢獻的開發者,核心貢獻者會提名爲 Committer,一塊兒主導社區的發展。咱們也歡迎你們有任何問題和建議,均可以經過 GitHub issue、Gitter 或釘釘羣(羣號:30150716)等渠道進行交流。Now start hacking!
趙奕豪(GitHub: sczyh30),阿里 Sentinel 開源項目負責人,高可用技術佈道師。
「 阿里巴巴雲原生關注微服務、Serverless、容器、Service Mesh 等技術領域、聚焦雲原生流行技術趨勢、雲原生大規模的落地實踐,作最懂雲原生開發者的公衆號。」