Hystrix是如何處理請求,在官網有詳細介紹:https://github.com/Netflix/Hystrix/wiki/How-it-Works, 本文重點圍繞下方流程圖介紹一下主要的流程;
Hystrix是將我們的系統間調用包裝成一個個Comman來執行,舉個簡單的例子:
public class TestCommand extends HystrixCommand<Integer> { private TestServiceA serviceA; private int index; private static HystrixCommandProperties.Setter setter = HystrixCommandProperties.Setter() //至少有10個請求,熔斷器才進行錯誤率的計算 .withCircuitBreakerRequestVolumeThreshold(3) //熔斷器中斷請求5秒后會進入半打開狀態,放部分流量過去重試 .withCircuitBreakerSleepWindowInMilliseconds(5000) //錯誤率達到50開啟熔斷保護 // .withCircuitBreakerErrorThresholdPercentage(30) .withExecutionIsolationSemaphoreMaxConcurrentRequests(2) .withExecutionTimeoutEnabled(true) .withExecutionTimeoutInMilliseconds(1000); protected TestCommand(TestServiceA serviceA, int index) { super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("testGroupKey")) .andCommandKey(HystrixCommandKey.Factory.asKey("testCommandKey")) .andCommandPropertiesDefaults(setter) .andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter().withCoreSize(10))); this.serviceA = serviceA; this.index = index; } @Override protected Integer run() throws Exception { return serviceA.service(index); } @Override protected Integer getFallback() { // if service execute fail, do sth return -1; } }
// execute
TestCommand testCommand = new TestCommand(new TestServiceA(), i);
testCommand.execute();
我們只需要用一個Command來包裝我們的RPC/RMI調用,上面就使用 TestCommand 包裝了一個TestService 方法;
下面解釋流程圖中具體邏輯;
1、包裝請求:
可以使用繼承HystrixCommand或HystrixObservableCommand來包裝業務方法;
2、發起請求:
使用調用Command的execute來執行一個業務方法調用;
Hystrix除了提供了execute方法,另外還提供了3種方來,所有的請求入口:
K value = command.execute(); Future<K> fValue = command.queue(); Observable<K> ohValue = command.observe(); //hot observable Observable<K> ocValue = command.toObservable(); //cold observable
如上圖所示:
執行同步調用execute方法,會調用queue().get()方法,queue()又會調用toObservable().toBlocking().toFuture();
所以,所有的方法調用都依賴Observable的方法調用,只是取決於是需要同步還是異步調用;
3、緩存處理:
當請求來到后,會判斷請求是否啟用了緩存(默認是啟用的),再判斷當前請求是否攜帶了緩存Key;
如果命中緩存就直接返回;否則進入剩下的邏輯;
4、判斷斷路器是否打開(熔斷):
斷路器是Hystrix的設計核心,斷路器是實現快速失敗的重要手段(斷路器打開就直接返回失敗);
可以設置斷路器打開一定時間后,可以進行嘗試進行業務請求(默認是5000毫秒);
5、判斷是否進行業務請求(請求是否需要隔離或降級):
是否進行業務請求之前還會根據當前服務處理質量,判斷是否需要去請求業務服務;
如果當前服務質量較低(線程池/隊列/信號量已滿),那么也會直接失敗;
線程池或信號量的選擇(默認是線程池):
線程池主要優勢是客戶端隔離和超時設置,但是如果是海量低延遲請求時,頻繁的線程切換帶來的損耗也是很可觀的,這種情況我們就可以使用信號量的策略;
信號量的主要缺點就是不能處理超時,請求發送到客戶端后,如果被客戶端pending住,那么就需要一直等待;
6、執行業務請求:
當前服務質量較好,那么就會提交請求到業務服務器去;
HystrixObservableCommand.construct()
or HystrixCommand.run()
7、健康監測:
根據歷史的業務方法執行結果,來統計當前的服務健康指標,為斷路器是否熔斷等動作作為依據;
8/9、響應失敗或成功的處理結果