原文鏈接:https://www.dubby.cn/detail.html?id=9100
1、CommandKey緩存問題
考慮這樣一個(gè)場景,先new了一個(gè)Command(commandKey="commandA"),他的隔離策略是信號(hào)量隔離(ExecutionIsolationStrategy.SEMAPHORE),之后又new了一個(gè)Command(commandKey="commandA"),不過它的隔離策略是線程隔離(ExecutionIsolationStrategy.THREAD),那么問題來了,這個(gè)新的command究竟是哪個(gè)隔離策略呢?
還是信號(hào)量隔離,因?yàn)镠ystrix有針對(duì)commandKey的緩存。
當(dāng)nenw一個(gè)新的command的參數(shù)設(shè)置階段(也就是AbstractCommand.initCommandProperties方法)時(shí),會(huì)優(yōu)先查看緩存里commandKey是否已經(jīng)存在,如果存在直接返回。
[圖片上傳失敗...(image-43d75f-1539487185510)]
2、信號(hào)量隔離(semaphore-isolated)的超時(shí)處理
Hystrix的官方wiki上說的是“This allows Hystrix to shed load without using thread pools but it does not allow for timing out and walking away.”。這句話讓我產(chǎn)生了誤解,其實(shí)他的意思并不是說信號(hào)量隔離不支持超時(shí),而是不支持超時(shí)之后立刻返回。
其實(shí)很好理解,因?yàn)樾盘?hào)量隔離并沒有使用線程池,所以這個(gè)command執(zhí)行的線程就是caller的線程,所以沒有辦法中斷這個(gè)線程,甚至我們可以說,這樣做是極度不安全的,因?yàn)榭赡軙?huì)中斷應(yīng)用線程。
那么,如果使用了信號(hào)量隔離,并且配置了超時(shí)時(shí)間1s,那么如果超時(shí)了5s,會(huì)發(fā)生什么呢?
這個(gè)command還是會(huì)執(zhí)行5s才回返回,不過返回的是getFallback返回的結(jié)果。
[圖片上傳失敗...(image-8f6fa0-1539487185510)]
相關(guān)閱讀:ExecutionIsolationStrategy.SEMAPHORE and interrupt-on-timeout
3、線程隔離下的getFallback在哪個(gè)線程里執(zhí)行
這幾張圖其實(shí)不是我想說明這個(gè)問題而截得,不過正好也可以用來說明,這里總結(jié)下。
- 如果是正常的執(zhí)行,拋異常,那么getFallback是在我們定義的線程池中執(zhí)行;
- 如果是因?yàn)槌瑫r(shí)被中斷,那么getFallback是在Timer的線程池(這是Hystrix自己的一個(gè)線程池,專門跑定時(shí)任務(wù),用來計(jì)時(shí))中執(zhí)行;
- 如果已經(jīng)被熔斷了,那么getFallback是在caller所在的線程中執(zhí)行;
- 如果是command超出了隊(duì)列限制,那么getFallback是在caller所在的線程中執(zhí)行;
4、Hystrix執(zhí)行失敗但不能進(jìn)入fallback的問題
如果command執(zhí)行方法拋出的throwable是:
- StackOverflowError
- VirtualMachineError
- ThreadDeath
- LinkageError
中的Error,那么Hystrix不會(huì)進(jìn)入fallback方法,而會(huì)直接拋出HystrixRuntimeException,因?yàn)檫@幾個(gè)Error被認(rèn)為是不可恢復(fù)錯(cuò)誤。
AbstractCommand.java
:
5、HystrixRuntimeException: Command fallback execution rejected.
異常全文是:
com.netflix.hystrix.exception.HystrixRuntimeException: TestCommand fallback execution rejected.
執(zhí)行錯(cuò)誤了,本應(yīng)該去執(zhí)行fallback方法,可是卻被reject了,為什么呢?
這種情況下,一般來說是command已經(jīng)熔斷了,所有請(qǐng)求都進(jìn)入fallback導(dǎo)致的,因?yàn)閒allback默認(rèn)是有個(gè)并發(fā)最大處理的限制,fallback.isolation.semaphore.maxConcurrentRequests,默認(rèn)是10,這個(gè)方法及時(shí)很簡單,處理很快,可是QPS如果很高,還是很容易達(dá)到10這個(gè)閾值,導(dǎo)致后面的被拒絕。
解決方法也很簡單:
- fallback盡可能的簡單,不要有耗時(shí)操作,如果用一個(gè)http接口來作為另一個(gè)http接口的降級(jí)處理,那你必須考慮這個(gè)http是不是也會(huì)失敗;
- 可以適當(dāng)增大fallback.isolation.semaphore.maxConcurrentRequests
如果關(guān)心具體處理邏輯的話,可以看下
AbstractCommand.getFallbackOrThrowException