還在擔心服務掛掉?Sentinel Go 讓服務穩如磐石


1.png

作者 | 趙奕豪

背景

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

2.png

在生產環境中大家可能遇到過以下不穩定的情況:

  • 大促時瞬間洪峰流量導致系統超出最大負載,load 飆高,系統崩潰導致用戶無法下單;

  • “黑馬”熱點商品擊穿緩存,DB 被打垮,擠占正常流量;

  • 調用端被不穩定第三方服務拖垮,線程池被占滿,調用堆積,導致整個調用鏈路卡死。

這些不穩定的場景可能會導致嚴重后果,但很多時候我們又容易忽視這些與流量/依賴相關的高可用防護。大家可能想問:如何預防這些不穩定因素帶來的影響?如何針對流量進行高可用的防護?如何保障服務“穩如磐石”?這時候我們就要請出服務高可用保障的利器 —— Sentinel。

Sentinel 介紹

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

3.png

在今年年初,社區宣布了 Sentinel Go 版本的發布,為 Go 語言的微服務提供流控降級、系統自適應保護等特性的原生支持,標志着 Sentinel 朝着多元化與雲原生邁出了重要的一步。在這半年的時間內,社區推出了近 10 個版本,逐步對齊了限流、熔斷降級、系統自適應流控、熱點防護等核心能力;同時社區也在不斷擴充開源生態,目前已提供 go-micro、gRPC、Dubbo、Gin 等框架的適配模塊,使用這些框架的開發者可以非常簡單快速地接入 Sentinel。

Sentinel 里面有兩個核心的抽象概念:資源和規則:

  • **資源 (resource) **是 Sentinel 的關鍵概念,它代表某個邏輯塊、函數或接口的調用。它可以是某個 Web API,或者是某個 RPC 服務,甚至是任意的代碼塊。使用 Sentinel 的 API 將業務邏輯封裝起來(或引入 Sentinel 提供的插件),這一步稱為“埋點”。每個埋點都有一個資源名稱,代表觸發了這個資源的調用或訪問;

  • **規則 (rule) **即定義到達怎樣的條件后進行怎樣的控制,針對某個資源或某些資源生效。所有規則都可以動態實時調整,社區提供了 etcd、Consul、Nacos 等動態數據源適配,可以方便地通過這些配置組件來管理規則。

4.png

Sentinel 底層通過高性能的滑動窗口進行秒級調用指標統計,結合 token bucket, leaky bucket 和自適應流控算法來透出核心的高可用防護能力。

5.png

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

高可用防護的核心場景

1. 流量控制

流量是非常隨機性的、不可預測的。前一秒可能還風平浪靜,后一秒可能就出現流量洪峰了(例如雙十一零點的場景)。然而我們系統的容量總是有限的,如果突然而來的流量超過了系統的承受能力,就可能會導致請求處理不過來,堆積的請求處理緩慢,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, // 控制效果為直接拒絕,不排隊
    },
})

2. Warm-Up 預熱流控

近期發布的 Sentinel Go 0.6.0 版本帶來了一種新的流控場景:Warm-Up 預熱流控。當系統長期處於低水位的情況下,流量突然增加時,直接把系統拉升到高水位可能瞬間把系統壓垮。比如剛啟動的服務,數據庫連接池可能還未初始化,緩存也處於空的狀態,這時候激增的流量非常容易導致服務崩潰。如果采用傳統的限流模式,不加以平滑/削峰限制,其實也是有被打掛的風險的(比如一瞬間並發很高)。

針對這種場景,我們就可以利用 Sentinel 的 Warm-Up 流控模式,控制通過的流量緩慢增加,在一定時間內逐漸增加到閾值上限,而不是在一瞬間全部放行,同時結合請求間隔控制+排隊的控制效果 來防止大量請求都在同一時刻被處理。這樣可以給冷系統一個預熱的時間,避免冷系統被壓垮。

6.png

3. 並發控制與熔斷降級

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

7.png

現代微服務架構都是分布式的,由非常多的服務組成。不同服務之間相互調用,組成復雜的調用鏈路。以上的問題在鏈路調用中會產生放大的效果。復雜鏈路上的某一環不穩定,就可能會層層級聯,最終導致整個鏈路都不可用。

