服務雪崩的過程

上面是一組簡單的服務依賴關系A,B服務同時依賴于基礎服務C,基礎服務C又調(diào)用了服務D

服務D是一個輔助類型服務,整個業(yè)務不依賴于D服務,某天D服務突然響應時間變長,導致了核心服務C響應時間變長,其上請求越積越多,C服務也出現(xiàn)了響應變慢的情況,由于A,B強依賴于服務C,故而一個無關緊要的服務卻影響了整個系統(tǒng)的可用。

雪崩是系統(tǒng)中的蝴蝶效應導致其發(fā)生的原因多種多樣,有不合理的容量設計,或者是高并發(fā)下某一個方法響應變慢,亦或是某臺機器的資源耗盡。從源頭上我們無法完全杜絕雪崩源頭的發(fā)生,但是雪崩的根本原因來源于服務之間的強依賴,所以我們可以提前評估,做好熔斷,隔離,限流。
熔斷
熔斷器
說到熔斷器,java技術棧的同學第一時間會想到Hystrix。下面我們一起來看下熔斷器的實現(xiàn)原理

熔斷器實際上是一個簡單的有限狀態(tài)機(Finite State Machine)
1.請求錯誤率達到某一閾值,熔斷器全開,產(chǎn)生熔斷(熔斷期間會對所有請求采用降級處理)
2.到熔斷時間窗口之后,熔斷器會進入半開狀態(tài),此時hystrix會放過1個試驗性請求
3.如果該試驗性請求成功,熔斷器進入關閉狀態(tài)
4.如果該試驗性請求失敗,熔斷器重新進入全開狀態(tài)
以下摘自hystrix官方文檔
1.Assuming the volume across a circuit meets a certain threshold (HystrixCommandProperties.circuitBreakerRequestVolumeThreshold())...
2.And assuming that the error percentage exceeds the threshold error percentage (HystrixCommandProperties.circuitBreakerErrorThresholdPercentage())...
3.Then the circuit-breaker transitions from?CLOSED?to?OPEN.
4.While it is open, it short-circuits all requests made against that circuit-breaker.
5.After some amount of time (HystrixCommandProperties.circuitBreakerSleepWindowInMilliseconds()), the next single request is let through (this is the?HALF-OPEN?state). If the request fails, the circuit-breaker returns to the?OPEN?state for the duration of the sleep window. If the request succeeds, the circuit-breaker transitions to?CLOSED?and the logic in?1.?takes over again.
指標Metric
hystrix內(nèi)部的統(tǒng)計指標是基于觀察者模式的,只不過事件的統(tǒng)計方式1.4.x與1.5.0王后的版本有些許不同。
1.4.x版本實現(xiàn)

采用滑動窗口+滾筒的機制進行指標統(tǒng)計,一個完整的時間窗口被劃分為多個bucket,圖中的一個bucket統(tǒng)計的是1s內(nèi)的計數(shù)指標,分別是success,failure,timeout,rejection,熔斷器評判標準是整個時間窗口的成功失敗比。
1.5.0以后版本
利用了hystirx大量引入了rxjava? api,其保留了滾筒機制,只不過bucket內(nèi)部的時間段指標統(tǒng)計利用了Observable.window?函數(shù)進行時間段內(nèi)聚合統(tǒng)計。

Observable.window操作分為2個維度,分別是bucket級別和window級別。
bucket級別的數(shù)據(jù)聚合是在BucketedCounterStream.java類中執(zhí)行,其功能是將服務調(diào)用級別的輸入數(shù)據(jù)流 inputEventStream 以 bucketSizeInMs 毫秒為一個桶進行了匯總,匯總的結果輸入到桶級別數(shù)據(jù)流 bucketedStream。

window級別的數(shù)據(jù)在BucketedRollingCounterStream.java類中進行聚合,numBuckets定義了window的大小,reduceWindowToSummary為窗口求和操作。

使用rxjava給hystrix帶來了下面幾點好處
無需再次編碼
比如window中的"滾筒"操作直接可以利用rxjava的window函數(shù)并且在后臺線程中運行,無需自己再編碼實現(xiàn)
減少了線程同步
比如每條command emit的數(shù)據(jù)會發(fā)射到?thread-local級別的rx.Subject,無需再進行同步操作,
資源隔離
太空科幻題材電影永遠是好萊塢最炙手可熱的主題,而一部電影是否能夠扣人心弦逃跑的橋段自然不能少,尤其在狹小的空間站中?!兜匦囊Α分械呐魈与x著火的國際空間站,《異行》中飛船上的伙計們逃離異行的追殺,《星際穿越》中庫珀逃離旋轉(zhuǎn)的空間站,似乎大家面對危險的第一反應就是“關上艙門”,把危險隔離在外。

防水倉
實際上船艙分開設計本身就是一種隔離的思想,一個防水倉進水不會導致整艘輪船沉沒。如果把我們整個系統(tǒng)比作海上漂浮的一艘輪船,那么我們系統(tǒng)的各個服務就好比輪船上的各個密封艙,服務A如果強依賴于服務B那么他們就在一個艙里。
應用級別隔離
常見的應用界別隔離手段有線程池隔離,信號量隔離,連接池隔離,hystrix實現(xiàn)了前2種,其各自優(yōu)缺點如下

硬件資源級別隔離
說到硬件級別的隔離就想到了近些年來大熱的docker

docker的sandbox特性可以讓我們的應用如圖中的集裝箱一個個彼此分開,單個集裝箱的損壞不會影響到整個服務器環(huán)境。docker為我們提供了以下幾種硬件隔離方式。
docker中計算機資源隔離
docker 通過 cgroup 來控制容器使用的資源配額,包括 CPU、內(nèi)存、磁盤IO三大方面
cgroup 是 Control Groups 的縮寫,是 Linux 內(nèi)核提供的一種可以限制、記錄、隔離進程組所使用的物理資源(如 cpu、memory、磁盤IO等等) 的機制,被 LXC、docker 等很多項目用于實現(xiàn)進程資源控制。
CPU
CPU份額控制
通過-c或者–cpu-shares參數(shù),在創(chuàng)建容器時指定容器所使用的 CPU 份額值
CPU周期控制
-cpu-period、--cpu-quota兩個參數(shù)控制容器可以分配到的 CPU 時鐘周期
CPU核心數(shù)控制
使用–cpuset-cpu s和–cpuset-mems參數(shù)可以控制容器運行限定使用哪些 CPU 內(nèi)核和內(nèi)存節(jié)點
內(nèi)存
-m 或 --memory:設置內(nèi)存的使用限額,例如 100M, 2G。
--memory-swap:設置 內(nèi)存+swap 的使用限額。
IO
block IO 權重
--blkio-weight參數(shù)可以改變?nèi)萜?block IO 的優(yōu)先級
限制 bps 和 iops
bps 是 byte per second,每秒讀寫的數(shù)據(jù)量。iops 是 io per second,每秒 IO 的次數(shù)。
--device-read-bps,限制讀某個設備的 bps。
--device-write-bps,限制寫某個設備的 bps。
--device-read-iops,限制讀某個設備的 iops。
--device-write-iops,限制寫某個設備的 iops。
docker中內(nèi)核資源隔離

docker網(wǎng)絡隔離
none 網(wǎng)絡
host 網(wǎng)絡
bridge 網(wǎng)絡
User-defined 網(wǎng)絡
資料參考:
http://reactivex.io/documentation/operators.html
https://segmentfault.com/a/1190000005988895
https://github.com/Netflix/Hystrix/wiki
https://blog.csdn.net/hustspy1990/article/details/77978329
http://blog.51cto.com/wzlinux/2046566