阿里 雙11 同款流控降級組件 Sentinel Go 正式 GA,助力雲原生服務穩穩穩

頭圖.png

做者 | 趙奕豪(宿何)  Sentinel 開源項目負責人
來源|阿里巴巴雲原生公衆號html

前言

微服務的穩定性一直是開發者很是關注的話題。隨着業務從單體架構向分佈式架構演進以及部署方式的變化,服務之間的依賴關係變得愈來愈複雜,業務系統也面臨着巨大的高可用挑戰。git

1.png

在生產環境中你們可能遇到過各類不穩定的狀況,好比:github

  • 大促時瞬間洪峯流量致使系統超出最大負載,load 飆高,系統崩潰致使用戶沒法下單。
  • 「黑馬」熱點商品擊穿緩存,DB 被打垮,擠佔正常流量。
  • 調用端被不穩定第三方服務拖垮,線程池被佔滿,調用堆積,致使整個調用鏈路卡死。

這些不穩定的場景可能會致使嚴重後果,但不少時候咱們又容易忽視這些與流量/依賴相關的高可用防禦。你們可能想問:如何預防這些不穩定因素帶來的影響?如何針對流量進行高可用的防禦?如何保障服務「穩如磐石」?這時候咱們就要請出阿里雙十一同款的高可用防禦中間件 —— Sentinel。在今年剛剛過去的天貓 雙11 大促中,Sentinel 完美地保障了阿里成千上萬服務 雙11 峯值流量的穩定性,同時 Sentinel Go 版本也在近期正式宣佈 GA。下面咱們來一塊兒瞭解下 Sentinel Go 的核心場景以及社區在雲原生方面的探索。golang

Sentinel 介紹

Sentinel 是阿里巴巴開源的,面向分佈式服務架構的流量控制組件,主要以流量爲切入點,從限流、流量整形、熔斷降級、系統自適應保護等多個維度來幫助開發者保障微服務的穩定性。Sentinel 承接了阿里巴巴近 10 年的 雙11 大促流量的核心場景,例如秒殺、冷啓動、消息削峯填谷、集羣流量控制、實時熔斷下游不可用服務等,是保障微服務高可用的利器,原生支持 Java/Go/C++ 等多種語言,而且提供 Istio/Envoy 全局流控支持來爲 Service Mesh 提供高可用防禦的能力。web

2.png

今年年初,Sentinel 社區宣佈了 Sentinel Go 版本的發佈,爲 Go 語言的微服務和基礎組件提供高可用防禦和容錯能力的原生支持,標誌着 Sentinel 朝着多元化與雲原生邁出了新的一步。在這半年的時間內,社區推出了近 10 個版本,逐步對齊了核心高可用防禦和容錯能力,同時也在不斷擴充開源生態,與 dubbo-go、螞蟻 MOSN 等開源社區進行共建。算法

就在近期,Sentinel Go 1.0 GA 版本正式發佈,標誌着 Go 版本正式進入生產可用階段。Sentinel Go 1.0 版本對齊了 Java 版本核心的高可用防禦和容錯能力,包括限流、流量整形、併發控制、熔斷降級、系統自適應保護、熱點防禦等特性。同時 Go 版本已覆蓋主流開源生態,提供了 Gin、gRPC、go-micro、dubbo-go 等經常使用微服務框架的適配,並提供了 etcd、Nacos、Consul 等動態數據源擴展支持。Sentinel Go 也在朝着雲原生的方向不斷演進,1.0 版本中也進行了一些雲原生方面的探索,包括 Kubernetes CRD data-source, Kubernetes HPA 等。對於 Sentinel Go 版本而言,咱們指望的流控場景並不侷限於微服務應用自己。雲原生基礎組件中 Go 語言生態佔比較高,而這些雲原生組件不少時候又缺少細粒度、自適應的保護與容錯機制,這時候就能夠結合組件的一些擴展機制,利用 Sentinel Go 來保護自身的穩定性。<br />
<br />Sentinel 底層經過高性能的滑動窗口進行秒級調用指標統計,結合 token bucket, leaky bucket 和自適應流控算法來透出核心的高可用防禦能力。數據庫

3.png

那麼咱們如何利用 Sentinel Go 來保證咱們微服務的穩定性?下面咱們來看幾個典型的應用場景。api

高可用防禦的核心場景

1. 流量控制與調配