Sentinel Go 提供以下的能力避免慢調用等不穩定因素造成不可用:

  • 並發控制:作為一種輕量級隔離的手段,控制某些調用的並發數(即正在進行的數目),防止過多的慢調用擠占正常的調用;

  • 熔斷降級:對不穩定的弱依賴調用進行自動熔斷降級,暫時切斷不穩定調用,避免局部不穩定因素導致整體的雪崩。

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

8.png

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

4. 熱點防護

流量是隨機的,不可預測的。為了防止被大流量打垮,我們通常會對核心接口配置限流規則,但有的場景下配置普通的流控規則是不夠的。

我們來看這樣一種場景——大促峰值的時候,總是會有不少“熱點”商品,這些熱點商品的瞬時訪問量非常高。一般情況下,我們可以事先預測一波熱點商品,並對這些商品信息進行緩存“預熱”,以便在出現大量訪問時可以快速返回而不會都打到 DB 上。但每次大促都會涌現出一些“黑馬”商品,這些“黑馬”商品是我們無法事先預測的,沒有被預熱。

當這些“黑馬”商品訪問量激增時,大量的請求會擊穿緩存,直接打到 DB 層,導致 DB 訪問緩慢,擠占正常商品請求的資源池,最后可能會導致系統掛掉。這時候,利用 Sentinel 的熱點參數流量控制能力,自動識別熱點參數並控制每個熱點值的訪問 QPS 或並發量,可以有效地防止過“熱”的參數訪問擠占正常的調用資源。

9.png

再比如有的場景下我們希望限制每個用戶調用某個 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 策略統計熱點參數,在后續的版本中社區會引入更多的緩存淘汰機制來適配不同的場景。

5. 系統自適應保護

有了以上的流量防護場景,是不是就萬事無憂了呢?其實不是的,很多時候我們無法事先就准確評估某個接口的准確容量,甚至無法預知核心接口的流量特征(如是否有脈沖情況),這時候靠事先配置的規則可能無法有效地保護當前服務節點;一些情況下我們可能突然發現機器的 Load 和 CPU usage 等開始飈高,但卻沒有辦法很快的確認到是什么原因造成的,也來不及處理異常。

這個時候我們其實需要做的是快速止損,先通過一些自動化的兜底防護手段,將瀕臨崩潰的微服務“拉”回來。針對這些情況,Sentinel Go 提供了一種獨有的系統自適應保護規則,結合系統指標和服務容量,自適應動態調整流量。

10.png

Sentinel 系統自適應保護策略借鑒了 TCP BBR 算法的思想,結合系統的 Load、CPU 使用率以及服務的入口 QPS、響應時間和並發量等幾個維度的監控指標,通過自適應的流控策略,讓系統的入口流量和系統的負載達到一個平衡,讓系統盡可能跑在最大吞吐量的同時保證系統整體的穩定性。系統規則可以作為整個服務的一個兜底防護策略,保障服務不掛,對 CPU 密集型的場景會有比較好的效果。同時,社區也在結合自動化控制理論和強化學習等手段,來更好地完善自適應流控的效果和適用場景。

Let's start hacking!

了解了以上的高可用防護的場景,相信大家對微服務容錯與穩定性保障的手段有了新的體會。大家可以動手玩起來,接入 Sentinel Go 來體驗這些能力,讓微服務“穩如磐石”。

同時 Sentinel 的演進也離不開社區的貢獻。Sentinel Go 1.0 GA 版本即將在近期發布,帶來更多雲原生相關的特性。我們非常歡迎感興趣的開發者參與貢獻,一起來主導未來版本的演進。我們鼓勵任何形式的貢獻,包括但不限於:

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

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

作者簡介

趙奕豪(GitHub: sczyh30),阿里 Sentinel 開源項目負責人,高可用技術布道師。

阿里巴巴雲原生關注微服務、Serverless、容器、Service Mesh 等技術領域、聚焦雲原生流行技術趨勢、雲原生大規模的落地實踐,做最懂雲原生開發者的公眾號。”


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM