java分佈式面試降級組件Hystrix的功能特性

引言

關於 Hystrix 的問題匯總後兩點:

  • Hystrix主要功能覆蓋考察。
  • Hystrix工作中使用經驗考察。

Hystrix語義為“豪豬”,它後背帶刺兒且具有自我保護的能力,這是不是就很好理解它的功能瞭。雖然我沒有直接使用過Hystrix,但是類似的同樣功能的框架功能和原理都大同小異,所以我決定針對 Hystrix 單獨拆分開講解。

同時我覺得Hystrix中有很多設計思想非常優秀,非常值得我們學習,學習這些設計思想,你可以從更高維度去思考如何讓系統更加穩定。

1、面試官:能簡單介紹下Hystrix有哪些功能嗎?

問題分析:瞭解Hystrix的功能,同時也能從Hystrix優秀的設計理念中得到架構設計方面的啟發。

答:我在項目裡使用到,系統在 Hystrix 的保護下,可以長期處於高可用的狀態,常用的功能有以下幾點:

1.1、fail-fast(快速失敗)

Hystrix設計中提供瞭 fail-fast(快速失敗)和快速恢復機制。

Tip:不知道之前你是否瞭解過fail-fast機制,或者面試Java基礎的時候,HashMap 中的 Iterator 迭代器,Iterator的設計就是 fail-fast 的,**快速失敗(fail—fast)**是Java集合中的一種機制, 在用迭代器遍歷一個集合對象時,如果遍歷過程中對集合對象的內容進行瞭修改(增加、刪除、修改),則會拋出Concurrent Modification Exception。

我第一次學習 HashMap 並不是很懂 fail-fast,覺得快速失敗隻是應用在Java集合類中,防止Java非線程安全集合的並發操作,學習使用 Hystrix 後,原來快速失敗機制還可以應用在系統架構設計中,對無法及時處理的請求快速失敗(fail-fast),降低系統負載,而不是排隊。

1.2、Fallback優雅降級機制

Fallback 字面意思是遇到Fall就啟動back,瞭解到Fallback的機制後,我馬上在項目中用起來。

看真實例子:

 @Override
    @Degrade(key = "getOrderByParamFromES", fallBackMethod = "getOrderByParamFromMysql")
    public OrderResult getOrderByParamFromES(OrderSearchParam param) {
        //走ES查詢
        ......
        return OrderResult;
    }
 		//fallBack後調用getOrderByParamFromMysql方法
 		public OrderResult getOrderByParamFromMysql(OrderSearchParam param) {
        //走mysql查詢
        ......
        return OrderResult;
    }
 

代碼解釋:

fallBackMethod = "getOrderByParamFromMysql"

就是在ES查詢故障失敗後,系統自動降級調getOrderByParamFromMysql方法,走mysql查詢,正常情況下,getOrderByParamFromMysql是不會被調用的,除非Fall。

1.3、線程/信號量隔離機制

線程隔離:

請求會根據自己的key獲取對應線程池中的線程執行,動態設置線程池參數,這樣自然地將不同的請求隔離開來,支持異步來提高接口性能。不同請求直接不影響,例如service1請求緩慢,但是service2和service3還是可以正常工作,缺點就是線程切換影響性能。

信號量隔離:

一個請求中訪問瞭service1、service2、service3,其中service1請求超時,將導致整個信號量一直不釋放,其他請求一直無法接受。

對於延遲小的請求(例如訪問緩存或者本地訪問數據庫)來說,線程池帶來的開銷是非常高的,你可以考慮采用其他方法,例如非阻塞信號量(不支持超時)來實現依賴服務的隔離。但絕大多數情況下,Netflix 更偏向於使用線程池來隔離依賴服務,因為其帶來的額外開銷可以接受,並且能支持包括超時在內的所有功能。

2、面試官:剛剛說到線程隔離,那實際使用中是否打開超時線程中斷開關?

