分佈式環境中咱們不能確保調用的依賴服務不發生問題。諸如基礎設施服務器宕機(數據庫、緩存),外部依賴服務掛掉,網絡抖動引發的鏈接超時。當這些狀況發生時,大量請求迅速涌到鏈路上的故障節點,就會像繁忙的高速公路上發生交通事故短期內就會形成交通擁堵,直至癱瘓。html
不能讓局部服務的故障不斷擴散蔓延致使全局系統不可用,形成重大生產事故,因此要對外部依賴進行資源隔離,將故障控制在小範圍內。java
建立副線程去調用依賴服務, 執行依賴代碼的線程與請求線程(好比Tomcat線程)分離 ,當副線程請求調用失敗、超時等異常狀況而阻塞時不會影響到主線程。算法
能夠利用線程可設置超時的特性給經過網絡進行的服務間調用設置超時時間。spring
線程池機制的優缺點數據庫
線程池機制的優勢:後端
(1) 任何一個依賴服務均可以被隔離在本身的線程池內,即便本身的線程池資源填滿了,也不會影響任何其餘的服務調用;緩存
(2) 服務能夠隨時引入一個新的依賴服務,由於即便這個新的依賴服務有問題,也不會影響其餘任何服務的調用;tomcat
(3) 當一個故障的依賴服務從新變好的時候,能夠經過清理掉線程池,瞬間恢復該服務的調用,而若是是tomcat線程池被佔滿,再恢復就很麻煩;服務器
(4) 若是一個client調用配置有問題,線程池的健康情況隨時會報告,好比成功/失敗/拒絕/超時的次數統計,而後能夠近實時熱修改依賴服務的調用配置,而不用停機;網絡
(5) 若是一個服務自己發生了修改,須要從新調整配置,此時線程池的健康情況也能夠隨時發現,好比成功/失敗/拒絕/超時的次數統計,而後能夠近實時熱修改依賴服務的調用配置,而不用停機;
(6) 基於線程池的異步本質,能夠在同步的調用之上,構建一層異步調用層;
線程池機制的缺點:
(1) 線程池機制最大的缺點就是增長了cpu的開銷。
用於隔離本地代碼,利用信號量限制同時運行的線程數量,不會建立副線程,開銷較小(複雜算法、多重循環,時間複雜度高的狀況)。
hystrix利用線程池的工做原理來進行限流。
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)
corePoolSize
爲線程池的基本大小。maximumPoolSize
爲線程池最大線程大小。keepAliveTime
和 unit
則是線程空閒後的存活時間。workQueue
用於存聽任務的阻塞隊列。handler
當隊列和最大線程池都滿了以後的飽和策略。
四種拒絕策略
AbortPolicy:不處理,直接拋出異常。
CallerRunsPolicy:若線程池還沒關閉,調用當前所在線程來運行任務,r.run()執行。
DiscardOldestPolicy:LRU策略,丟棄隊列裏最近最久不使用的一個任務,並執行當前任務。
DiscardPolicy:不處理,丟棄掉,不拋出異常。
@HystrixCommand(commandKey = "getCompanyInfoById", groupKey = "company-info", threadPoolKey = "company-info", fallbackMethod = "fallbackMethod", threadPoolProperties = { @HystrixProperty(name = "coreSize", value = "30"), @HystrixProperty(name = "maxQueueSize", value = "101"), @HystrixProperty(name = "keepAliveTimeMinutes", value = "2"), @HystrixProperty(name = "queueSizeRejectionThreshold", value = "15"), })
服務提早配置備用措施,當故障發生時無縫啓用備用方案(或者返回一些默認值),用戶無感知,最終目的都是爲了提供7*24小時穩定服務,這樣對用戶來講纔是高價值、可信賴的優質服務。
線程run()拋出異常,超時,線程池或信號量滿了,或短路了,都會觸發fallback機制。
當請求調用失敗率達到閥值自動觸發降級(如因網絡故障/超時形成的失敗率高),熔斷器觸發的快速失敗會進行快速恢復。
工做流程:
根據監控結果能夠看出合理的超時時長配置和計算出服務集羣部署的規模大小。
計算公式:
服務集羣部署的規模大小 = 服務在健康狀態時每秒支撐的最大請求數 * 第99百分位延遲時間(以秒爲單位)+ 少許用於緩衝的額外線程
舉個例子:某個服務須要支撐的QPS爲1000,即每秒須要處理1000個請求。假設經過統計獲得百分之99的服務耗時爲100ms,那一個線程1秒內能處理10個請求,一臺機器的線程池大小通常就使用默認配置爲10,即一臺機器1秒內能處理 10 * 10 = 100個請求,最後得出該服務總共須要部署 1000/100 = 10臺機器。
在一次請求中,若是有多個command,參數都是同樣的,調用的接口也是同樣的,其實結果能夠認爲也是同樣的。這個時候,可讓第一次command執行返回的結果,被緩存在內存中,而後在這個請求上下文中,後續的其餘對這個依賴的調用所有從內存中取用緩存結果就能夠了。
https://blog.csdn.net/zhuchua...
高併發的場景下,將一個時間窗口內多個相同請求合併成一個請求,較少網絡鏈接次數。
http://blog.didispace.com/spr...
默認狀況下,hystrix不會將父線程的上下文傳播到有hystrix命令管理的線程中。例如,在默認狀況下,對被父線程調用並由@HystrixCommand保護的方法而言,在父線程中設置爲ThreadLocal的值是不會自動傳遞到子線程的。實際場景中的例子,調用通用UserUtil工具類從請求頭獲取不到userId, jwt串, 租戶id。
兩種方法:
(1) 手動設置
手動從父線程ThreadLocal中取出須要的key-value設置到子線程中。
(2) 代碼配置
自定義HystrixConcurrencyStrategy