天天看點

Sentinel 與 Hystrix 的對比

Sentinel

是阿裡中間件團隊研發的面向分布式服務架構的輕量級高可用流量控制元件,最近正式開源。Sentinel 主要以流量為切入點,從流量控制、熔斷降級、系統負載保護等多個次元來幫助使用者保護服務的穩定性。大家可能會問:Sentinel 和之前常用的熔斷降級庫 Netflix Hystrix 有什麼異同呢?本文将從多個角度對 Sentinel 和 Hystrix 進行對比,幫助大家進行技術選型。

Overview

先來看一下

Hystrix

的官方介紹:

Hystrix is a library that helps you control the interactions between these distributed services by adding latency tolerance and fault tolerance logic. Hystrix does this by isolating points of access between the services, stopping cascading failures across them, and providing fallback options, all of which improve your system’s overall resiliency.

可以看到 Hystrix 的關注點在于以 隔離 和 熔斷 為主的容錯機制,逾時或被熔斷的調用将會快速失敗,并可以提供 fallback 機制。

而 Sentinel 的側重點在于:

  • 多樣化的流量控制
  • 熔斷降級
  • 系統負載保護
  • 實時監控和控制台

可以看到兩者解決的問題還是有比較大的不同的,下面我們來分别對比一下。

共同特性

資源模型和執行模型上的對比

Hystrix 的資源模型設計上采用了指令模式,将對外部資源的調用和 fallback 邏輯封裝成一個指令對象(

HystrixCommand

/

HystrixObservableCommand

),其底層的執行是基于 RxJava 實作的。每個 Command 建立時都要指定 commandKey 和 groupKey(用于區分資源)以及對應的隔離政策(線程池隔離 or 信号量隔離)。線程池隔離模式下需要配置線程池對應的參數(線程池名稱、容量、排隊逾時等),然後 Command 就會在指定的線程池按照指定的容錯政策執行;信号量隔離模式下需要配置最大并發數,執行 Command 時 Hystrix 就會限制其并發調用。

Sentinel 的設計則更為簡單。相比 Hystrix Command 強依賴隔離規則,Sentinel 的資源定義與規則配置的耦合度更低。Hystrix 的 Command 強依賴于隔離規則配置的原因是隔離規則會直接影響 Command 的執行。在執行的時候 Hystrix 會解析 Command 的隔離規則來建立 RxJava Scheduler 并在其上排程執行,若是線程池模式則 Scheduler 底層的線程池為配置的線程池,若是信号量模式則簡單包裝成目前線程執行的 Scheduler。而 Sentinel 并不指定執行模型,也不關注應用是如何執行的。Sentinel 的原則非常簡單:根據對應資源配置的規則來為資源執行相應的限流/降級/負載保護政策。在 Sentinel 中資源定義和規則配置是分離的。使用者先通過 Sentinel API 給對應的業務邏輯定義資源(埋點),然後可以在需要的時候配置規則。埋點方式有兩種:

  • try-catch 方式(通過

    SphU.entry(...)

    ),使用者在 catch 塊中執行異常處理 / fallback
  • if-else 方式(通過

    SphO.entry(...)

    ),當傳回 false 時執行異常處理 / fallback

未來 Sentinel 還會引入基于注解的資源定義方式,同時可以通過注解參數指定異常處理函數和 fallback 函數。

Sentinel 提供

多樣化的規則配置方式

。除了直接通過

loadRules

API 将規則注冊到記憶體态之外,使用者還可以注冊各種外部資料源來提供動态的規則。使用者可以根據系統目前的實時情況去動态地變更規則配置,資料源會将變更推送至 Sentinel 并即時生效。

隔離設計上的對比

隔離是 Hystrix 的核心功能之一。Hystrix 提供兩種隔離政策:線程池隔離(Bulkhead Pattern)和信号量隔離,其中最推薦也是最常用的是線程池隔離。Hystrix 的線程池隔離針對不同的資源分别建立不同的線程池,不同服務調用都發生在不同的線程池中,線上程池排隊、逾時等阻塞情況時可以快速失敗,并可以提供 fallback 機制。線程池隔離的好處是隔離度比較高,可以針對某個資源的線程池去進行處理而不影響其它資源,但是代價就是線程上下文切換的 overhead 比較大,特别是對低延時的調用有比較大的影響。