問題分析:考察實際使用經驗,根據線程本身的特點,線程超時,如果不及時中斷,會浪費線程資源。

答:一般情況下我們會打開超時中斷開關,目的是及時釋放線程資源。

通過hystrix.command.default.execution.isolation.thread.interruptOnTimeout = true 設置。

但是如果是寫數據庫命令,或者記錄關鍵日志命令的情況下,需要命令執行完畢情況,可關閉超時中斷。

(面試官點頭滿意,相信我確實有Hystrix的維護經驗)

3、面試官:那你是如何估計線程池大小的?

答:要正確設置線程池的大小,需要分析所部署系統的CPU個數、內存大小、任務類型(計算密集、IO密集等),對於計算密集型任務,線程池大小和CPU個數相近通常能實現最優利用率,對於IO密集型任務,線程池的最優大小的計算公式:線程池大小=CPU個數* (1 + 任務等待時間/ 任務處理時間)。

深入分析

Hystrix歷史

Hystrix源自Netflix API團隊於2011年開始的項目。2012年,Hystrix不斷發展和成熟,Netflix內部的許多團隊都采用瞭它。如今,每天在Netflix上通過Hystrix執行數百億個線程隔離和數千億個信號量隔離的調用。這極大地提高瞭正常運行時間和彈性。

在高並發訪問下,系統所依賴的服務的穩定性對系統的影響非常大,依賴有很多不可控的因素,比如網絡連接變慢,資源突然繁忙,暫時不可用,服務脫機等。我們要構建穩定、可靠的分佈式系統,就必須要有這樣一套容錯方法。

Hystrix的主要功能特性

熔斷器機制:熔斷器可以理解成保險絲,項目裡使用Hystrix Command,當 Hystrix Command請求後,如果服務失敗數量超過一定比例(比如默認50%),斷路器自動熔斷,該服務將進入熔斷狀態,後續請求都會進入fallback。

降級機制:通過fallbackMethod註解,當請求後端服務出現異常的時候, 為瞭避免影響到其他業務邏輯,可以使用fallback方法指定的方法快速返回,或啟用“備胎方案”。

環境隔離:包括線程隔離和信號量隔離。

cache:Hystrix支持將一個請求結果緩存起來,下一個具有相同key的請求將直接從緩存中取出結果,減少請求開銷。

Hystrix Demo

通過一個demo快速理解Hystrix fallback 的使用

@Service
public class OrderQueryService {
     /**
     * 訂單查詢接口
     */
    @HystrixCommand(fallbackMethod = "queryOrderBack")
    public List<Order> queryOrderFromRedis(String userId) {
      // todo  reids查詢邏輯
      return orderlist;
    }
     /**
     * 訂單查詢接口失敗降級方案
     */
    @SuppressWarnings("unused")
    private String queryOrderBack(String userId) {
      // todo  如,走ES查詢邏輯  或者 直接提示用戶“請稍後再試”
      // todo 通知維護人員處理故障
      return "";
    }
}

代碼解釋:

程序正常時,查詢訂單服務是走queryOrderFromRedis方法的邏輯,當queryOrderFromRedis方法拋出異常,根據設定的異常比例,或者指定哪個異常,達到閾值觸法fallback開關,程序切換到queryOrderBack,設置程序走ES查詢邏輯 或者 直接提示用戶“請稍後再試”,根據業務自行設置。

哪些情況下會觸發fallback?

Failure Type Exception class Exception.cause 觸發fallback
FAILURE HystrixRuntimeException underlying exception (user-controlled) YES
SEMAPHORE_REJECTED HystrixRuntimeException j.l.RuntimeException YES
SHORT_CIRCUITED HystrixRuntimeException j.l.RuntimeException YES
THREAD_POOL_REJECTED HystrixRuntimeException j.u.c.RejectedExecutionException YES
TIMEOUT HystrixRuntimeException j.u.c.TimeoutException YES

