用網關zuul時,熔斷hytrix裏面的坑

1,zuul 默認的隔離級別是信號量,默認最大隔離信號量是100

信號量隔離和線程池隔離的區別如下:

https://my.oschina.net/u/867417/blog/2120713 

默認設置:

 

 

2,zuul裏隔離是按服務隔離的,也就是1個服務1個信號量,非接口級別的

所以得注意zuul服務本身的線程池大小,後端服務的線程池大小,以及隔離信號量或線程池的線程池大小,防止1個線程被佔用光

 

3,在zuul裏,重新封裝了hytrix的一些配置名稱,導致hytrix的一些原生配置會失效

具體設置hytrix參數的setter如下:

需要通過zuulProperties重新設置的屬性如下:

  • 隔離級別指定:zuul.ribbonIsolationStrategy: SEMAPHORE
  • 信號隔離的默認隔離大小:semaphore.maxSemaphores = 20
  • 指定服務的信號隔離級別大小:zuul.eureka.serviceId.semaphore.maxSemaphores = 20

而原生的hytrix.command.default.execution.isolation.strategy和maxConcurrentRequests的配置將失效,會被這3個覆蓋

 

4,如果用的是信號量隔離級別,那麼hytrix的超時將會失效

當使用線程池隔離時,因爲多了一層線程池,而且是用的RXJava實現,故可以直接支持hytrix的超時調用

如果使用的是信號量隔離,那麼hytrix的超時將會失效,但是ribbon或者socket本身的超時機制依然是有效果的,而且超時後會釋放掉信號

 

5,但如果是信號量隔離,依然得注意hytrix設置的超時時間,因爲它涉及到信號量的釋放

先看看hytrix信號量的實現:

信號量的設置在AbstractCommand裏:

 

用了個ConcurrentHashMap<String, TryableSemaphore> 去保存個計數器的設置,key對應的是commandKey, TryableSemaphore(TryableSemaphoreActual)對應計數器實現,用java的AtomicInter實現,tryAcquire()時,進行原子加incrementAndGet,如果大於設置的maxConcurrentRequests,則進行阻塞

 

返回fallBack;

執行完後,釋放也很簡單。原子減去,decrementAndGet。這樣看來,信號量就是一個計數器。

那麼爲什麼說和超時有關呢,因爲超時時,即使訪問線程還在阻塞,也會把當前信號量釋放。(怎麼做的,因爲hytrix超時(此時訪問線程並未超時)的後續處理部分是由RxJava控制,不是依靠訪問線程的超時)

這句會造成,如果你配置了超時1s,如:

hystrix.command.default.execution.timeout.enabled=true

hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=1000

那麼你的信號量生效將是1s內,也就是說,過了1s,不管你socket是否超時,hytrix都會釋放掉信號量

 

6,在zuul裏,線程池隔離情況下,是異步訪問的,而不是異步

這一點在上篇有說到,

調用的是hytrix command的excute方法,hytrix的官網原文說明如下:

  • execute() — blocks, then returns the single response received from the dependency (or throws an exception in case of an error)

execute是一個阻塞方法,也就是說,如果不合理的設置線程池的大小,和超時時間,還是有可能把zuul的線程消耗完。從而失去對服務的保護作用

 

總結:

zuul的複雜度很大程度因爲集成了hytrix, ribbon,導致設置超時,線程,隔離都有一定的複雜度,本身文檔確沒那麼清楚。

很多地方還是需要debug分析源碼才能避免踩坑。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章