服務(wù)降級
由于爆炸性的流量沖擊,對一些服務(wù)進(jìn)行有策略的放棄,以此緩解系統(tǒng)壓力,保證目前主要業(yè)務(wù)的正常運行。它主要是針對非正常情況下的應(yīng)急服務(wù)措施:當(dāng)此時一些業(yè)務(wù)服務(wù)無法執(zhí)行時,給出一個統(tǒng)一的返回結(jié)果。
降級服務(wù)的特征
- 原因:整體負(fù)荷超出整體負(fù)載承受能力。
- 目的:保證重要或基本服務(wù)正常運行,非重要服務(wù)延遲使用或暫停使用
- 大?。航档头?wù)粒度,要考慮整體模塊粒度的大小,將粒度控制在合適的范圍內(nèi)
- 可控性:在服務(wù)粒度大小的基礎(chǔ)上增加服務(wù)的可控性,后臺服務(wù)開關(guān)的功能是一項必要配置(單機(jī)可配置文件,其他可領(lǐng)用數(shù)據(jù)庫和緩存),可分為手動控制和自動控制。
- 次序:一般從外圍延伸服務(wù)開始降級,需要有一定的配置項,重要性低的優(yōu)先降級,比如可以分組設(shè)置等級1-10,當(dāng)服務(wù)需要降級到某一個級別時,進(jìn)行相關(guān)配置
降級方式
- 延遲服務(wù):比如發(fā)表了評論,重要服務(wù),比如在文章中顯示正常,但是延遲給用戶增加積分,只是放到一個緩存中,等服務(wù)平穩(wěn)之后再執(zhí)行。
- 在粒度范圍內(nèi)關(guān)閉服務(wù)(片段降級或服務(wù)功能降級):比如關(guān)閉相關(guān)文章的推薦,直接關(guān)閉推薦區(qū)
- 頁面異步請求降級:比如商品詳情頁上有推薦信息/配送至等異步加載的請求,如果這些信息響應(yīng)慢或者后端服務(wù)有問題,可以進(jìn)行降級;
- 頁面跳轉(zhuǎn)(頁面降級):比如可以有相關(guān)文章推薦,但是更多的頁面則直接跳轉(zhuǎn)到某一個地址
- 寫降級:比如秒殺搶購,我們可以只進(jìn)行Cache的更新,然后異步同步扣減庫存到DB,保證最終一致性即可,此時可以將DB降級為Cache。
- 讀降級:比如多級緩存模式,如果后端服務(wù)有問題,可以降級為只讀緩存,這種方式適用于對讀一致性要求不高的場景。
降級預(yù)案
在進(jìn)行降級之前要對系統(tǒng)進(jìn)行梳理,看看系統(tǒng)是不是可以丟卒保帥;從而梳理出哪些必須誓死保護(hù),哪些可降級;比如可以參考日志級別設(shè)置預(yù)案:
- 一般:比如有些服務(wù)偶爾因為網(wǎng)絡(luò)抖動或者服務(wù)正在上線而超時,可以自動降級;
- 警告:有些服務(wù)在一段時間內(nèi)成功率有波動(如在95~100%之間),可以自動降級或人工降級,并發(fā)送告警;
- 錯誤:比如可用率低于90%,或者數(shù)據(jù)庫連接池被打爆了,或者訪問量突然猛增到系統(tǒng)能承受的最大閥值,此時可以根據(jù)情況自動降級或者人工降級;
- 嚴(yán)重錯誤:比如因為特殊原因數(shù)據(jù)錯誤了,此時需要緊急人工降級。
服務(wù)降級分類
- 降級按照是否自動化可分為:自動開關(guān)降級(超時、失敗次數(shù)、故障、限流)和人工開關(guān)降級(秒殺、電商大促等)。
- 降級按照功能可分為:讀服務(wù)降級、寫服務(wù)降級。
- 降級按照處于的系統(tǒng)層次可分為:多級降級。
自動降級分類
- 超時降級:主要配置好超時時間和超時重試次數(shù)和機(jī)制,并使用異步機(jī)制探測回復(fù)情況
- 失敗次數(shù)降級:主要是一些不穩(wěn)定的api,當(dāng)失敗調(diào)用次數(shù)達(dá)到一定閥值自動降級,同樣要使用異步機(jī)制探測回復(fù)情況
- 故障降級:比如要調(diào)用的遠(yuǎn)程服務(wù)掛掉了(網(wǎng)絡(luò)故障、DNS故障、http服務(wù)返回錯誤的狀態(tài)碼、rpc服務(wù)拋出異常),則可以直接降級。降級后的處理方案有:默認(rèn)值(比如庫存服務(wù)掛了,返回默認(rèn)現(xiàn)貨)、兜底數(shù)據(jù)(比如廣告掛了,返回提前準(zhǔn)備好的一些靜態(tài)頁面)、緩存(之前暫存的一些緩存數(shù)據(jù))
- 限流降級
當(dāng)我們?nèi)ッ霘⒒蛘邠屬徱恍┫拶徤唐窌r,此時可能會因為訪問量太大而導(dǎo)致系統(tǒng)崩潰,此時開發(fā)者會使用限流來進(jìn)行限制訪問量,當(dāng)達(dá)到限流閥值,后續(xù)請求會被降級;降級后的處理方案可以是:排隊頁面(將用戶導(dǎo)流到排隊頁面等一會重試)、無貨(直接告知用戶沒貨了)、錯誤頁(如活動太火爆了,稍后重試)
服務(wù)降級需考慮的問題
- 核心服務(wù)或非核心服務(wù)。
- 是否支持降級,及其降級策略。
- 業(yè)務(wù)放通場景,極其策略。
Hystrix組件
Hystrix流程
服務(wù)降級通??梢酝ㄟ^使用該組建完成。
- 在通過第三方客戶端訪問(通常通過網(wǎng)絡(luò))依賴服務(wù)出現(xiàn)高延遲或失敗時,為系統(tǒng)提供保護(hù)和控制。
- 在分布式系統(tǒng)中防止級聯(lián)失敗。
- 快速失?。‵ail-fast)同時能快速恢復(fù)。
- 提供失敗回退(Fallback)和優(yōu)雅的服務(wù)降級機(jī)制。

