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

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

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

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

默認設置:git

 

 

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

因此得注意zuul服務自己的線程池大小,後端服務的線程池大小,以及隔離信號量或線程池的線程池大小,防止1個線程被佔用光github

 

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個覆蓋socket

 

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

當使用線程池隔離時,由於多了一層線程池,並且是用的RXJava實現,故能夠直接支持hytrix的超時調用ui

若是使用的是信號量隔離,那麼hytrix的超時將會失效,可是ribbon或者socket自己的超時機制依然是有效果的,並且超時後會釋放掉信號spa

 

5,但若是是信號量隔離,依然得注意hytrix設置的超時時間,由於它涉及到信號量的釋放

先看看hytrix信號量的實現:.net

信號量的設置在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分析源碼才能避免踩坑。

 

 

公衆號:

何錦彬 2018.09.25

相關文章
相關標籤/搜索