流量是很是隨機性的、不可預測的。前一秒可能還風平浪靜,後一秒可能就出現流量洪峯了(例如 雙11 零點的場景)。然而咱們系統的容量老是有限的,若是忽然而來的流量超過了系統的承受能力,就可能會致使請求處理不過來,堆積的請求處理緩慢,CPU/Load 飆高,最後致使系統崩潰。所以,咱們須要針對這種突發的流量來進行限制,在儘量處理請求的同時來保障服務不被打垮,這就是流量控制。流量控制的場景是很是通用的,像脈衝流量類的場景都是適用的。緩存

一般在 Web 入口或服務提供方(Service Provider)的場景下,咱們須要保護服務提供方自身不被流量洪峯打垮。這時候一般根據服務提供方的服務能力進行流量控制,或針對特定的服務調用方進行限制。咱們能夠結合前期壓測評估核心接口的承受能力,配置 QPS 模式的流控規則,當每秒的請求量超過設定的閾值時,會自動拒絕多餘的請求。性能優化

下面是最簡單的一個 Sentinel 限流規則的配置示例:

_, err = flow.LoadRules([]*flow.Rule{
    {
        Resource:          "some-service", // 埋點資源名
        Count:             10, // 閾值爲 10,默認爲秒級維度統計,即該請求單機每秒不超過 10 次
        ControlBehavior:   flow.Reject, // 控制效果爲直接拒絕,不控制請求之間的時間間隔,不排隊
    },
})

2. Warm-Up 預熱流控

當系統長期處於低水位的狀況下,流量忽然增長時,直接把系統拉昇到高水位可能瞬間把系統壓垮。好比剛啓動的服務,數據庫鏈接池可能還未初始化,緩存也處於空的狀態,這時候激增的流量很是容易致使服務崩潰。若是採用傳統的限流模式,不加以平滑/削峯限制,其實也是有被打掛的風險的(好比一瞬間併發很高)。針對這種場景,咱們就能夠利用 Sentinel 的 Warm-Up 流控模式,控制經過的流量緩慢增長,在必定時間內逐漸增長到閾值上限,而不是在一瞬間所有放行,同時結合請求間隔控制+排隊的控制效果 來防止大量請求都在同一時刻被處理。這樣能夠給冷系統一個預熱的時間,避免冷系統被壓垮。

4.png

3. 併發控制與熔斷降級

一個服務經常會調用別的模塊,多是另外的一個遠程服務、數據庫,或者第三方 API 等。例如,支付的時候,可能須要遠程調用銀聯提供的 API;查詢某個商品的價格,可能須要進行數據庫查詢。然而,這個被依賴服務的穩定性是不能保證的。若是依賴的服務出現了不穩定的狀況,請求的響應時間變長,那麼調用服務的方法的響應時間也會變長,線程會產生堆積,最終可能耗盡業務自身的線程池,服務自己也變得不可用。

5.png

現代微服務架構都是分佈式的,由很是多的服務組成。不一樣服務之間相互調用,組成複雜的調用鏈路。以上的問題在鏈路調用中會產生放大的效果。複雜鏈路上的某一環不穩定,就可能會層層級聯,最終致使整個鏈路都不可用。Sentinel Go 提供如下的能力避免慢調用等不穩定因素形成不可用:

  • 併發控制(isolation 模塊):做爲一種輕量級隔離的手段,控制某些調用的併發數(即正在進行的數目),防止過多的慢調用擠佔正常的調用。
  • 熔斷降級(circuitbreaker 模塊):對不穩定的弱依賴調用進行自動熔斷降級,暫時切斷不穩定調用,避免局部不穩定因素致使總體的雪崩。

Sentinel Go 熔斷降級特性基於熔斷器模式的思想,在服務出現不穩定因素(如響應時間變長,錯誤率上升)的時候暫時切斷服務的調用,等待一段時間再進行嘗試。一方面防止給不穩定服務「雪上加霜」,另外一方面保護服務的調用方不被拖垮。Sentinel 支持兩種熔斷策略:基於響應時間(慢調用比例)和基於錯誤(錯誤比例/錯誤數),能夠有效地針對各類不穩定的場景進行防禦。

6.png

注意熔斷器模式通常適用於弱依賴調用,即降級後不影響業務主流程,開發者須要設計好降級後的 fallback 邏輯和返回值。另外須要注意的是,即便服務調用方引入了熔斷降級機制,咱們仍是須要在 HTTP 或 RPC 客戶端配置請求超時時間,來作一個兜底的防禦。

4. 熱點防禦