流程說明:
- 每次調(diào)用創(chuàng)建一個新的HystrixCommand,把依賴調(diào)用封裝在run()方法中.
- 執(zhí)行execute()/queue做同步或異步調(diào)用.
- 判斷熔斷器(circuit-breaker)是否打開,如果打開跳到步驟8,進(jìn)行降級策略,如果關(guān)閉進(jìn)入步驟.
- 判斷線程池/隊列/信號量是否跑滿,如果跑滿進(jìn)入降級步驟8,否則繼續(xù)后續(xù)步驟.
- 調(diào)用HystrixCommand的run方法.運行依賴邏輯
a: 依賴邏輯調(diào)用超時,進(jìn)入步驟8. - 判斷邏輯是否調(diào)用成功
a: 返回成功調(diào)用結(jié)果
b: 調(diào)用出錯,進(jìn)入步驟8. - 計算熔斷器狀態(tài),所有的運行狀態(tài)(成功, 失敗, 拒絕,超時)上報給熔斷器,用于統(tǒng)計從而判斷熔斷器狀態(tài).
- getFallback()降級邏輯.以下四種情況將觸發(fā)getFallback調(diào)用:(1):run()方法拋出非HystrixBadRequestException異常;(2):run()方法調(diào)用超時;(3):熔斷器開啟攔截調(diào)用;(4):線程池/隊列/信號量是否跑滿。
a: 沒有實現(xiàn)getFallback的Command將直接拋出異常
b: fallback降級邏輯調(diào)用成功直接返回
c: 降級邏輯調(diào)用失敗拋出異常 - 返回執(zhí)行成功結(jié)果
Hystrix測試說明