FAILURE:任意RuntimeException異常都可以激活fallback。

THREAD_POOL_REJECTED:並發執行的任務數超過線程池和隊列之和時,也就是Hystrix的線程隔離機制。

SEMAPHORE_REJECTED:類似 THREAD_POOL_REJECTED ,當服務的並發數大於信號量閾值時將進入fallback。比如配置程序執行並發數不能大於3,由於信號量隔離下無論調用哪種命令執行方法,Hystrix都不會創建新線程執行run()/construct(),所以調用程序需要自己創建多個線程來模擬並發調用execute(),最後看到一旦並發線程>3,後續請求都進入fallback。

SHORT_CIRCUITED:在一定時間內,用戶請求超過一定的比例失敗時,如超時,異常,線程並發達到限定最大值等,斷路器都會打開;短路器打開後所有請求直接走fallback,可以通過。circuitBreakerErrorThresholdPercentage方法設置百分比,默認是50。

TIMEOUT:即超時請求。

附錄:Hystrix策略配置

/* --------------統計相關------------------*/ 
// 統計滾動的時間窗口,默認:5000毫秒(取自circuitBreakerSleepWindowInMilliseconds)   
private final HystrixProperty metricsRollingStatisticalWindowInMilliseconds;   
// 統計窗口的Buckets的數量,默認:10個,每秒一個Buckets統計   
private final HystrixProperty metricsRollingStatisticalWindowBuckets; // number of buckets in the statisticalWindow   
// 是否開啟監控統計功能,默認:true   
private final HystrixProperty metricsRollingPercentileEnabled;   
/* --------------熔斷器相關------------------*/ 
// 熔斷器在整個統計時間內是否開啟的閥值,默認20。也就是在metricsRollingStatisticalWindowInMilliseconds(默認10s)內至少請求20次,熔斷器才發揮起作用   
private final HystrixProperty circuitBreakerRequestVolumeThreshold;   
// 熔斷時間窗口,默認:5秒.熔斷器中斷請求5秒後會進入半打開狀態,放下一個請求進來重試,如果該請求成功就關閉熔斷器,否則繼續等待一個熔斷時間窗口
private final HystrixProperty circuitBreakerSleepWindowInMilliseconds;   
//是否啟用熔斷器,默認true. 啟動   
private final HystrixProperty circuitBreakerEnabled;   
//默認:50%。當出錯率超過50%後熔斷器啟動
private final HystrixProperty circuitBreakerErrorThresholdPercentage;  
//是否強制開啟熔斷器阻斷所有請求,默認:false,不開啟。置為true時,所有請求都將被拒絕,直接到fallback 
private final HystrixProperty circuitBreakerForceOpen;   
//是否允許熔斷器忽略錯誤,默認false, 不開啟   
private final HystrixProperty circuitBreakerForceClosed; 
/* --------------信號量相關------------------*/ 
//使用信號量隔離時,命令調用最大的並發數,默認:10   
private final HystrixProperty executionIsolationSemaphoreMaxConcurrentRequests;   
//使用信號量隔離時,命令fallback(降級)調用最大的並發數,默認:10   
private final HystrixProperty fallbackIsolationSemaphoreMaxConcurrentRequests; 
/* --------------其他------------------*/ 
//使用命令調用隔離方式,默認:采用線程隔離,ExecutionIsolationStrategy.THREAD   
private final HystrixProperty executionIsolationStrategy;   
//使用線程隔離時,調用超時時間,默認:1秒   
private final HystrixProperty executionIsolationThreadTimeoutInMilliseconds;   
//線程池的key,用於決定命令在哪個線程池執行   
private final HystrixProperty executionIsolationThreadPoolKeyOverride;   
//是否開啟fallback降級策略 默認:true   
private final HystrixProperty fallbackEnabled;   
// 使用線程隔離時,是否對命令執行超時的線程調用中斷(Thread.interrupt())操作.默認:true   
private final HystrixProperty executionIsolationThreadInterruptOnTimeout; 
// 是否開啟請求日志,默認:true   
private final HystrixProperty requestLogEnabled;   
//是否開啟請求緩存,默認:true   
private final HystrixProperty requestCacheEnabled; // Whether request caching is enabled
//請求合並是允許的最大請求數,默認: Integer.MAX_VALUE   
private final HystrixProperty maxRequestsInBatch;   
//批處理過程中每個命令延遲的時間,默認:10毫秒   
private final HystrixProperty timerDelayInMilliseconds;   
//批處理過程中是否開啟請求緩存,默認:開啟   
private final HystrixProperty requestCacheEnabled; 
/* 配置線程池大小,默認值10個 */ 
private final HystrixProperty corePoolSize; 
/* 配置線程值等待隊列長度,默認值:-1 建議值:-1表示不等待直接拒絕,測試表明線程池使用直接決絕策略+ 合適大小的非回縮線程池效率最高.所以不建議修改此值。 當使用非回縮線程池時,queueSizeRejectionThreshold,keepAliveTimeMinutes 參數無效 */
private final HystrixProperty maxQueueSize; 

