貴陽網(wǎng)站建設(shè)是什么金泉網(wǎng)做網(wǎng)站多少錢
文章目錄
- 前言
- 斷路器模式
- 艙壁隔離模式
- 重試模式
- 總結(jié)
- 附
前言
容錯設(shè)計(jì)模式,指的是“要實(shí)現(xiàn)某種容錯策略,我們該如何去做”。微服務(wù)中常見的設(shè)計(jì)模式包括斷路器模式、艙壁隔離模式和超時重試模式等,另外還有流量控制模式等。
斷路器模式
斷路器模式是微服務(wù)架構(gòu)中最基礎(chǔ)的容錯設(shè)計(jì)模式。斷路器的思路也簡單,就是通過代理(斷路器對象)來一對一(一個遠(yuǎn)程服務(wù)對應(yīng)一個斷路器對象)地接管服務(wù)調(diào)用者的遠(yuǎn)程請求。斷路器會持續(xù)監(jiān)控并統(tǒng)計(jì)服務(wù)返回的成功、失敗、超時、拒絕等各種結(jié)果,當(dāng)出現(xiàn)故障(失敗、超時、拒絕)的次數(shù)達(dá)到斷路器的閾值時,它的狀態(tài)就自動變?yōu)椤癘PEN”。之后這個斷路器代理的遠(yuǎn)程訪問都將直接返回調(diào)用失敗,而不會發(fā)出真正的遠(yuǎn)程服務(wù)請求。
通過斷路器對遠(yuǎn)程服務(wù)進(jìn)行熔斷,就可以避免因?yàn)槌掷m(xù)的失敗或拒絕而消耗資源,因?yàn)槌掷m(xù)的超時而堆積請求,最終可以避免雪崩效應(yīng)的出現(xiàn)。由此可見,斷路器本質(zhì)上是快速失敗策略的一種實(shí)現(xiàn)方式。
從調(diào)用序列來看,斷路器就是一種有限狀態(tài)機(jī),斷路器模式就是根據(jù)自身的狀態(tài)變化,自動調(diào)整代理請求策略的過程。
斷路器一般可以設(shè)置為 CLOSED、OPEN 和 HALF OPEN 三種狀態(tài):
- CLOSED:表示斷路器關(guān)閉(請求可正常響應(yīng)),此時的遠(yuǎn)程請求會真正發(fā)送給服務(wù)提供者。斷路器剛剛建立時默認(rèn)處于這種狀態(tài),此后將持續(xù)監(jiān)視遠(yuǎn)程請求的數(shù)量和執(zhí)行結(jié)果,決定是否要進(jìn)入 OPEN 狀態(tài)。
- OPEN:表示斷路器開啟,此時不會進(jìn)行遠(yuǎn)程請求,直接給服務(wù)調(diào)用者返回調(diào)用失敗的信息,以實(shí)現(xiàn)快速失敗策略。
- HALF OPEN:是一種中間狀態(tài)。斷路器必須帶有自動的故障恢復(fù)能力,當(dāng)進(jìn)入 OPEN 狀態(tài)一段時間以后,將“自動”(一般是由下一次請求而不是計(jì)時器觸發(fā)的,所以這里的自動是帶引號的)切換到 HALF OPEN 狀態(tài)。在中間狀態(tài)下,會放行一次遠(yuǎn)程調(diào)用,然后根據(jù)這次調(diào)用的結(jié)果成功與否,轉(zhuǎn)換為 CLOSED 或者 OPEN 狀態(tài),來實(shí)現(xiàn)斷路器的彈性恢復(fù)。
這里值得討論的是OPEN 和 CLOSED 狀態(tài)的轉(zhuǎn)換條件,不同框架都有各自的偏好設(shè)置,如Netflix Hystrix中的默認(rèn)設(shè)置:
當(dāng)一次調(diào)用失敗后,如果還同時滿足下面兩個條件,斷路器的狀態(tài)就變?yōu)?OPEN: - 一段時間(比如 10 秒以內(nèi))內(nèi),請求數(shù)量達(dá)到一定閾值(比如 20 個請求)。(響應(yīng)頻率)
- 一段時間(比如 10 秒以內(nèi))內(nèi),請求的故障率(發(fā)生失敗、超時、拒絕的統(tǒng)計(jì)比例)到達(dá)一定閾值(比如 50%)。(可用性)
另外,服務(wù)熔斷和服務(wù)降級之間的聯(lián)系與差別:
斷路器做的事情是自動進(jìn)行服務(wù)熔斷,屬于一種快速失敗的容錯策略的實(shí)現(xiàn)方法。在快速失敗策略明確反饋了故障信息給上游服務(wù)以后,上游服務(wù)必須能夠主動處理調(diào)用失敗的后果,而不是坐視故障擴(kuò)散。這里的“處理”,指的就是一種典型的服務(wù)降級邏輯,降級邏輯可以是,但不應(yīng)該只是,把異常信息拋到用戶界面去,而應(yīng)該盡力想辦法通過其他路徑解決問題,比如把原本要處理的業(yè)務(wù)記錄下來,留待以后重新處理是最低限度的通用降級邏輯。
服務(wù)降級不一定是在出現(xiàn)錯誤后才被動執(zhí)行的,我們在很多場景中談?wù)摰慕导壐赡苁侵?#xff0c;需要主動迫使服務(wù)進(jìn)入降級邏輯的情況。比如,出于應(yīng)對可預(yù)見的峰值流量,或者是系統(tǒng)檢修等原因,要關(guān)閉系統(tǒng)部分功能或關(guān)閉部分旁路服務(wù),這時候就有可能會主動迫使這些服務(wù)降級。此時服務(wù)降級就是出于流量控制的范疇。
艙壁隔離模式
艙壁隔離模式,是常用的實(shí)現(xiàn)服務(wù)隔離的設(shè)計(jì)模式。艙壁這個詞來自造船業(yè),意思是在每個區(qū)域設(shè)計(jì)獨(dú)立的水密艙室。
分布式系統(tǒng)中,服務(wù)隔離,就是避免某一個遠(yuǎn)程服務(wù)的局部失敗影響到全局,而設(shè)置的一種止損方案。這種思想,對應(yīng)的就是容錯策略中的失敗靜默策略。
在調(diào)用外部服務(wù)可能面臨的三大類故障:失敗、拒絕和超時中,“超時”引起的故障,尤其容易給調(diào)用者帶來全局性的風(fēng)險(xiǎn)。這是因?yàn)?#xff0c;目前主流的網(wǎng)絡(luò)訪問大多是基于 TPR 并發(fā)模型(Thread per Request)來實(shí)現(xiàn)的,只要請求一直不結(jié)束(無論是以成功結(jié)束還是以失敗結(jié)束),就要一直占用著某個線程不能釋放。而線程是典型的整個系統(tǒng)的全局性資源,尤其是在 Java 這類將線程映射為操作系統(tǒng)內(nèi)核線程來實(shí)現(xiàn)的語言環(huán)境中。
要解決這類問題,本質(zhì)上就是要控制單個服務(wù)的最大連接數(shù)。一種可行的解決辦法是為每個服務(wù)單獨(dú)設(shè)立線程池,這些線程池默認(rèn)不預(yù)置活動線程,只用來控制單個服務(wù)的最大連接數(shù)。使用局部的線程池來控制服務(wù)的最大連接數(shù),有很多好處,比如當(dāng)服務(wù)出問題時能夠隔離影響,當(dāng)服務(wù)恢復(fù)后,還可以通過清理掉局部線程池,瞬間恢復(fù)該服務(wù)的調(diào)用。而如果是 Tomcat 的全局線程池被占滿,再恢復(fù)就會非常麻煩。
但是,局部線程池有一個顯著的弱點(diǎn),那就是它額外增加了 CPU 的開銷,每個獨(dú)立的線程池都要進(jìn)行排隊(duì)、調(diào)度和下文切換工作。
為應(yīng)對這種情況,還有一種更輕量的控制服務(wù)最大連接數(shù)的辦法,那就是信號量機(jī)制(Semaphore)。如果不考慮清理線程池、客戶端主動中斷線程這些額外的功能,僅僅是為了控制單個服務(wù)并發(fā)調(diào)用的最大次數(shù)的話,我們可以只為每個遠(yuǎn)程服務(wù)維護(hù)一個線程安全的計(jì)數(shù)器,并不需要建立局部線程池。具體做法是,當(dāng)服務(wù)開始調(diào)用時計(jì)數(shù)器加 1,服務(wù)返回結(jié)果后計(jì)數(shù)器減 1;一旦計(jì)數(shù)器的值超過設(shè)置的閾值就立即開始限流,在回落到閾值范圍之前都不再允許請求了。因?yàn)椴恍枰袚?dān)線程的排隊(duì)、調(diào)度和切換工作,所以單純維護(hù)一個作為計(jì)數(shù)器的信號量的性能損耗,相對于局部線程池來說,幾乎可以忽略不計(jì)。
一般來說,我們會選擇將服務(wù)層面的隔離實(shí)現(xiàn)在服務(wù)調(diào)用端或者邊車代理上,將系統(tǒng)層面的隔離實(shí)現(xiàn)在 DNS 或者網(wǎng)關(guān)處。
重試模式
故障轉(zhuǎn)移和故障恢復(fù)這兩種策略都需要對服務(wù)進(jìn)行重復(fù)調(diào)用,差別就在于這些重復(fù)調(diào)用有可能是同步的,也可能是后臺異步進(jìn)行;有可能會重復(fù)調(diào)用同一個服務(wù),也可能會調(diào)用服務(wù)的其他副本。但是,無論具體是通過怎樣的方式調(diào)用、調(diào)用的服務(wù)實(shí)例是否相同,都可以歸結(jié)為重試設(shè)計(jì)模式的應(yīng)用范疇。
重試模式適合解決系統(tǒng)中的瞬時故障,簡單地說就是有可能自己恢復(fù)(Resilient,稱為自愈,也叫做回彈性)的臨時性失靈,比如網(wǎng)絡(luò)抖動、服務(wù)的臨時過載(比如返回了 503 Bad Gateway 錯誤)這些都屬于瞬時故障。
重試模式實(shí)現(xiàn)起來并不難,在實(shí)踐中,我們判斷是否應(yīng)該且是否能夠?qū)σ粋€服務(wù)進(jìn)行重試時,要看是否同時滿足下面 4 個條件:
- 第一,僅在主路邏輯的關(guān)鍵服務(wù)上進(jìn)行同步的重試。(如果不是關(guān)鍵服務(wù),一般不要把重試作為首選容錯方案,尤其不應(yīng)該進(jìn)行同步重試。)
- 第二,僅對由瞬時故障導(dǎo)致的失敗進(jìn)行重試。盡管要做到精確判定一個故障是否屬于可自愈的瞬時故障并不容易,但我們至少可以從 HTTP 的狀態(tài)碼上獲得一些初步的結(jié)論。比如,當(dāng)發(fā)出的請求收到了 401 Unauthorized 響應(yīng)時,說明服務(wù)本身是可用的,只是你沒有權(quán)限調(diào)用,這時候再去重試就沒有什么意義。
- 第三,僅對具備冪等性的服務(wù)進(jìn)行重試。比如,RESTful 服務(wù)中的 POST 請求是非冪等的;GET、HEAD、OPTIONS、TRACE 請求應(yīng)該被設(shè)計(jì)成冪等的,因?yàn)樗鼈儾粫淖冑Y源狀態(tài);PUT 請求一般也是冪等的,因?yàn)?n 個 PUT 請求會覆蓋相同的資源 n-1 次;DELETE 請求也可看作是冪等的,同一個資源首次刪除會得到 200 OK 響應(yīng),此后應(yīng)該得到 204 No Content 響應(yīng)。
- 第四,重試必須有明確的終止條件,常用的終止條件有超時終止和次數(shù)終止兩種:
超時終止。其實(shí),超時機(jī)制并不限于重試策略,所有涉及遠(yuǎn)程調(diào)用的服務(wù)都應(yīng)該有超時機(jī)制來避免無限期的等待。
次數(shù)終止。重試必須要有一定限度,不能無限制地做下去,通常是重試 2~5 次。因?yàn)橹卦嚥粌H會給調(diào)用者帶來負(fù)擔(dān),對服務(wù)提供者來說也同樣是負(fù)擔(dān),所以我們要避免把重試次數(shù)設(shè)得太大。
另外,由于重試模式可以在網(wǎng)絡(luò)鏈路的多個環(huán)節(jié)中去實(shí)現(xiàn),比如在客戶端發(fā)起調(diào)用時自動重試、網(wǎng)關(guān)中自動重試、負(fù)載均衡器中自動重試等等,如果配置不當(dāng),可能會帶來巨大的負(fù)擔(dān)。
總結(jié)
熔斷、隔離、重試、降級、超時等概念,都是建立具有韌性的微服務(wù)系統(tǒng)的必須的保障措施。那么就目前來說,這些措施的正確運(yùn)作,主要還是依靠開發(fā)人員對服務(wù)邏輯的了解,以及根據(jù)運(yùn)維人員的經(jīng)驗(yàn)去靜態(tài)地調(diào)整、配置參數(shù)和閾值。
但是,面對能夠自動擴(kuò)縮(Auto Scale)的大型分布式系統(tǒng),靜態(tài)的配置越來越難以起到良好的效果。這就要求,系統(tǒng)不僅要有能力可以自動地根據(jù)服務(wù)負(fù)載來調(diào)整服務(wù)器的數(shù)量規(guī)模,同時還要有能力根據(jù)服務(wù)調(diào)用的統(tǒng)計(jì)結(jié)果,或者啟發(fā)式搜索的結(jié)果來自動變更容錯策略和參數(shù)。當(dāng)然,目前這方面的研究,還處于各大廠商在內(nèi)部分頭摸索的初級階段,不過這正是服務(wù)治理未來的重要發(fā)展方向之一。
附
此文章為3月Day02學(xué)習(xí)筆記,內(nèi)容來源于極客時間《周志明的軟件架構(gòu)課》