九、 深入理解線程池隔離技術的設計原則

9.1 線程池隔離技術面對的場景

Hystrix採取了bulkhead艙壁隔離技術,來將外部依賴進行資源隔離,進而避免任何外部依賴的故障導致本服務崩潰(線程池隔離,學術名稱:bulkhead,艙壁隔離)。外部依賴的調用在單獨的線程中執行,這樣就能跟調用線程隔離開來,避免外部依賴調用timeout耗時過長,導致調用線程被卡死

 

Hystrix對每個外部依賴用一個單獨的線程池,這樣的話,如果對那個外部依賴調用延遲很嚴重,最多就是耗盡那個依賴自己的線程池而已,不會影響其他的依賴調用

 

Hystrix選擇用線程池機制來進行資源隔離,要面對的場景如下:

(1)每個服務都會調用幾十個後端依賴服務,那些後端依賴服務通常是由很多不同的團隊開發的。

(2)每個後端依賴服務都會提供它自己的client調用庫,比如說用thrift的話,就會提供對應的thrift依賴。

(3)client調用庫隨時會變更。

(4)client調用庫隨時可能會增加新的網絡請求的邏輯。

(5)client調用庫可能會包含諸如自動重試,數據解析,內存中緩存等邏輯。

(6)client調用庫一般都對調用者來說是個黑盒,包括實現細節,網絡訪問,默認配置,等等。

(7)在真實的生產環境中,經常會出現調用者,突然發現,client調用庫發生了某些變化。

(8)即使client調用庫沒有改變,依賴服務本身可能有會發生邏輯上的變化。

(9)有些依賴的client調用庫可能還會拉取其他的依賴庫,而且可能那些依賴庫配置的不正確。

(10)大多數網絡請求都是同步調用的。

(11)調用失敗和延遲,也有可能會發生在client調用庫本身的代碼中,不一定就是發生在網絡請求中。

 

9.2 線程池機制的優點

(1)任何一個依賴服務都可以被隔離在自己的線程池內,即使自己的線程池資源填滿了,也不會影響任何其他的服務調用

(2)服務可以隨時引入一個新的依賴服務,因爲即使這個新的依賴服務有問題,也不會影響其他任何服務的調用

(3)當一個故障的依賴服務重新變好的時候,可以通過清理掉線程池,瞬間恢復該服務的調用,而如果是tomcat線程池被佔滿,再恢復就很麻煩

(4)如果一個client調用庫配置有問題,線程池的健康狀況隨時會報告,比如成功/失敗/拒絕/超時的次數統計,然後可以近實時熱修改依賴服務的調用配置,而不用停機

(5)如果一個服務本身發生了修改,需要重新調整配置,此時線程池的健康狀況也可以隨時發現,比如成功/失敗/拒絕/超時的次數統計,然後可以近實時熱修改依賴服務的調用配置,而不用停機

(6)基於線程池的異步本質,可以在同步的調用之上,構建一層異步調用層

簡單來說,最大的好處,就是資源隔離,確保說,任何一個依賴服務故障,不會拖垮當前的這個服務

 

9.3 線程池機制的缺點

(1)線程池機制最大的缺點就是增加了cpu的開銷

除了tomcat本身的調用線程之外,還有hystrix自己管理的線程池

(2)每個command的執行都依託一個獨立的線程,會進行排隊,調度,還有上下文切換

(3)Hystrix官方自己做了一個多線程異步帶來的額外開銷,通過對比多線程異步調用+同步調用得出,Netflix API每天通過hystrix執行10億次調用,每個服務實例有40個以上的線程池,每個線程池有10個左右的線程

(4)最後發現說,用hystrix的額外開銷,就是給請求帶來了3ms左右的延時,最多延時在10ms以內,相比於可用性和穩定性的提升,這是可以接受的

 

我們可以用hystrix semaphore技術來實現對某個依賴服務的併發訪問量的限制,而不是通過線程池/隊列的大小來限制流量

 

sempahore技術可以用來限流和削峯,但是不能用來對調研延遲的服務進行timeout和隔離

execution.isolation.strategy,設置爲SEMAPHORE,那麼hystrix就會用semaphore機制來替代線程池機制,來對依賴服務的訪問進行限流

如果通過semaphore調用的時候,底層的網絡調用延遲很嚴重,那麼是無法timeout的,只能一直block住。

一旦請求數量超過了semephore限定的數量之後,就會立即開啓限流

 

9.4 線程池接口限流參數設置

withCoreSize:設置你的線程池的大小

withMaxQueueSize:設置的是你的等待隊列,緩衝隊列的大小

withQueueSizeRejectionThreshold:如果withMaxQueueSize<withQueueSizeRejectionThreshold,那麼取的是withMaxQueueSize,反之,取得是withQueueSizeRejectionThreshold

線程池本身的大小,如果你不設置另外兩個queue相關的參數,等待隊列是關閉的

.andThreadPoolPropertiesDefaults(

                            HystrixThreadPoolProperties.Setter()

                            //CoreSize:設置線程池的大小,默認是10,如果你不設置另外兩個queue相關的參數,等待隊列是關閉

                            //先進去線程池的是10個請求,5個請求進入等待隊列,線程池裏有空閒,等待隊列中的請求如果還沒有timeout,那麼就進去線程池去執行

                            .withCoreSize(10)

                            //設置線程池的最大大小,只有在設置allowMaximumSizeToDivergeFromCoreSize的時候才能生效

                            .withMaximumSize(18)

                            //允許線程池大小自動動態調整(默認爲false),設置爲true之後,maxSize就生效了,此時如果一開始是coreSize個線程,隨着併發量上來,那麼就會自動獲取新的線程,

                            //但是如果線程在keepAliveTimeMinutes內空閒,就會被自動釋放掉

                            .withAllowMaximumSizeToDivergeFromCoreSize(true)

                            //如果coreSize < maxSize,那麼這個參數就設置了一個線程多長時間空閒之後,就會被釋放掉

                            .withKeepAliveTimeMinutes(1)

                            //設置的是你的等待隊列,緩衝隊列的大小

                            .withMaxQueueSize(12)

                            //QueueSizeRejectionThreshold:控制隊列的最大大小HystrixCommand在提交到線程池之前,其實會先進入一個隊列中,這個隊列滿了之後,纔會reject

                            //如果withMaxQueueSize<withQueueSizeRejectionThreshold,那麼取的是withMaxQueueSize,反之,取得是withQueueSizeRejectionThreshold

                           .withQueueSizeRejectionThreshold(8) queue生效

 

 

 

withExecutionTimeoutInMilliseconds(20000):手動設置timeout時長,timeout也設置大一些,否則如果請求放等待隊列中時間太長了,直接就會timeout,等不到去線程池裏執行了

withFallbackIsolationSemaphoreMaxConcurrentRequests(30):fallback,sempahore限流,30個,避免太多的請求同時調用fallback被拒絕訪問

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