真該跟架構(gòu)師來深度解析微服務(wù)高并發(fā)熔斷降級 :新版熔斷降級!
新版熔斷降級
Sentinel 1.8.0發(fā)布于2020年08月20日,從官方文檔來看,該版本的最大亮點是對熔斷降級功能進行了重構(gòu)。舊版本的熔斷降級功能對慢調(diào)用并不友好,而新版本改善了這個問題。
舊版熔斷降級的不足
Sentinel 1.7.x支持以下3種熔斷降級策略。
? DEGRADE_GRADE_RT:按平均響應(yīng)耗時。
?
DEGRADE_GRADE_EXCEPTION_RATIO:按失敗比率。
?
DEGRADE_GRADE_EXCEPTION_COUNT:按失敗次數(shù)。
1. 按平均響應(yīng)耗時
當熔斷降級策略為DEGRADE_GRADE_RT時,閾值為平均響應(yīng)耗時,如果秒級滑動窗口統(tǒng)計的平均響應(yīng)耗時超過熔斷降級規(guī)則配置的閾值,則當連續(xù)rtSlowRequestAmount個請求之后,平均響應(yīng)耗時依然超過閾值,則觸發(fā)熔斷。
將1秒內(nèi)請求耗時的平均值與熔斷降級規(guī)則配置的閾值進行比較,判斷一個請求是否是慢請求。在接口耗時較長的情況下,如果1秒內(nèi)統(tǒng)計的請求較為稀疏,會導(dǎo)致平均響應(yīng)耗時容易受某個特別慢的請求影響,從而導(dǎo)致熔斷效果不佳。
假設(shè)某接口調(diào)用的平均耗時正常為100毫秒,熔斷的閾值為500毫秒,如果1秒內(nèi)有10個請求,其中一個請求的耗時超過了10秒,就會將平均響應(yīng)耗時延長到1090毫秒,則后續(xù)需要很多個平均耗時為100毫秒的請求才能將平均耗時降下來,這種情況下很容易觸發(fā)熔斷。
2. 按失敗比率
當熔斷降級策略為
DEGRADE_GRADE_EXCEPTION_RATIO時,閾值為失敗總數(shù)與成功總數(shù)的比值,如果秒級滑動窗口統(tǒng)計的失敗總數(shù)與成功總數(shù)的比值大于或等于閾值,則觸發(fā)熔斷。
使用1秒內(nèi)失敗總數(shù)與成功總數(shù)的比值來判斷是否達到熔斷降級規(guī)則配置的閾值,這與按平均響應(yīng)耗時一樣,請求越稀疏,失敗比率就越容易受單個異常請求的影響,從而提高失敗比率,因此
DEGRADE_GRADE_EXCEPTION_RATIO也不適用于慢調(diào)用場景。
3. 按失敗次數(shù)
當熔斷降級策略為
DEGRADE_GRADE_EXCEPTION_COUNT時,閾值為失敗次數(shù),若分鐘級滑動窗口統(tǒng)計的異??倲?shù)大于或等于閾值,則觸發(fā)熔斷。
使用1分鐘內(nèi)統(tǒng)計的失敗請求總數(shù)作為閾值,即便將timeWindow配置為1秒,并在timeWindow秒之后關(guān)閉開關(guān),開關(guān)也會立即被打開,因此大部分場景都不使用
DEGRADE_GRADE_EXCEPTION_COUNT,這個缺點也使其成了一個無意義的選項。
?新版本的改進
Sentinel 1.8.0使用的熔斷降級策略(CircuitBreakerStrategy)如下。
? SLOW_REQUEST_RATIO:按慢請求比率。
? ERROR_RATIO:按失敗比率。
? ERROR_COUNT:按失敗次數(shù)。
DegradeRule類調(diào)整后的源碼如下。