但是,實際情況下,線程池隔離并沒有帶來非常多的好處。首先就是過多的線程池會非常影響性能。考慮這樣一個場景,在 Tomcat 之類的 Servlet 容器使用 Hystrix,本身 Tomcat 自身的線程數目就非常多了(可能到幾十或一百多),如果加上 Hystrix 為各個資源建立的線程池,總共線程數目會非常多(幾百個線程),這樣上下文切換會有非常大的損耗。另外,線程池模式比較徹底的隔離性使得 Hystrix 可以針對不同資源線程池的排隊、逾時情況分别進行處理,但這其實是逾時熔斷和流量控制要解決的問題,如果元件具備了逾時熔斷和流量控制的能力,線程池隔離就顯得沒有那麼必要了。

Sentinel 可以通過并發線程數模式的流量控制來提供信号量隔離的功能。這樣的隔離非常輕量級,僅限制對某個資源調用的并發數,而不是顯式地去建立線程池,是以 overhead 比較小,但是效果不錯。并且結合基于響應時間的熔斷降級模式,可以在不穩定資源的平均響應時間比較高的時候自動降級,防止過多的慢調用占滿并發數,影響整個系統。而 Hystrix 的信号量隔離比較簡單,無法對慢調用自動進行降級,隻能等待用戶端自己逾時,是以仍然可能會出現級聯阻塞的情況。

熔斷降級對比

Sentinel 和 Hystrix 的熔斷降級功能本質上都是基于熔斷器模式(Circuit Breaker Pattern)。Sentinel 與 Hystrix 都支援基于失敗比率(異常比率)的熔斷降級,在調用達到一定量級并且失敗比率達到設定的門檻值時自動進行熔斷,此時所有對該資源的調用都會被 block,直到過了指定的時間視窗後才啟發性地恢複。上面提到過,Sentinel 還支援基于平均響應時間的熔斷降級,可以在服務響應時間持續飙高的時候自動熔斷,拒絕掉更多的請求,直到一段時間後才恢複。這樣可以防止調用非常慢造成級聯阻塞的情況。

實時名額統計實作對比

Hystrix 和 Sentinel 的實時名額資料統計實作都是基于滑動視窗的。Hystrix 1.5 之前的版本是通過環形數組實作的滑動視窗,通過鎖配合 CAS 的操作對每個桶的統計資訊進行更新。Hystrix 1.5 開始對實時名額統計的實作進行了重構,将名額統計資料結構抽象成了響應式流(reactive stream)的形式,友善消費者去利用名額資訊。同時底層改造成了基于 RxJava 的事件驅動模式,在服務調用成功/失敗/逾時的時候釋出相應的事件,通過一系列的變換和聚合最終得到實時的名額統計資料流,可以被熔斷器或 Dashboard 消費。

Sentinel 目前抽象出了 Metric 名額統計接口,底層可以有不同的實作,目前預設的實作是基于

LeapArray

的滑動視窗,後續根據需要可能會引入 reactive stream 等實作。

Sentinel 的特色

除了之前提到的兩者的共同特性之外,Sentinel 還提供以下的特色功能:

輕量級、高性能

Sentinel 作為一個功能完備的高可用流量管控元件,其核心

sentinel-core

沒有任何多餘依賴,打包後隻有不到 200 KB,非常輕量級。開發者可以放心地引入

sentinel-core

而不需擔心依賴問題。同時,Sentinel 提供了多種擴充點,使用者可以很友善地根據需求去進行擴充,并且無縫地切合到 Sentinel 中。

引入 Sentinel 帶來的性能損耗非常小。隻有在業務單機量級超過 25W QPS 的時候才會有一些顯著的影響(5% - 10% 左右),單機 QPS 不太大的時候損耗幾乎可以忽略不計。

