(8)彈力設(shè)計(jì)篇之“熔斷設(shè)計(jì)”

1、熔斷設(shè)計(jì):正常、故障和、故障后檢測(cè)(故障是否已被修復(fù)的場(chǎng)景)

2、介紹了 Netflix 的 Hystrix 對(duì)熔斷的實(shí)現(xiàn)

3、熔斷設(shè)計(jì)的幾個(gè)重點(diǎn)

熔斷機(jī)制借鑒于我們電閘上的 " 保險(xiǎn)絲 ",當(dāng)電壓有問(wèn)題時(shí)(比如短路),自動(dòng)跳閘,此時(shí)電路就會(huì)斷開(kāi),我們的電器就會(huì)受到保護(hù)。

重試機(jī)制,如果錯(cuò)誤太多,或是在短時(shí)間內(nèi)得不到修復(fù),重試也沒(méi)有意義了,此時(shí)應(yīng)該開(kāi)啟我們的熔斷操作,保護(hù)后端不會(huì)過(guò)載。

熔斷設(shè)計(jì)

防止不斷地嘗試可能會(huì)失敗的操作,使應(yīng)用程序繼續(xù)執(zhí)行而不用等待修正錯(cuò)誤,或者浪費(fèi) CPU 時(shí)間去等待長(zhǎng)時(shí)間的超時(shí)產(chǎn)生。熔斷器模式也可以使應(yīng)用程序能夠診斷錯(cuò)誤是否已經(jīng)修正。如果已經(jīng)修正,再次嘗試調(diào)用操作

熔斷器模式就像是那些容易導(dǎo)致錯(cuò)誤的操作的一種代理。這種代理能夠記錄最近調(diào)用發(fā)生錯(cuò)誤的次數(shù),然后決定允許操作繼續(xù),或者立即返回錯(cuò)誤。

(本圖來(lái)自 Martin Fowler 的 Circuit Breaker)

熔斷器可以使用狀態(tài)機(jī)來(lái)實(shí)現(xiàn),內(nèi)部模擬以下幾種狀態(tài)。

閉合(Closed)狀態(tài):失敗次數(shù)加 1。給定時(shí)間內(nèi)超過(guò)允許失敗的閾值,切換到斷開(kāi) (Open) 狀態(tài)。此時(shí)開(kāi)啟了一個(gè)超時(shí)時(shí)鐘,當(dāng)該時(shí)鐘超過(guò)了該時(shí)間,切換到半斷開(kāi)(Half-Open)狀態(tài)。該超時(shí)時(shí)間的設(shè)定是給了系統(tǒng)一次機(jī)會(huì)來(lái)修正導(dǎo)致調(diào)用失敗的錯(cuò)誤,以回到正常工作的狀態(tài)。在 Closed 狀態(tài)下,錯(cuò)誤計(jì)數(shù)器是基于時(shí)間的。在特定的時(shí)間間隔內(nèi)會(huì)自動(dòng)重置。這能夠防止由于某次的偶然錯(cuò)誤導(dǎo)致熔斷器進(jìn)入斷開(kāi)狀態(tài)。也可以基于連續(xù)失敗的次數(shù)。

斷開(kāi) (Open) 狀態(tài):在該狀態(tài)下,對(duì)應(yīng)用程序的請(qǐng)求會(huì)立即返回錯(cuò)誤響應(yīng),而不調(diào)用后端的服務(wù)。這樣也許比較粗暴,有些時(shí)候,我們可以 cache 住上次成功請(qǐng)求,直接返回緩存(當(dāng)然,這個(gè)緩存放在本地內(nèi)存就好了),如果沒(méi)有緩存再返回錯(cuò)誤(緩存的機(jī)制最好用在全站一樣的數(shù)據(jù),而不是用在不同的用戶間不同的數(shù)據(jù),因?yàn)楹笳咝枰彺娴臄?shù)據(jù)有可能會(huì)很多)。

半開(kāi)(Half-Open)狀態(tài)允許應(yīng)用程序一定數(shù)量的請(qǐng)求去調(diào)用服務(wù)。如果這些請(qǐng)求對(duì)服務(wù)的調(diào)用成功,那么可以認(rèn)為之前導(dǎo)致調(diào)用失敗的錯(cuò)誤已經(jīng)修正,此時(shí)熔斷器切換到閉合狀態(tài) (并且將錯(cuò)誤計(jì)數(shù)器重置)。

如果這一定數(shù)量的請(qǐng)求有調(diào)用失敗的情況,則認(rèn)為導(dǎo)致之前調(diào)用失敗的問(wèn)題仍然存在,熔斷器切回到斷開(kāi)狀態(tài),然后重置計(jì)時(shí)器來(lái)給系統(tǒng)一定的時(shí)間來(lái)修正錯(cuò)誤。半斷開(kāi)狀態(tài)能夠有效防止正在恢復(fù)中的服務(wù)被突然而來(lái)的大量請(qǐng)求再次拖垮。

實(shí)現(xiàn)熔斷器模式使得系統(tǒng)更加穩(wěn)定和有彈性,在系統(tǒng)從錯(cuò)誤中恢復(fù)的時(shí)候提供穩(wěn)定性,并且減少了錯(cuò)誤對(duì)系統(tǒng)性能的影響。它通過(guò)快速地拒絕那些試圖有可能會(huì)導(dǎo)致錯(cuò)誤的服務(wù)調(diào)用,而不會(huì)去等待操作超時(shí)或者永遠(yuǎn)不返回結(jié)果來(lái)提高系統(tǒng)的響應(yīng)時(shí)間。

如果熔斷器設(shè)計(jì)模式在每次狀態(tài)切換的時(shí)候會(huì)發(fā)出一個(gè)事件,這種信息可以用來(lái)監(jiān)控服務(wù)的運(yùn)行狀態(tài),能夠通知管理員在熔斷器切換到斷開(kāi)狀態(tài)時(shí)進(jìn)行處理。

二、Netflix 的開(kāi)源項(xiàng)目Hystrix中的熔斷的實(shí)現(xiàn)邏輯(其出處在這里)。

從這個(gè)流程圖中,可以看到:

有請(qǐng)求來(lái)了,首先 allowRequest() 函數(shù)判斷是否在熔斷中,如果不是則放行,如果是的話,還要看有沒(méi)有到達(dá)一個(gè)熔斷時(shí)間片,如果熔斷時(shí)間片到了,也放行,否則直接返回出錯(cuò)。

每次調(diào)用都有兩個(gè)函數(shù) markSuccess(duration) 和 markFailure(duration) 來(lái)統(tǒng)計(jì)一下在一定的 duration 內(nèi)有多少調(diào)用是成功還是失敗的。

判斷是否熔斷的條件 isOpen(),是計(jì)算一下 failure/(success+failure) 當(dāng)前的錯(cuò)誤率,如果高于一個(gè)閾值,那么打開(kāi)熔斷,否則關(guān)閉。

Hystrix 會(huì)在內(nèi)存中維護(hù)一個(gè)數(shù)組,其中記錄著每一個(gè)周期的請(qǐng)求結(jié)果的統(tǒng)計(jì)。超過(guò)時(shí)長(zhǎng)長(zhǎng)度的元素會(huì)被刪除掉。

三、熔斷設(shè)計(jì)的重點(diǎn)

在實(shí)現(xiàn)熔斷器模式的時(shí)候,以下這些因素需可能需要考慮。

錯(cuò)誤的類型。根據(jù)不同的錯(cuò)誤情況來(lái)調(diào)整相應(yīng)的策略。重試一樣,需要對(duì)返回的錯(cuò)誤進(jìn)行識(shí)別。一些錯(cuò)誤先走重試的策略(比如限流,或是超時(shí)),重試幾次后再打開(kāi)熔斷。一些錯(cuò)誤是遠(yuǎn)程服務(wù)掛掉,恢復(fù)時(shí)間比較長(zhǎng);這種錯(cuò)誤不必走重試,可以直接打開(kāi)熔斷策略。

日志監(jiān)控。熔斷器應(yīng)該能夠記錄所有失敗的請(qǐng)求,以及一些可能會(huì)嘗試成功的請(qǐng)求,使得管理員能夠監(jiān)控使用熔斷器保護(hù)的服務(wù)的執(zhí)行情況。

