面試官:高并發(fā)場景下,微服務(wù)熔斷策略該怎么設(shè)計(jì)?
今天我們來繼續(xù)聊聊高可用系統(tǒng)的另一個核心話題——熔斷。
假設(shè)有這樣一個場景,有個核心的訂單服務(wù),依賴于一個時常不穩(wěn)定的第三方支付服務(wù)。當(dāng)支付服務(wù)出現(xiàn)故障時,我們?nèi)绾未_保整個訂單系統(tǒng)不被拖垮,甚至引發(fā)整個電商平臺的雪崩?
這就不得不用到我們今天要講的熔斷機(jī)制了。是每個后端工程師都必須掌握的核心技能。我們不僅要懂它是什么,更要能說清楚,并且在實(shí)戰(zhàn)中知道如何利用它來保護(hù)你的系統(tǒng)。
1. 什么是熔斷?
熔斷,簡單理解就是一種斷流機(jī)制。簡單來說,在微服務(wù)架構(gòu)中,當(dāng)某個下游服務(wù)因自身故障或過載而響應(yīng)異常時,熔斷器會介入,暫時“切斷”對該服務(wù)的進(jìn)一步請求,直到它恢復(fù)正常。

從上圖就可以看出,熔斷是一種主動拒絕機(jī)制。假設(shè)現(xiàn)在某個服務(wù)因?yàn)閿?shù)據(jù)庫慢查詢導(dǎo)致CPU負(fù)載飆升至99%。此時請求量又在激增。有了熔斷策略之后,系統(tǒng)就會主動拒絕這些請求。
2. 為什么需要熔斷?
一句話總結(jié),熔斷的主要作用就是避免服務(wù)雪崩。在深入介紹熔斷機(jī)制之前,我們首先來看下一般的服務(wù)雪崩場景是怎么形成的
2.1 雪崩是怎么形成的?
雪崩其實(shí)是分布式系統(tǒng)中一種連鎖故障的現(xiàn)象,在一個分布式系統(tǒng)中,局部故障是不可避免的。如果不能將局部故障控制好,導(dǎo)致局部故障被正反饋循環(huán),就會出現(xiàn)連鎖故障,最終導(dǎo)致整體系統(tǒng)崩潰。一般來說,出現(xiàn)雪崩會經(jīng)歷以下三個階段
局部服務(wù)過載
一切的開端,通常是系統(tǒng)中某個服務(wù)(我們稱之為服務(wù)C)的處理能力出現(xiàn)瓶頸。導(dǎo)致過載的原因多種多樣:可能是程序自身的Bug導(dǎo)致性能劣化;可能是流量洪峰超出了服務(wù)容量;也可能是部署的機(jī)器實(shí)例宕機(jī),導(dǎo)致整體處理能力下降。
當(dāng)服務(wù)的QPS超過其處理極限時,它會開始表現(xiàn)出響應(yīng)變慢、內(nèi)部資源(如內(nèi)存、線程)消耗加劇等癥狀。這就像高速公路開始堵車,通行效率急劇下降。
資源耗盡與服務(wù)不可用
隨著過載情況的加劇,積壓在服務(wù)C內(nèi)部的請求會越來越多。這些積壓的請求會持續(xù)消耗著服務(wù)器的內(nèi)存、CPU、線程池甚至是文件句柄等寶貴資源。當(dāng)其中任何一項(xiàng)資源被耗盡時,服務(wù)C就會開始大量報(bào)錯,甚至頻繁崩潰,最終對外呈現(xiàn)為“不可用”狀態(tài)。
當(dāng)服務(wù)C的某個實(shí)例崩潰后,上游的負(fù)載均衡機(jī)制會把原本發(fā)往這個實(shí)例的流量,自動轉(zhuǎn)發(fā)給其它正常的的實(shí)例,這樣的話,就加速了整個服務(wù)C集群的全面癱瘓。
故障沿調(diào)用鏈路逆向蔓延
到這一步,就輪到服務(wù)C的上游調(diào)用者(服務(wù)B)遭殃了。由于服務(wù)C無法及時響應(yīng),服務(wù)B的請求線程會大量阻塞在等待響應(yīng)上,這同樣會快速耗盡服務(wù)B自身的線程和資源。很快,服務(wù)B也變得過載、不可用。
這個過程會像多米諾骨牌一樣,沿著調(diào)用鏈路一路逆向傳播(服務(wù)B -> 服務(wù)A),最終導(dǎo)致整個調(diào)用鏈上的所有服務(wù)全部癱瘓,系統(tǒng)發(fā)生“雪崩”。
2
2.2 熔斷保護(hù)
有了上面對雪崩理解之后,我們很容易想到為了避免這種情況,就需要在某個服務(wù)出現(xiàn)問題之后,我們主動掐斷它就可以了,就類似于電路中的保險(xiǎn)絲。
在軟件架構(gòu)中,熔斷機(jī)制的設(shè)計(jì)實(shí)現(xiàn)也類似。它在服務(wù)的調(diào)用方內(nèi)部,設(shè)置了一個監(jiān)控哨兵。當(dāng)它監(jiān)測到對某個下游服務(wù)的調(diào)用,在一段時間內(nèi)失敗率持續(xù)過高時,就會主動“斷開”連接,后續(xù)的請求將不再真正發(fā)出,而是直接在調(diào)用方內(nèi)部快速失敗,立即返回錯誤。
3
3. 熔斷器的設(shè)計(jì)核心
熔斷器的作用很好理解,就是一個保險(xiǎn)開關(guān),達(dá)到閾值就關(guān)閉,服務(wù)性能恢復(fù)之后再次打開就可以了。我們在設(shè)計(jì)的時候需要抓住以下兩個重點(diǎn):
- 如何判斷服務(wù)出問題了?
- 如何判斷服務(wù)恢復(fù)正常了?
3.1 服務(wù)健康狀態(tài)判定
判斷一個服務(wù)是否健康,這與我們在設(shè)計(jì)負(fù)載均衡時評估節(jié)點(diǎn)健康度的思路其實(shí)是一樣的。本質(zhì)上,我們需要基于業(yè)務(wù)場景選擇合適的指標(biāo)來量化服務(wù)的健康程度。最常用的指標(biāo)包括響應(yīng)時間和錯誤率。
無論選擇哪個指標(biāo),我們都需要考慮兩個核心要素:閾值的設(shè)定,以及是否需要持續(xù)一段時間才觸發(fā)熔斷。
以響應(yīng)時間為例,這個閾值應(yīng)該如何設(shè)定?這完全取決于業(yè)務(wù)需求。如果你的業(yè)務(wù)對用戶承諾響應(yīng)時間在800毫秒以內(nèi),那么閾值可以設(shè)定在800毫秒,或者稍微放寬一些,比如1秒,給予一定的容錯空間。
如果產(chǎn)品經(jīng)理沒有給出明確的響應(yīng)時間要求,你可以通過線上監(jiān)控?cái)?shù)據(jù)來確定。一個基本原則是,熔斷閾值應(yīng)顯著高于正常的響應(yīng)時間。比如,通過觀察,你發(fā)現(xiàn)某個服務(wù)99.9%的請求都能在500毫秒內(nèi)完成,那么你可以將熔斷閾值設(shè)定為800毫秒。
4
一個設(shè)計(jì)良好的熔斷器,也不會因?yàn)橐淮闻既坏某瑫r就立刻熔斷。所以我們一般會要求這種異常狀態(tài)持續(xù)一段時間,才進(jìn)行熔斷。這樣做主要有兩個目的:一是過濾掉偶發(fā)的網(wǎng)絡(luò)波動或GC停頓導(dǎo)致的瞬時延遲;二是為了防止系統(tǒng)在“正?!迸c“熔斷”之間高頻切換,也就是我們常說的“抖動”問題。
5
這個異常事件到底持續(xù)多長時間我們再進(jìn)行熔斷呢,很大程度上依賴于經(jīng)驗(yàn)。如果設(shè)置得太短,可能會因?yàn)橐恍┧矔r抖動就頻繁熔斷恢復(fù),影響系統(tǒng)穩(wěn)定性;如果設(shè)置得太長,則可能導(dǎo)致問題服務(wù)遲遲得不到隔離,風(fēng)險(xiǎn)敞口過大。通??梢愿鶕?jù)經(jīng)驗(yàn)設(shè)定一個值,例如“在1分鐘的滑動窗口內(nèi),有超過30秒的時間響應(yīng)時間持續(xù)高于閾值”,才觸發(fā)熔斷。
3.2 如何優(yōu)雅地恢復(fù)服務(wù)
第二個核心問題是,服務(wù)在進(jìn)入熔斷狀態(tài)后,如何優(yōu)雅地恢復(fù)。一個服務(wù)因?yàn)轫憫?yīng)過長而熔斷了,它拒絕了所有新流量。在幾分鐘后,積壓的任務(wù)處理完畢,服務(wù)本身可能已經(jīng)恢復(fù)了正常狀態(tài)。此時,它需要退出熔斷狀態(tài),重新開始服務(wù)。
6
但是,許多主流的微服務(wù)框架在服務(wù)恢復(fù)這個環(huán)節(jié)做得相對簡單。一種比較常見的做法是:觸發(fā)熔斷后,等待一個固定的時間窗口(例如60秒),然后直接將服務(wù)狀態(tài)置為“正?!?,讓100%的流量重新涌入。
這種一刀切的恢復(fù)策略,就極易引起服務(wù)抖動。就比如說,假設(shè)因?yàn)榱髁窟^高已經(jīng)熔斷了一次,那么在等待60秒后,外部的請求洪峰可能并未消退。此時冒然全面恢復(fù)流量,服務(wù)立刻又面臨被新一輪的流量高峰打垮,再次觸發(fā)熔斷。如此循環(huán)往復(fù),就會造成服務(wù)不斷抖動。
7
要解決這個抖動問題,關(guān)鍵在于恢復(fù)時必須控制流量的進(jìn)入,不能搞硬著陸。正確的做法是逐步放開流量,實(shí)現(xiàn)軟著陸。比如,在恢復(fù)期結(jié)束后,不立即恢復(fù)100%的流量,而是先放開10%的流量進(jìn)行試探。如果這10%的請求都能被正常處理,響應(yīng)時間也恢復(fù)到了正常水平,那么再逐步將流量提升到20%、50%,最終到100%。這個過程,我們稱之為“半開(Half-Open)狀態(tài)的探測。
8
這種漸進(jìn)式的恢復(fù)方式雖然在一定程度上可以避免熔斷恢復(fù)過程中的抖動問題,但是這種在服務(wù)端控制流量的方式依然有其局限性,因?yàn)榉?wù)端仍然接收了100%的請求,只是在內(nèi)部丟棄了大部分。一個更優(yōu)雅的思路是,讓客戶端也來主導(dǎo)這個流量恢復(fù)的過程。這就是接下來要介紹的面試亮點(diǎn)方案。
4. 面試實(shí)戰(zhàn)指南
握了上述基礎(chǔ)知識后,我們還需要將理論與實(shí)際工作相結(jié)合,才能在面試中游刃有余。在面試前,需要先梳理清楚自己項(xiàng)目中是如何應(yīng)用熔斷的:
- 系統(tǒng)是通過哪些指標(biāo)來判斷某個微服務(wù)異常的?例如錯誤率、超時比例、平均響應(yīng)時間等。
- 當(dāng)服務(wù)恢復(fù)正常時,又是依據(jù)什么標(biāo)準(zhǔn)來判定的?
- 服務(wù)恢復(fù)之后,是否有額外措施來防止頻繁切換帶來的“抖動”問題?
- 熔斷觸發(fā)后,流量是如何處理的?比如直接失敗返回,還是通過緩存/降級服務(wù)兜底來保證用戶體驗(yàn)?
在面試中,展示熔斷知識的最佳策略,是將其作為你構(gòu)建高可用微服務(wù)體系的一部分。例如,在介紹項(xiàng)目時,你可以這樣開場:
“為了確保我們這套核心交易系統(tǒng)的穩(wěn)定性,我主導(dǎo)設(shè)計(jì)了一套立體的可用性保障方案,其中就包括了限流、降級和熔斷等關(guān)鍵措施?!?/span>
如果面試官問及服務(wù)治理、系統(tǒng)可用性,或者某個服務(wù)崩潰了怎么辦,熔斷都是一個絕佳的切入點(diǎn)。
4.1 基礎(chǔ)應(yīng)對方案
當(dāng)面試官問到“你項(xiàng)目中用過熔斷嗎”或者“如何保障微服務(wù)可用性”時,你可以結(jié)合我們前面討論的知識點(diǎn),清晰地闡述你的實(shí)踐。關(guān)鍵詞是持續(xù)超過閾值。
“在我們的核心服務(wù)中,為了保障整體可用性,我引入了熔斷機(jī)制。針對不同服務(wù)的重要性,我設(shè)計(jì)了差異化的熔斷策略。
比如,對于一個核心的商品查詢服務(wù),我們主要基于響應(yīng)時間來熔斷。根據(jù)線上監(jiān)控?cái)?shù)據(jù),我們設(shè)定了當(dāng)99%的響應(yīng)時間在30秒的滑動窗口內(nèi)持續(xù)超過1.5秒時,就觸發(fā)熔斷。觸發(fā)后,新的請求會被快速失敗,而服務(wù)內(nèi)部正在處理的請求會繼續(xù)完成。這樣既保護(hù)了下游服務(wù),也給了自身恢復(fù)的時間?!?/span>
此時,面試官可能會追問:
- 這個閾值是怎么來的? 你可以回答是基于業(yè)務(wù)SLO要求和線上長期監(jiān)控?cái)?shù)據(jù)綜合評估得出的。
- 為什么是持續(xù)30秒? 你可以坦誠地回答這是基于經(jīng)驗(yàn)的權(quán)衡,并解釋時間過長或過短的利弊。
- 如何判斷服務(wù)是否恢復(fù)? 你可以回答,在熔斷觸發(fā)60秒后,系統(tǒng)會進(jìn)入“半開”狀態(tài),先放行少量請求進(jìn)行探測,如果成功率達(dá)標(biāo),再逐步放開全部流量,以避免抖動。
4.2 基于依賴的熔斷
這里,我提供一個更具場景化的創(chuàng)新方案,關(guān)鍵詞是關(guān)鍵依賴故障。
“除了常規(guī)的性能指標(biāo),我還設(shè)計(jì)過一個基于關(guān)鍵依賴的熔斷方案。我們有一個訂單服務(wù),它強(qiáng)依賴于庫存服務(wù)。如果庫存服務(wù)不可用,那么所有創(chuàng)建訂單的請求最終都會失敗。
因此,我們的熔斷策略是:一旦檢測到對庫存服務(wù)的調(diào)用連續(xù)出現(xiàn)5次以上的網(wǎng)絡(luò)超時或500錯誤,就立即對訂單創(chuàng)建接口進(jìn)行熔斷。如果不這么做,大量的失敗請求會打到數(shù)據(jù)庫,最終可能拖垮訂單庫。
熔斷后,我們會啟動一個獨(dú)立的健康檢查任務(wù),每5秒鐘調(diào)用一次庫存服務(wù)的健康檢查接口。一旦庫存服務(wù)恢復(fù),我們就退出熔斷狀態(tài),恢復(fù)服務(wù)?!?/span>
9
這個方案巧妙地將業(yè)務(wù)與技術(shù)結(jié)合,體現(xiàn)了你對系統(tǒng)架構(gòu)的深入理解。同時,這個方案還留下了可以引導(dǎo)面試官深入探討的鉤子:
- 下游接口穩(wěn)定性保護(hù):你可以順勢將話題引向第三方接口或者是下游接口不穩(wěn)定的一些常見解決方案上,比如做超時控制,重試策略等等。
最后,當(dāng)你提到退出熔斷狀態(tài)時,如果面試官經(jīng)驗(yàn)豐富,他很可能會問:“你是如何放開流量的?一次性全部放開嗎?”這時,你就可以自然地引出抖動問題,并為接下來的亮點(diǎn)方案做好鋪墊:
“直接放開全部流量風(fēng)險(xiǎn)很高,容易產(chǎn)生抖動。我們采用的是逐步放開流量的方案。不過,這種在服務(wù)端控制的方式依然有優(yōu)化空間,更理想的做法是與客戶端的負(fù)載均衡策略相結(jié)合。”
4.3 熔斷與負(fù)載均衡的聯(lián)動
其實(shí)應(yīng)對面試的話,前面的回答基本上已經(jīng)可以讓你通過面試了,但如果你想給面試官留下深刻印象,展現(xiàn)你在服務(wù)治理上的深度思考,可以祭出下面這個融合了負(fù)載均衡與熔斷聯(lián)動的亮點(diǎn)方案。
我們之前討論過,即使是在服務(wù)端逐步放開流量,服務(wù)端依然接收了全部請求,只是在內(nèi)部進(jìn)行了丟棄。這本身就是一種資源浪費(fèi)。那么,為什么不從源頭——也就是客戶端——來控制流量呢?
10
結(jié)合我在負(fù)載均衡中提到的根據(jù)調(diào)用結(jié)果動態(tài)調(diào)整策略的思路,我們可以設(shè)計(jì)一個客戶端感知的熔斷恢復(fù)流程:
整體流程如下:
- 服務(wù)端節(jié)點(diǎn)A因過載觸發(fā)熔斷,在返回給客戶端的響應(yīng)中,攜帶一個特定的錯誤碼或頭部信息,明確告知“我已熔斷”。
- 客戶端(或其代理,如Service Mesh)收到這個熔斷信號后,會立即將節(jié)點(diǎn)A從其本地的可用服務(wù)列表中臨時摘除。后續(xù)的新請求將不會再路由到節(jié)點(diǎn)A。
- 客戶端等待一個預(yù)設(shè)的時間窗口(比如30秒)后,將節(jié)點(diǎn)A置為“半開”狀態(tài),并試探性地發(fā)送一小部分請求(比如單個請求或1%的流量)到節(jié)點(diǎn)A。
- 如果試探請求成功,客戶端會逐步加大流向節(jié)點(diǎn)A的流量,最終將其完全恢復(fù)到可用列表中。
- 如果試探請求再次失?。ɡ缬质盏搅巳蹟嘈盘枺?,客戶端會再次將節(jié)點(diǎn)A從可用列表中摘除,并可能進(jìn)入一個更長的熔斷冷卻周期(指數(shù)退避策略)。
- 這個過程循環(huán)進(jìn)行,直到服務(wù)端節(jié)點(diǎn)A完全恢復(fù)穩(wěn)定。
11
12
13
在面試中,你可以這樣闡述,關(guān)鍵詞是客戶端負(fù)載均衡:
“我們最終采用的方案,是讓客戶端的負(fù)載均衡器與服務(wù)端的熔斷狀態(tài)進(jìn)行聯(lián)動,實(shí)現(xiàn)智能的流量控制。
整體思路是,當(dāng)服務(wù)端節(jié)點(diǎn)觸發(fā)熔斷時,它會返回一個明確的熔斷信號??蛻舳耸盏皆撔盘柡?,會主動將這個節(jié)點(diǎn)在其負(fù)載均衡策略中標(biāo)記為不可用,并在一段時間內(nèi)避免向其發(fā)送請求。等待期過后,客戶端會發(fā)起健康探測請求,如果節(jié)點(diǎn)恢復(fù),就逐步恢復(fù)流量;如果依然熔斷,就延長其隔離時間。這種方式將故障隔離和流量恢復(fù)的決策前置到了客戶端,實(shí)現(xiàn)了更快速、更高效的故障轉(zhuǎn)移和恢復(fù)?!?/span>
講到這里,你甚至可以主動提出一個邊緣案例來展示你思維的嚴(yán)謹(jǐn)性:
“當(dāng)然,這個方案也需要一個兜底策略。如果因?yàn)榈讓右蕾嚕ū热缯麄€數(shù)據(jù)庫集群故障)導(dǎo)致某個服務(wù)的所有節(jié)點(diǎn)都觸發(fā)了熔斷,客戶端會發(fā)現(xiàn)無可用節(jié)點(diǎn)。這種情況超出了熔斷和負(fù)載均衡能解決的范疇,需要依賴監(jiān)控告警系統(tǒng)通知人工介入處理?!?/span>
5. 小結(jié)
總而言之,熔斷機(jī)制作為構(gòu)建高可用微服務(wù)架構(gòu)的基石,其設(shè)計(jì)的精髓遠(yuǎn)不止于簡單的開關(guān)。從基礎(chǔ)的基于閾值觸發(fā),到考慮半開狀態(tài)的試探恢復(fù),再到最終將熔斷狀態(tài)與客戶端負(fù)載均衡策略深度聯(lián)動,熔斷策略一步步優(yōu)化,系統(tǒng)的性能也在一步步提升。這種聯(lián)動方案不僅從源頭上避免了恢復(fù)期的服務(wù)“抖動”問題,更將故障隔離的責(zé)任前置,實(shí)現(xiàn)了真正快速、優(yōu)雅的故障轉(zhuǎn)移。深刻理解并實(shí)踐這種從全局視角出發(fā)的設(shè)計(jì)思想,才能真正設(shè)計(jì)出一個切實(shí)可行的熔斷方案

