流量控制

Sentinel 可以針對不同的調用關系,以不同的運作名額(如 QPS、并發調用數、系統負載等)為基準,對資源調用進行流量控制,将随機的請求調整成合适的形狀。

Sentinel 支援多樣化的流量整形政策,在 QPS 過高的時候可以自動将流量調整成合适的形狀。常用的有:

  • 直接拒絕模式:即超出的請求直接拒絕。
  • 慢啟動預熱模式:當流量激增的時候,控制流量通過的速率,讓通過的流量緩慢增加,在一定時間内逐漸增加到門檻值上限,給冷系統一個預熱的時間,避免冷系統被壓垮。
  • 勻速器模式:利用 Leaky Bucket 算法實作的勻速模式,嚴格控制了請求通過的時間間隔,同時堆積的請求将會排隊,超過逾時時長的請求直接被拒絕。

Sentinel 還支援

基于調用關系的限流

,包括基于調用方限流、基于調用鍊入口限流、關聯流量限流等,依托于 Sentinel 強大的調用鍊路統計資訊,可以提供精準的不同次元的限流。

目前 Sentinel 對異步調用鍊路的支援還不是很好,後續版本會着重改善支援異步調用。

Sentinel 對系統的次元提供保護,負載保護算法借鑒了 TCP BBR 的思想。當系統負載較高的時候,如果仍持續讓請求進入,可能會導緻系統崩潰,無法響應。在叢集環境下,網絡負載均衡會把本應這台機器承載的流量轉發到其它的機器上去。如果這個時候其它的機器也處在一個邊緣狀态的時候,這個增加的流量就會導緻這台機器也崩潰,最後導緻整個叢集不可用。針對這個情況,Sentinel 提供了對應的保護機制,讓系統的入口流量和系統的負載達到一個平衡,保證系統在能力範圍之内處理最多的請求。

Sentinel 與 Hystrix 的對比

實時監控與控制台

Sentinel 提供 HTTP API 用于擷取

實時的監控資訊

,如調用鍊路統計資訊、簇點資訊、規則資訊等。如果使用者正在使用 Spring Boot/Spring Cloud 并使用了

Sentinel Spring Cloud Starter

,還可以友善地通過其暴露的 Actuator Endpoint 來擷取運作時的一些資訊,如動态規則等。未來 Sentinel 還會支援标準化的名額監控 API,可以友善地整合各種監控系統和可視化系統,如 Prometheus、Grafana 等。

Sentinel 控制台

(Dashboard)提供了機器發現、配置規則、檢視實時監控、檢視調用鍊路資訊等功能,使得使用者可以非常友善地去檢視監控和進行配置。

生态

Sentinel 目前已經針對 Servlet、Dubbo、Spring Boot/Spring Cloud、gRPC 等進行了适配,使用者隻需引入相應依賴并進行簡單配置即可非常友善地享受 Sentinel 的高可用流量防護能力。未來 Sentinel 還會對更多常用架構進行适配,并且會為 Service Mesh 提供叢集流量防護的能力。

總結

最後用表格來進行對比總結:

隔離政策 基于并發數 線程池隔離/信号量隔離
熔斷降級政策 基于響應時間或失敗比率 基于失敗比率
實時名額實作 滑動視窗 滑動視窗(基于 RxJava)
規則配置 支援多種資料源
擴充性 多個擴充點 插件的形式
基于注解的支援 即将釋出 支援
調用鍊路資訊 支援同步調用 不支援
限流 基于 QPS / 并發數,支援基于調用關系的限流
流量整形 支援慢啟動、勻速器模式
實時監控 API 各式各樣 較為簡單
控制台 開箱即用,可配置規則、檢視秒級監控、機器發現等 不完善
常見架構的适配 Servlet、Spring Cloud、Dubbo、gRPC 等 Servlet、Spring Cloud Netflix

若有 Sentinel 設計上的疑問或讨論,歡迎來提

issue

。若對 Sentinel 的開發感興趣,不要猶豫,歡迎加入我們,我們随時歡迎貢獻!