流量是隨機的,不可預測的。爲了防止被大流量打垮,咱們一般會對核心接口配置限流規則,但有的場景下配置普通的流控規則是不夠的。咱們來看這樣一種場景——大促峯值的時候,老是會有很多「熱點」商品,這些熱點商品的瞬時訪問量很是高。通常狀況下,咱們能夠事先預測一波熱點商品,並對這些商品信息進行緩存「預熱」,以便在出現大量訪問時能夠快速返回而不會都打到 DB 上。但每次大促都會涌現出一些「黑馬」商品,這些「黑馬」商品是咱們沒法事先預測的,沒有被預熱。當這些「黑馬」商品訪問量激增時,大量的請求會擊穿緩存,直接打到 DB 層,致使 DB 訪問緩慢,擠佔正常商品請求的資源池,最後可能會致使系統掛掉。這時候,利用 Sentinel 的熱點參數流量控制,自動識別熱點參數並控制每一個熱點值的訪問 QPS 或併發量,能夠有效地防止過「熱」的參數訪問擠佔正常的調用資源。

7.png

再好比有的場景下咱們但願限制每一個用戶調用某個 API 的頻率,將 API 名稱+userId 做爲埋點資源名顯然是不合適的。這時候咱們能夠在給 API 埋點的時候經過 WithArgs(xxx) 將 userId 做爲參數傳入到 API 埋點中,而後配置熱點規則便可針對每一個用戶分別限制調用頻率;同時,Sentinel 也支持針對某些具體值單獨配置限流值,進行精細化流控。像其餘規則同樣,熱點流控規則一樣支持經過動態數據源進行動態配置。<br />Sentinel Go 提供的 RPC 框架整合模塊(如 Dubbo、gRPC)均會自動將 RPC 調用的參數列表附帶在埋點中,用戶能夠直接針對相應的參數位置配置熱點流控規則。注意若是須要配置具體值限流,受類型系統限制,目前僅支持基本類型和 string 類型。

Sentinel Go 的熱點流量控制基於緩存淘汰機制+令牌桶機制實現。Sentinel 經過淘汰機制(如 LRU、LFU、ARC 策略等)來識別熱點參數,經過令牌桶機制來控制每一個熱點參數的訪問量。目前的 Sentinel Go 版本採用 LRU 策略統計熱點參數,社區也已有貢獻者提交了優化淘汰機制的 PR,在後續的版本中社區會引入更多的緩存淘汰機制來適配不一樣的場景。

5. 系統自適應保護

有了以上的流量防禦場景,是否是就萬事無憂了呢?其實不是的,不少時候咱們沒法事先就準確評估某個接口的準確容量,甚至沒法預知核心接口的流量特徵(如是否有脈衝狀況),這時候靠事先配置的規則可能沒法有效地保護當前服務節點;一些狀況下咱們可能忽然發現機器的 Load 和 CPU usage 等開始飈高,但卻沒有辦法很快的確認到是什麼緣由形成的,也來不及處理異常。這個時候咱們其實須要作的是快速止損,先經過一些自動化的兜底防禦手段,將瀕臨崩潰的微服務「拉」回來。針對這些狀況,Sentinel Go 提供了一種系統自適應保護規則,結合系統指標和服務容量,自適應動態調整流量。

8.png

Sentinel 系統自適應保護策略借鑑了 TCP BBR 算法的思想,結合系統的 Load、CPU 使用率以及服務的入口 QPS、響應時間和併發量等幾個維度的監控指標,經過自適應的流控策略,讓系統的入口流量和系統的負載達到一個平衡,讓系統儘量跑在最大吞吐量的同時保證系統總體的穩定性。系統規則能夠做爲整個服務的一個兜底防禦策略,保障服務不掛,對 CPU 密集型的場景會有比較好的效果。同時,社區也在結合自動化控制理論和強化學習等手段,持續完善自適應流控的效果和適用場景。在將來的版本中,社區會也推出更多試驗性的自適應流控策略,來知足更多的可用性場景。

雲原生探索

雲原生是 Sentinel Go 版本演進最爲重要的一環。在 GA 的過程當中,Sentinel Go 社區也在 Kubernetes 和 Service Mesh 等場景下進行了一些探索。

1. Kubernetes CRD data-source

在生產環境中咱們通常都須要經過配置中心來動態管理各類規則配置。在 Kubernetes 集羣中,咱們能夠自然利用 Kubernetes CRD 的方式來管理應用的 Sentinel 規則。在 Go 1.0.0 版本中社區提供了基本的 Sentinel 規則 CRD 抽象以及相應的 數據源實現。用戶只須要先導入 Sentinel 規則 CRD 定義文件,接入 Sentinel 時註冊對應的 data-source,而後按照 CRD 定義的格式編寫 YAML 配置並 kubectl apply 到對應的 namespace 下便可實現動態配置規則。如下是一個流控規則的示例:

apiVersion: datasource.sentinel.io/v1alpha1
kind: FlowRules
metadata:
  name: foo-sentinel-flow-rules
