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被拒絕訪問