Hystrix特性
1. 請求熔斷: 當(dāng)Hystrix Command請求后端服務(wù)失敗數(shù)量超過一定比例(默認(rèn)50%), 斷路器會切換到開路狀態(tài)(Open). 這時所有請求會直接失敗而不會發(fā)送到后端服務(wù). 斷路器保持在開路狀態(tài)一段時間后(默認(rèn)5秒), 自動切換到半開路狀態(tài)(HALF-OPEN).
這時會判斷下一次請求的返回情況, 如果請求成功, 斷路器切回閉路狀態(tài)(CLOSED), 否則重新切換到開路狀態(tài)(OPEN). Hystrix的斷路器就像我們家庭電路中的保險絲, 一旦后端服務(wù)不可用, 斷路器會直接切斷請求鏈, 避免發(fā)送大量無效請求影響系統(tǒng)吞吐量, 并且斷路器有自我檢測并恢復(fù)的能力.
2. 服務(wù)降級:Fallback相當(dāng)于是降級操作. 對于查詢操作, 我們可以實現(xiàn)一個fallback方法, 當(dāng)請求后端服務(wù)出現(xiàn)異常的時候, 可以使用fallback方法返回的值. fallback方法的返回值一般是設(shè)置的默認(rèn)值或者來自緩存.告知后面的請求服務(wù)不可用了,不要再來了。
3. 依賴隔離(采用艙壁模式,Docker就是艙壁模式的一種):在Hystrix中, 主要通過線程池來實現(xiàn)資源隔離. 通常在使用的時候我們會根據(jù)調(diào)用的遠(yuǎn)程服務(wù)劃分出多個線程池.比如說,一個服務(wù)調(diào)用兩外兩個服務(wù),你如果調(diào)用兩個服務(wù)都用一個線程池,那么如果一個服務(wù)卡在哪里,資源沒被釋放
后面的請求又來了,導(dǎo)致后面的請求都卡在哪里等待,導(dǎo)致你依賴的A服務(wù)把你卡在哪里,耗盡了資源,也導(dǎo)致了你另外一個B服務(wù)也不可用了。這時如果依賴隔離,某一個服務(wù)調(diào)用A B兩個服務(wù),如果這時我有100個線程可用,我給A服務(wù)分配50個,給B服務(wù)分配50個,這樣就算A服務(wù)掛了,我的B服務(wù)依然可以用。
4. 請求緩存:比如一個請求過來請求我userId=1的數(shù)據(jù),你后面的請求也過來請求同樣的數(shù)據(jù),這時我不會繼續(xù)走原來的那條請求鏈路了,而是把第一次請求緩存過了,把第一次的請求結(jié)果返回給后面的請求。
5. 請求合并:我依賴于某一個服務(wù),我要調(diào)用N次,比如說查數(shù)據(jù)庫的時候,我發(fā)了N條請求發(fā)了N條SQL然后拿到一堆結(jié)果,這時候我們可以把多個請求合并成一個請求,發(fā)送一個查詢多條數(shù)據(jù)的SQL的請求,這樣我們只需查詢一次數(shù)據(jù)庫,提升了效率。
Hystrix如何解決依賴隔離
Hystrix使用命令模式HystrixCommand(Command)包裝依賴調(diào)用邏輯,每個命令在單獨線程中/信號授權(quán)下執(zhí)行。
可配置依賴調(diào)用超時時間,超時時間一般設(shè)為比99.5%平均時間略高即可.當(dāng)調(diào)用超時時,直接返回或執(zhí)行fallback邏輯。
為每個依賴提供一個小的線程池(或信號),如果線程池已滿調(diào)用將被立即拒絕,默認(rèn)不采用排隊.加速失敗判定時間。
依賴調(diào)用結(jié)果分:成功,失?。⊕伋霎惓#瑫r,線程拒絕,短路。 請求失敗(異常,拒絕,超時,短路)時執(zhí)行fallback(降級)邏輯。
提供熔斷器組件,可以自動運行或手動調(diào)用,停止當(dāng)前依賴一段時間(10秒),熔斷器默認(rèn)錯誤率閾值為50%,超過將自動運行。
提供近實時依賴的統(tǒng)計和監(jiān)控
服務(wù)熔斷
服務(wù)熔斷也被稱為服務(wù)過載保護(hù)。
如下圖所示:

其實可以認(rèn)為:服務(wù)熔斷是服務(wù)降級的措施。
服務(wù)熔斷與服務(wù)降級比較
- 服務(wù)熔斷對服務(wù)提供了proxy,防止服務(wù)不可能時,出現(xiàn)串聯(lián)故障(cascading failure),導(dǎo)致雪崩效應(yīng)。
- 服務(wù)熔斷一般是某個服務(wù)(下游服務(wù))故障引起,而服務(wù)降級一般是從整體負(fù)荷考慮。
- 共性:
- 目的 -> 都是從可用性、可靠性出發(fā),提高系統(tǒng)的容錯能力。
- 最終表現(xiàn)->使某一些應(yīng)用不可達(dá)或不可用,來保證整體系統(tǒng)穩(wěn)定。
- 粒度 -> 一般都是服務(wù)級別,但也有細(xì)粒度的層面:如做到數(shù)據(jù)持久層、只許查詢不許增刪改等。
- 自治 -> 對其自治性要求很高。都要求具有較高的自動處理機(jī)制。
- 區(qū)別:
- 觸發(fā)原因 -> 服務(wù)熔斷通常是下級服務(wù)故障引起;服務(wù)降級通常為整體系統(tǒng)而考慮。
- 管理目標(biāo) -> 熔斷是每個微服務(wù)都需要的,是一個框架級的處理;而服務(wù)降級一般是關(guān)注業(yè)務(wù),對業(yè)務(wù)進(jìn)行考慮,抓住業(yè)務(wù)的層級,從而決定在哪一層上進(jìn)行處理:比如在IO層,業(yè)務(wù)邏輯層,還是在外圍進(jìn)行處理。
- 實現(xiàn)方式 -> 代碼實現(xiàn)中的差異。
服務(wù)熔斷中需考慮的設(shè)計:
源自博主張善友的觀點:
- 異常處理:調(diào)用受熔斷器保護(hù)的服務(wù)的時候,我們必須要處理當(dāng)服務(wù)不可用時的異常情況。這些異常處理通常需要視具體的業(yè)務(wù)情況而定。比如,如果應(yīng)用程序只是暫時的功能降級,可能需要切換到其它的可替換的服務(wù)上來執(zhí)行相同的任務(wù)或者獲取相同的數(shù)據(jù),或者給用戶報告錯誤然后提示他們稍后重試。
- 異常的類型:請求失敗的原因可能有很多種。一些原因可能會比其它原因更嚴(yán)重。比如,請求會失敗可能是由于遠(yuǎn)程的服務(wù)崩潰,這可能需要花費數(shù)分鐘來恢復(fù);也可能是由于服務(wù)器暫時負(fù)載過重導(dǎo)致超時。熔斷器應(yīng)該能夠檢查錯誤的類型,從而根據(jù)具體的錯誤情況來調(diào)整策略。比如,可能需要很多次超時異常才可以斷定需要切換到斷開狀態(tài),而只需要幾次錯誤提示就可以判斷服務(wù)不可用而快速切換到斷開狀態(tài)。
- 日志:熔斷器應(yīng)該能夠記錄所有失敗的請求,以及一些可能會嘗試成功的請求,使得的管理員能夠監(jiān)控使用熔斷器保護(hù)的服務(wù)的執(zhí)行情況。
- 測試服務(wù)是否可用:在斷開狀態(tài)下,熔斷器可以采用定期的ping遠(yuǎn)程的服務(wù)或者資源,來判斷是否服務(wù)是否恢復(fù),而不是使用計時器來自動切換到半斷開狀態(tài)。這種ping操作可以模擬之前那些失敗的請求,或者可以使用通過調(diào)用遠(yuǎn)程服務(wù)提供的檢查服務(wù)是否可用的方法來判斷。
- 手動重置:在系統(tǒng)中對于失敗操作的恢復(fù)時間是很難確定的,提供一個手動重置功能能夠使得管理員可以手動的強(qiáng)制將熔斷器切換到閉合狀態(tài)。同樣的,如果受熔斷器保護(hù)的服務(wù)暫時不可用的話,管理員能夠強(qiáng)制的將熔斷器設(shè)置為斷開狀態(tài)。
- 并發(fā)問題:相同的熔斷器有可能被大量并發(fā)請求同時訪問。熔斷器的實現(xiàn)不應(yīng)該阻塞并發(fā)的請求或者增加每次請求調(diào)用的負(fù)擔(dān)。
- 資源的差異性:使用單個熔斷器時,一個資源如果??有分布在多個地方就需要小心。比如,一個數(shù)據(jù)可能存儲在多個磁盤分區(qū)上(shard),某個分區(qū)可以正常訪問,而另一個可能存在暫時性的問題。在這種情況下,不同的錯誤響應(yīng)如果混為一談,那么應(yīng)用程序訪問的這些存在問題的分區(qū)的失敗的可能性就會高,而那些被認(rèn)為是正常的分區(qū),就有可能被阻塞。
- 加快熔斷器的熔斷操作:有時候,服務(wù)返回的錯誤信息足夠讓熔斷器立即執(zhí)行熔斷操作并且保持一段時間。比如,如果從一個分布式資源返回的響應(yīng)提示負(fù)載超重,那么應(yīng)該等待幾分鐘后再重試。(HTTP協(xié)議定義了”HTTP 503 Service Unavailable”來表示請求的服務(wù)當(dāng)前不可用,他可以包含其他信息比如,超時等)
- 重復(fù)失敗請求:當(dāng)熔斷器在斷開狀態(tài)的時候,熔斷器可以記錄每一次請求的細(xì)節(jié),而不是僅僅返回失敗信息,這樣當(dāng)遠(yuǎn)程服務(wù)恢復(fù)的時候,可以將這些失敗的請求再重新請求一次。
服務(wù)熔斷恢復(fù)需注意的問題
如果服務(wù)是冪等性的,則恢復(fù)重試不會有問題;而如果服務(wù)是非冪等性的,則重試會導(dǎo)致數(shù)據(jù)出現(xiàn)問題。
本文轉(zhuǎn)載自高并發(fā)之服務(wù)降級與熔斷