spec:
  rules:
    - resource: simple-resource
      threshold: 500
    - resource: something-to-smooth
      threshold: 100
      controlBehavior: Throttling
      maxQueueingTimeMs: 500
    - resource: something-to-warmup
      threshold: 200
      tokenCalculateStrategy: WarmUp
      controlBehavior: Reject
      warmUpPeriodSec: 30
      warmUpColdFactor: 3

Kubernetes CRD data-source 模塊地址https://github.com/sentinel-group/sentinel-go-datasource-k8s-crd

後續社區會進一步完善 Rule CRD 定義並與其它社區一塊兒探討高可用防禦相關的標準抽象。

2. Service Mesh

Service Mesh 是微服務向雲原生演進的趨勢之一。在 Service Mesh 架構下,一些服務治理和策略控制的能力都逐漸下沉到了 data plane 層。去年 Sentinel 社區在 Java 1.7.0 版本里面作了一些嘗試,提供了 Envoy Global Rate Limiting gRPC Service 的實現 —— Sentinel RLS token server,藉助 Sentinel 集羣限流 token server 來爲 Envoy 服務網格提供集羣流量控制的能力。今年隨着 Sentinel Go 版本的誕生,社區與更多的 Service Mesh 產品開展合做、整合。咱們與螞蟻的 MOSN 社區進行共建,在 MOSN Mesh 中原生支持了 Sentinel Go 的流控降級能力,同時也已在螞蟻內部落地。社區也在探索更爲通用的方案,如利用 Istio 的 Envoy WASM 擴展機制實現 Sentinel 插件,讓 Istio/Envoy 服務網格能夠藉助 Sentinel 原生的流控降級與自適應保護的能力來保障整個集羣服務的穩定性。

9.png

3. Kubernetes HPA based on Sentinel metrics

保障服務穩定性的方法多種多樣,除了各類規則對流量進行「控制」以外,「彈性」也是一種思路。對於部署在 Kubernetes 中的應用來講,能夠利用 Kubernetes HPA 能力進行對服務進行水平擴縮容。HPA 默認支持多種系統指標,而且支持自定義指標統計。目前咱們已經在阿里雲 Kubernetes 容器服務上結合 AHAS Sentinel 支持基於服務的平均 QPS、響應時間等做爲條件進行彈性伸縮。社區也正在這一塊作一些嘗試,將一些 Sentinel 的服務級別的指標統計(經過量,拒絕量,響應時間等)經過 Prometheus 或 OpenTelemetry 等標準方式透出,並適配到 Kubernetes HPA 中。

10.png

固然基於 Sentinel 的彈性方案不是萬靈藥,它只適用於一些特定的場景,好比適用於啓動速度快的無狀態服務(Serverless 場景)。對於啓動較慢的服務,或非本服務容量問題的場景(如依賴的 DB 容量不夠),彈性的方案不能很好地解決穩定性的問題,甚至可能會加重服務的惡化。

Let's start hacking!

瞭解了以上的高可用防禦的場景,以及 Sentinel 在雲原生方向的一些探索,相信你們對微服務容錯與穩定性的手段有了新的體會。歡迎你們動手玩一下 demo,將微服務接入 Sentinel 來享受高可用防禦和容錯的能力,讓服務「穩如磐石」。同時 Sentinel Go 1.0 GA 版本的發佈離不開社區的貢獻,感謝全部參與貢獻的小夥伴們。

本次 GA 咱們也新加入了兩位給力的 committer —— @sanxun0325 和 @luckyxiaoqiang,兩位在 1.0 版本的演進帶來了 Warm Up 流控、Nacos 動態數據源以及一系列功能改進和性能優化,很是積極地幫助社區答疑解惑以及 review 代碼。恭喜兩位!社區在將來版本中也會朝着雲原生和自適應智能化的方向不斷探索和演進,也歡迎更多的同窗加入貢獻小組,一塊兒參與 Sentinel 將來的演進,創造無限可能。咱們鼓勵任何形式的貢獻,包括但不限於:

  • bug fix
  • new features/improvements
  • dashboard
  • document/website
  • test cases

開發者能夠在 GitHub 上面的 good first issue 列表上挑選感興趣的 issue 來參與討論和貢獻。咱們會重點關注積極參與貢獻的開發者,核心貢獻者會提名爲 Committer,一塊兒主導社區的發展。咱們也歡迎你們有任何問題和建議,均可以經過 GitHub issue、Gitter 或釘釘羣(羣號:30150716)等渠道進行交流。Now start hacking!

相關文章
相關標籤/搜索