其與舊版本的區(qū)別如下。
? grade:熔斷降級策略,取值為CircuitBreakerStrategy,并與舊版本取值兼容。
? timeWindow:時間窗口大小,熔斷器從打開狀態(tài)到關(guān)閉狀態(tài)的最小時間間隔。
? slowRatioThreshold:慢請求比率,當熔斷降級策略配置為SLOW_REQUEST_RATIO時使用。
? statIntervalMs:統(tǒng)計時長,滑動窗口的周期,單位為毫秒。
1. 新版本支持的3種熔斷降級策略均可自定義統(tǒng)計時長
DegradeRule類的statIntervalMs字段用于指定資源指標數(shù)據(jù)統(tǒng)計時長,單位為毫秒,默認值為1000。通過配置此字段來延長統(tǒng)計時長,可以將“稀疏”請求調(diào)整為“密集”請求。例如,若某接口的平均耗時為1秒,則可以將統(tǒng)計時長配置為10秒。
2. 對按平均響應(yīng)耗時策略升級,改為按慢請求比率策略
由舊版本的按平均響應(yīng)耗時策略改為按慢請求比率策略,統(tǒng)計慢請求數(shù),使用慢請求數(shù)與總請求數(shù)的比值與閾值比較。
當熔斷降級策略為SLOW_REQUEST_RATIO時,count表示慢請求閾值,只有響應(yīng)耗時超出count的請求才會被記為慢請求,是否為慢請求取決于當前請求的響應(yīng)耗時,與平均耗時沒有關(guān)系;slowRatioThreshold則表示慢請求比率閾值,用于決定是否打開熔斷器的閾值。
3. 引入半開啟自動恢復(fù)支持,并提供熔斷器事件監(jiān)聽器
從Sentinel 1.8.0開始,Sentinel使用熔斷器實現(xiàn)熔斷降級功能,每個熔斷降級規(guī)則對應(yīng)生成一個熔斷器。新版引入的熔斷器支持半開啟自動恢復(fù),并且可以注冊自定義事件監(jiān)聽器以感知熔斷器的狀態(tài)變化。
熔斷器有3種狀態(tài),分別是開啟狀態(tài)、半開啟狀態(tài)和關(guān)閉狀態(tài)。當熔斷器狀態(tài)為半開啟狀態(tài)時,直接拒絕請求;當熔斷器狀態(tài)為關(guān)閉狀態(tài)時,放行請求;當熔斷器狀態(tài)為開啟狀態(tài)時,根據(jù)timeWindow嘗試將開啟狀態(tài)改為半開啟狀態(tài),若修改成功,則放行當前請求,否則拒絕當前請求。
熔斷器的實現(xiàn)原理
熔斷器模式(或斷路器模式)源于Martin Fowler的CircuitBreaker一文。在Hystrix早期就已經(jīng)采用熔斷器實現(xiàn)熔斷降級,而Sentinel在Sentinel 1.8.0中才采用熔斷器模式。
熔斷器狀態(tài)的切換類似于線程狀態(tài)的切換,如圖6.2所示。

圖6.2 熔斷器狀態(tài)的切換
熔斷器初始狀態(tài)為關(guān)閉狀態(tài),當達到熔斷降級規(guī)則配置的閾值時,熔斷器的狀態(tài)從關(guān)閉狀態(tài)變?yōu)殚_啟狀態(tài)。
熔斷器不能直接從開啟狀態(tài)變?yōu)殛P(guān)閉狀態(tài),只有處在半開啟狀態(tài)時才能關(guān)閉。當熔斷器從關(guān)閉狀態(tài)變?yōu)殚_啟狀態(tài)的時間與當前時間的間隔超過timeWindow時,可嘗試將熔斷器變?yōu)榘腴_啟狀態(tài)。
熔斷器可以從半開啟狀態(tài)變?yōu)殛P(guān)閉狀態(tài),也可以從半開啟狀態(tài)變?yōu)殚_啟狀態(tài),但不能從關(guān)閉狀態(tài)變?yōu)榘腴_啟狀態(tài)。
觸發(fā)熔斷器從半開啟狀態(tài)變?yōu)殚_啟狀態(tài)的時機有如下兩個。
① 達到熔斷降級規(guī)則配置的閾值時開啟熔斷器,如慢請求比率達到閾值。
② 當前請求被其他地方拒絕時開啟熔斷器,如對同一資源配置多個熔斷器時,有其他規(guī)則的熔斷器拒絕了請求,或者被限流器限流。
對于處于半開啟狀態(tài)的熔斷器,只要當前請求調(diào)用正常即可關(guān)閉:當熔斷降級策略為按失敗比率或按失敗次數(shù)時,只要當前請求正常即可關(guān)閉熔斷器;當熔斷降級策略為按慢請求比率時,只要當前請求不是慢請求即可關(guān)閉熔斷器。
在狀態(tài)改變的過程中,熔斷器在通知監(jiān)聽器的同時會修改一些數(shù)據(jù),如圖6.3所示。

圖6.3 熔斷器在狀態(tài)改變時修改數(shù)據(jù)
當熔斷器從關(guān)閉狀態(tài)變?yōu)殚_啟狀態(tài)時,更新下一次允許將熔斷器關(guān)閉的時間,即間隔timeWindow秒之后才可以將熔斷器關(guān)閉。
當熔斷器從半開啟狀態(tài)變?yōu)殚_啟狀態(tài)時,更新下一次允許熔斷器關(guān)閉的時間。如果熔斷器剛從開啟狀態(tài)變?yōu)榘腴_啟狀態(tài),此時想嘗試關(guān)閉卻發(fā)現(xiàn)又達到閾值了,就將其恢復(fù)為開啟狀態(tài),并延長timeWindow秒之后再嘗試關(guān)閉。
當熔斷器從半開啟狀態(tài)變?yōu)殛P(guān)閉狀態(tài)時,重置當前時間窗口統(tǒng)計的指標數(shù)據(jù)。每個熔斷器都有一個獨立的滑動窗口用于統(tǒng)計各自關(guān)心的指標數(shù)據(jù)。熔斷器重置當前時間窗口的指標數(shù)據(jù)統(tǒng)計并非重置資源的指標數(shù)據(jù)統(tǒng)計。
重置熔斷器統(tǒng)計的指標數(shù)據(jù)用于避免熔斷器剛關(guān)閉又立即進入開啟狀態(tài)的現(xiàn)象出現(xiàn)。