測(cè)試服務(wù)是否可用。在斷開(kāi)狀態(tài)下,熔斷器可以采用定期地 ping 一下遠(yuǎn)程的服務(wù)的健康檢查接口,來(lái)判斷服務(wù)是否恢復(fù),而不是使用計(jì)時(shí)器來(lái)自動(dòng)切換到半開(kāi)狀態(tài)。這樣做的一個(gè)好處是,在服務(wù)恢復(fù)的情況下,不需要真實(shí)的用戶流量就可以把狀態(tài)從半開(kāi)狀態(tài)切回關(guān)閉狀態(tài)。否則在半開(kāi)狀態(tài)下,即便服務(wù)已恢復(fù)了,也需要用戶真實(shí)的請(qǐng)求來(lái)恢復(fù),這會(huì)影響用戶的真實(shí)請(qǐng)求。

手動(dòng)重置。在系統(tǒng)中對(duì)于失敗操作的恢復(fù)時(shí)間是很難確定的,提供一個(gè)手動(dòng)重置功能能夠使得管理員可以手動(dòng)地強(qiáng)制將熔斷器切換到閉合狀態(tài)。同樣的,如果受熔斷器保護(hù)的服務(wù)暫時(shí)不可用的話,管理員能夠強(qiáng)制將熔斷器設(shè)置為斷開(kāi)狀態(tài)。

并發(fā)問(wèn)題。不應(yīng)該阻塞并發(fā)的請(qǐng)求或者增加每次請(qǐng)求調(diào)用的負(fù)擔(dān)。尤其是其中的對(duì)調(diào)用結(jié)果的統(tǒng)計(jì),一般來(lái)說(shuō)會(huì)成為一個(gè)共享的數(shù)據(jù)結(jié)構(gòu),這個(gè)會(huì)導(dǎo)致有鎖的情況。在這種情況下,最好使用一些無(wú)鎖的數(shù)據(jù)結(jié)構(gòu),或是 atomic 的原子操作。這樣會(huì)帶來(lái)更好的性能。

資源分區(qū)。熔斷器只對(duì)有問(wèn)題的分區(qū)進(jìn)行熔斷,而不是整體。比如,數(shù)據(jù)庫(kù)的分庫(kù)分表,某個(gè)分區(qū)可能出現(xiàn)問(wèn)題,而其它分區(qū)還可用。單一的熔斷器會(huì)把所有的分區(qū)訪問(wèn)給混為一談,從而,一旦開(kāi)始熔斷,那么所有的分區(qū)都會(huì)受到熔斷影響?;蚴浅霈F(xiàn)一會(huì)兒熔斷一會(huì)兒又好,來(lái)來(lái)回回的情況。

重試錯(cuò)誤的請(qǐng)求。有時(shí)候,錯(cuò)誤和請(qǐng)求的數(shù)據(jù)和參數(shù)有關(guān)系,所以,記錄下出錯(cuò)的請(qǐng)求,在半開(kāi)狀態(tài)下重試能夠準(zhǔn)確地知道服務(wù)是否真的恢復(fù)。當(dāng)然,這需要被調(diào)用端支持冪等調(diào)用,否則會(huì)出現(xiàn)一個(gè)操作被執(zhí)行多次的副作用。

也歡迎你分享一下你實(shí)現(xiàn)過(guò)的熔斷使用了怎樣的算法?實(shí)現(xiàn)的過(guò)程中遇到過(guò)什么坑?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,534評(píng)論 19 139
  • 專業(yè)考題類型管理運(yùn)行工作負(fù)責(zé)人一般作業(yè)考題內(nèi)容選項(xiàng)A選項(xiàng)B選項(xiàng)C選項(xiàng)D選項(xiàng)E選項(xiàng)F正確答案 變電單選GYSZ本規(guī)程...
    小白兔去釣魚閱讀 10,490評(píng)論 0 13
  • ORA-00001: 違反唯一約束條件 (.) 錯(cuò)誤說(shuō)明:當(dāng)在唯一索引所對(duì)應(yīng)的列上鍵入重復(fù)值時(shí),會(huì)觸發(fā)此異常。 O...
    我想起個(gè)好名字閱讀 5,944評(píng)論 0 9
  • Java繼承關(guān)系初始化順序 父類的靜態(tài)變量-->父類的靜態(tài)代碼塊-->子類的靜態(tài)變量-->子類的靜態(tài)代碼快-->父...
    第六象限閱讀 2,248評(píng)論 0 9
  • 無(wú)戒365·婚姻育兒·日記專題聯(lián)合征文 “要為重活的現(xiàn)在高興,不為死去的過(guò)去憂傷”。小艾帶著微醉的眼神,堅(jiān)定有力地...
    蘭汐蘭閱讀 469評(píng)論 3 7

友情鏈接更多精彩內(nèi)容