其他常用限流降級組件

Sentinel:阿裡巴巴集團內部基礎技術模塊,覆蓋瞭所有的核心場景。Sentinel 也因此積累瞭大量的流量歸整場景以及生產實踐。2018 年,Sentinel 開源,並持續演進。

Resilience4j:也是一個輕量級的容錯組件,其靈感來自於 Hystrix,但主要為 Java 8 和函數式編程所設計。輕量級體現在其隻用 Vavr庫(前身是 Javaslang),沒有任何外部依賴。而 Hystrix 依賴瞭 Archaius ,Archaius 本身又依賴很多第三方包,例如 Guava、Apache Commons Configuration 等。

Sentinel 與 Hystrix resilience4j 對比

  Sentinel Hystrix resilience4j
隔離策略 信號量隔離(並發線程數限流) 線程池隔離/信號量隔離 信號量隔離
熔斷降級策略 基於響應時間、異常比率、異常數等 異常比率模式、超時熔斷 基於異常比率、響應時間
實時統計實現 滑動窗口(LeapArray) 滑動窗口(基於 RxJava) Ring Bit Buffer
動態規則配置 支持多種配置源 支持多種數據源 有限支持
擴展性 豐富的 SPI 擴展接口 插件的形式 接口的形式
基於註解的支持 支持 支持 支持
限流 基於 QPS,支持基於調用關系的限流 有限的支持 Rate Limiter
集群流量控制 支持 不支持 不支持
流量整形 支持預熱模式、勻速排隊模式等多種復雜場景 不支持 簡單的 Rate Limiter 模式
系統自適應保護 支持 不支持 不支持
控制臺 提供開箱即用的控制臺,可配置規則、查看秒級監控、機器發現等 簡單的監控查看 不提供控制臺,可對接其它監控系統
多語言支持 Java / C++ Java Java
開源社區狀態 活躍 停止維護 較活躍

至於如何選擇,個人覺得,隻要滿足需求掌握使用理念,選技術文檔最多最全的一種即可,你最熟悉的就是最適合你的。

總結

Hystrix 框架提供瞭高可用相關的各種各樣的功能,有瞭 Hystrix 的保護,整個系統可以長期處於高可用的狀態。

這一小節的內容不僅僅是學會 Hystrix 這門工具的使用,更重要的是理解降級的設計理念,即便 Hystrix 官方已經停止維護更新,但不可否定 Hystrix 是一個優秀的生產力工具。

以上就是java分佈式面試降級組件Hystrix的功能特性的詳細內容,更多關於java分佈式面試降級組件Hystrix的資料請關註WalkonNet其它相關文章!

推薦閱讀: