微服務(wù)架構(gòu)使得可以通過明確定義的服務(wù)邊界來隔離故障禁荸。但是像在每個分布式系統(tǒng)中一樣嘹锁,發(fā)生網(wǎng)絡(luò)葫录、硬件、應用級別的錯誤都是很常見的领猾。由于服務(wù)依賴關(guān)系米同,任何組件可能暫時無法提供服務(wù)。為了盡量減少部分中斷的影響瘤运,我們需要構(gòu)建容錯服務(wù)窍霞,來優(yōu)雅地處理這些中斷的響應結(jié)果。
本文介紹了基于RisingStack 的 Node.js 咨詢和開發(fā)經(jīng)驗構(gòu)建和操作高可用性微服務(wù)系統(tǒng)的最常見技術(shù)和架構(gòu)模式拯坟。
如果你不熟悉本文中的模式但金,那并不一定意味著你做錯了。建立可靠的系統(tǒng)總是會帶來額外的成本郁季。
微服務(wù)架構(gòu)的風險
微服務(wù)架構(gòu)將應用程序邏輯移動到服務(wù)冷溃,并使用網(wǎng)絡(luò)層在它們之間進行通信钱磅。這種通過網(wǎng)絡(luò)間通信代替單應用程序內(nèi)調(diào)用的做法,會帶來額外的延遲似枕,以及需要協(xié)調(diào)多個物理和邏輯組件的系統(tǒng)復雜度盖淡。分布式系統(tǒng)的復雜性增加也將導致更高的網(wǎng)絡(luò)故障率。
微服務(wù)體系結(jié)構(gòu)的最大優(yōu)勢之一是凿歼,團隊可以獨立設(shè)計褪迟,開發(fā)和部署他們的服務(wù)。他們對服務(wù)的生命周期擁有完全的所有權(quán)答憔。這也意味著團隊無法控制他們依賴的服務(wù)味赃,因為它更有可能由不同的團隊管理。使用微服務(wù)架構(gòu)虐拓,我們需要記住心俗,提供者服務(wù)可能會臨時不可用,由于其他人員發(fā)行的錯誤版本蓉驹,配置以及其他更改等城榛。
優(yōu)雅的服務(wù)降級
微服務(wù)架構(gòu)的最大優(yōu)點之一是您可以隔離故障,并在當組件單獨故障時态兴,進行優(yōu)雅的服務(wù)降級狠持。例如,在中斷期間诗茎,照片共享應用程序中的客戶可能無法上傳新圖片工坊,但仍可以瀏覽,編輯和共享其現(xiàn)有照片敢订。
微服務(wù)容錯隔離
在大多數(shù)情況下王污,由于分布式系統(tǒng)中的應用程序相互依賴,因此很難實現(xiàn)這種優(yōu)雅的服務(wù)降級楚午,您需要應用幾種故障轉(zhuǎn)移的邏輯(其中一些將在本文后面介紹)昭齐,以為暫時的故障和中斷做準備。
服務(wù)間彼此依賴矾柜,再沒有故障轉(zhuǎn)移邏輯下阱驾,服務(wù)全部失敗。
變更管理
Google的網(wǎng)站可靠性小組發(fā)現(xiàn)怪蔑,大約70%的中斷是由現(xiàn)有系統(tǒng)的變化引起的里覆。當您更改服務(wù)中的某些內(nèi)容時,您將部署新版本的代碼或更改某些配置 - 這總有可能會造成故障缆瓣,或者引入新的bug喧枷。
在微服務(wù)架構(gòu)中,服務(wù)依賴于彼此。這就是為什么你應該盡量減少故障并限制它的負面影響隧甚。要處理變更中的問題车荔,您可以實施變更管理策略和自動回滾機制。
例如戚扳,當您部署新代碼或更改某些配置時忧便,您應該先小范圍的進行部分的替換,以漸進式的方式替換服務(wù)的全部實例帽借。在這期間珠增,需要監(jiān)視它們,如果您發(fā)現(xiàn)它們對您的關(guān)鍵指標有負面影響宜雀,應立即進行服務(wù)回滾切平,這稱為“金絲雀部署”。
變更管理 - 回滾部署
另一個解決方案可能是您運行兩個生產(chǎn)環(huán)境辐董。您始終只能部署其中一個,并且在驗證新版本是否符合預期之后才禀综,將負載均衡器指向新的简烘。這稱為藍綠或紅黑部署。
回滾代碼不是壞事定枷。你不應該在生產(chǎn)中遺留錯誤的代碼孤澎,然后考慮出了什么問題。如果必要欠窒,越早回滾你的代碼越好覆旭。
健康檢查與負載均衡
實例由于出現(xiàn)故障、部署或自動縮放的情況岖妄,會進行持續(xù)啟動型将、重新啟動或停止操作。它可能導致它們暫時或永久不可用荐虐。為避免問題七兜,您的負載均衡器應該從路由中跳過不健康的實例,因為它們當前無法為客戶或子系統(tǒng)提供服務(wù)福扬。
應用實例健康狀況可以通過外部觀察來確定腕铸。您可以通過重復調(diào)用GET /health
端點或通過自我報告來實現(xiàn)。現(xiàn)在主流的服務(wù)發(fā)現(xiàn)解決方案铛碑,會持續(xù)從實例中收集健康信息狠裹,并配置負載均衡器,將流量僅路由到健康的組件上汽烦。
自我修復
自我修復可以幫助應用程序從錯誤中恢復過來涛菠。當應用程序可以采取必要步驟從故障狀態(tài)恢復時,我們就可以說它是可以實現(xiàn)自我修復的。在大多數(shù)情況下碗暗,它由外部系統(tǒng)實現(xiàn)颈将,該系統(tǒng)會監(jiān)視實例運行狀況,并在較長時間內(nèi)處于故障狀態(tài)時重新啟動它們言疗。自我修復在大多數(shù)情況下是非常有用的晴圾。但是在某些情況下,持續(xù)地重啟應用程序可能會導致麻煩噪奄。當您的應用程序由于超負荷或其數(shù)據(jù)庫連接超時而無法給出健康的運行狀況時死姚,這種情況下的頻繁的重啟就可能就不太合適了。
對于這種特殊的場景(如丟失的數(shù)據(jù)庫連接)勤篮,要實現(xiàn)滿足它的高級自我修復的解決方案可能很棘手都毒。在這種情況下,您需要為應用程序添加額外的邏輯來處理邊緣情況碰缔,并讓外部系統(tǒng)知道實例不需要立即重新啟動账劲。
故障轉(zhuǎn)移緩存
由于網(wǎng)絡(luò)問題和我們系統(tǒng)的變化,服務(wù)經(jīng)常會失敗金抡。然而瀑焦,由于自我修復和負載均衡的保障,它們中的大多數(shù)中斷是臨時的梗肝,我們應該找到一個解決方案榛瓮,使我們的服務(wù)在這些故障時服務(wù)仍就可以工作。這就是故障轉(zhuǎn)移緩存的作用巫击,它可以幫助并為我們的應用程序在服務(wù)故障時提供必要的數(shù)據(jù)禀晓。
故障轉(zhuǎn)移緩存通常使用兩個不同的到期日期; 較短的時間告訴您在正常情況下緩存可以使用的過期時間,而較長的時間可以在服務(wù)故障時緩存依舊可用的過期時間坝锰。
故障轉(zhuǎn)移緩存
請務(wù)必提及粹懒,只有當服務(wù)使用過時的數(shù)據(jù)比沒有數(shù)據(jù)更好時,才能使用故障轉(zhuǎn)移緩存什黑。
要設(shè)置緩存和故障轉(zhuǎn)移緩存崎淳,可以在 HTTP 中使用標準響應頭。
例如愕把,使用 max-age
屬性可以指定資源被視為有效的最大時間拣凹。使用 stale-if-error
屬性,您可以明確在出現(xiàn)故障的情況下恨豁,依舊可以從緩存中獲取資源的最大時間嚣镜。
現(xiàn)代的 CDN 和負載均衡器都提供各種緩存和故障轉(zhuǎn)移行為,但您也可以為擁有標準可靠性解決方案的公司創(chuàng)建一個共享庫橘蜜。
重試邏輯
在某些情況下菊匿,我們無法緩存數(shù)據(jù)付呕,或者我們想對其進行更改,但是我們的操作最終都失敗了跌捆。對于此徽职,我們可以重試我們的操作,因為我們可以預期資源將在一段時間后恢復佩厚,或者我們的負載均衡器將請求發(fā)送到了健康的實例上姆钉。
您應該小心地為您的應用程序和客戶端添加重試邏輯,因為大量的重試可能會使事情更糟抄瓦,甚至阻止應用程序恢復潮瓶,如當服務(wù)超載時,大量的重試只能使狀況更糟钙姊。
在分布式系統(tǒng)中毯辅,微服務(wù)系統(tǒng)重試可以觸發(fā)多個其他請求或重試,并啟動級聯(lián)效應煞额。為了最小化重試的影響思恐,您應該限制它們的數(shù)量,并使用指數(shù)退避算法來持續(xù)增加重試之間的延遲立镶,直到達到最大限制壁袄。
當客戶端(瀏覽器,其他微服務(wù)等)發(fā)起重試媚媒,并且客戶端不知道在處理請求之前或之后操作失敗時,您應該為你的應用程序做好冪等處理的準備涩僻。例如缭召,當您重試購買操作時,您不應該再次向客戶收取費用逆日。為每個交易使用唯一的冪等值鍵可以幫助處理重試嵌巷。
限流器和負載降級
流量限制是在一段時間內(nèi)定義特定客戶或應用程序可以接收或處理多少個請求的技術(shù)。例如室抽,通過流量限制,您可以過濾掉造成流量峰值的客戶和服務(wù),或者您可以確保您的應用程序在自動縮放無法滿足時炊琉,依然不會超載杰赛。
您還可以阻止較低優(yōu)先級的流量,為關(guān)鍵事務(wù)提供足夠的資源兽泄。
限流器可以阻止流量峰值產(chǎn)生
有一個不同類型的限流器漓概,叫做并發(fā)請求限制器。當您有重要的端點病梢,您不應該被調(diào)用超過指定的次數(shù)胃珍,而您仍然想要能提供服務(wù)時,這將是有用的。
負載降級的一系列使用觅彰,可以確狈悦铮總是有足夠的資源來提供關(guān)鍵交易。它為高優(yōu)先級請求保留一些資源填抬,不允許低優(yōu)先級的事務(wù)使用它們烛芬。負載降級開關(guān)是根據(jù)系統(tǒng)的整體狀態(tài)做出決定,而不是基于單個用戶的請求量大小痴奏。負載降級有助于您的系統(tǒng)恢復蛀骇,因為當你有一個偶發(fā)事件時(可能是一個熱點事件),您仍能保持核心功能的正常工作读拆。
要了解有關(guān)限流器和負載降級的更多信息擅憔,我建議查看這篇Stripe的文章。
快速失敗原則與獨立性
在微服務(wù)架構(gòu)中檐晕,我們想要做到讓我們的服務(wù)具備快速失敗與相互獨立的能力暑诸。為了在服務(wù)級別上進行故障隔離,我們可以使用艙壁模式辟灰。你可以在本文的后面閱讀更多有關(guān)艙壁的內(nèi)容个榕。
我們也希望我們的組件能夠快速失敗,因為我們不希望對于有故障的服務(wù)芥喇,在請求超時后才斷開西采。沒有什么比掛起的請求和無響應的 UI 更令人失望。這不僅浪費資源继控,而且還會影響用戶體驗械馆。我們的服務(wù)在調(diào)用鏈中是相互調(diào)用的,所以在這些延遲累加之前武通,我們應該特別注意防止掛起操作霹崎。
你想到的第一個想法是對每個服務(wù)調(diào)用都設(shè)置明確的超時等級。這種方法的問題是冶忱,您不能知道真正合理的超時值是多少尾菇,因為網(wǎng)絡(luò)故障和其他問題發(fā)生的某些情況只會影響一兩次操作。在這種情況下囚枪,如果只有其中一些超時派诬,您可能不想拒絕這些請求。
我們可以說眶拉,在微服務(wù)種通過使用超時來達到快速失敗的效果是一種反模式的千埃,你應該避免使用它。取而代之忆植,您可以應用斷路器模式放可,依據(jù)操作的成功與失敗統(tǒng)計數(shù)據(jù)決定谒臼。
艙壁模式
工業(yè)中使用艙壁將船舶劃分為幾個部分,以便在船體破壞的情況下耀里,可以將船舶各個部件密封起來蜈缤。
艙壁的概念在軟件開發(fā)中可以被應用在隔離資源上。
通過應用艙壁模式冯挎,我們可以保護有限的資源不被耗盡底哥。例如,對于一個有連接數(shù)限制的數(shù)據(jù)庫實例來說房官,如果我們有兩種連接它的操作趾徽,我們采用可以采用兩個連接池的方式進行連接,來代替僅采用一個共享連接池的方式翰守。由于這種客戶端與資源進行了隔離孵奶,超時或過度使用池的操作頁不會使其他操作失敗。
泰坦尼克號沉沒的主要原因之一是其艙壁設(shè)計失敗蜡峰,水可以通過上面的甲板倒在艙壁的頂部了袁,導致整個船體淹沒。
泰坦尼克號艙壁設(shè)計(無效的設(shè)計)
斷路器
為了限制操作的持續(xù)時間湿颅,我們可以使用超時载绿。超時可以防止掛起操作并保持系統(tǒng)響應。然而油航,在微服務(wù)中使用靜態(tài)崭庸、精細的超時是一種反模式,因為我們處于高度動態(tài)的環(huán)境中谊囚,幾乎不可能提出在每種情況下都能正常工作的正確的時間限制冀自。
替代這種靜態(tài)超時的手段是,我們可以使用斷路器來處理錯誤秒啦。斷路器以現(xiàn)實世界的電子元件命名,因為它們的作用是相同的搀玖。您可以保護資源余境,并幫助他們使用斷路器進行恢復。它們在分布式系統(tǒng)中非常有用灌诅,因為在分布式系統(tǒng)中芳来,重復故障可能導致雪球效應并使整個系統(tǒng)癱瘓。
當特定類型的錯誤在短時間內(nèi)多次發(fā)生時猜拾,斷路器會被斷開即舌。開路的斷路器可以防止進一步的請求 - 就像我們平時所說的電路跳閘一樣。斷路器通常在一定時間后關(guān)閉挎袜,在這期間可以為底層服務(wù)提供足夠的空間來恢復顽聂。
請記住肥惭,并不是所有的錯誤都應該觸發(fā)斷路器。例如紊搪,您可能希望跳過客戶端問題蜜葱,例如具有4xx響應代碼的請求,但不包括5xx服務(wù)器端故障耀石。一些斷路器也具有半開狀態(tài)牵囤。在這種狀態(tài)下,服務(wù)發(fā)送第一個請求以檢查系統(tǒng)可用性滞伟,同時讓其他請求失敗揭鳞。如果這個第一個請求成功,它將使斷路器恢復到關(guān)閉狀態(tài)并使流量流動梆奈。否則野崇,它保持打開。
斷路器
測試故障
您應該不斷測試您系統(tǒng)的常見問題鉴裹,以確保您的服務(wù)可以抵抗各種故障舞骆。您應經(jīng)常測試故障,讓您的團隊具備故障處理的能力径荔。
對于測試督禽,您可以使用外部服務(wù)來標識實例組,并隨機終止此組中的一個實例总处。這樣狈惫,您可以準備單個實例故障,但您甚至可以關(guān)閉整個區(qū)域來模擬云提供商的故障鹦马。
最流行的測試解決方案之一是 Netflix 的 ChaosMonkey 彈性工具胧谈。
結(jié)尾
實施和運行可靠的服務(wù)并不容易。您需要付出很多努力荸频,同時公司也要有相應的財力投入菱肖。
可靠性有很多層次和方面,因此找到最適合您團隊的解決方案很重要旭从。您應該使可靠性成為您的業(yè)務(wù)決策流程中的一個因素稳强,并為其分配足夠的預算和時間。
主要收獲
動態(tài)環(huán)境和分布式系統(tǒng)(如微服務(wù))會導致更高的故障機率和悦;
服務(wù)應該做到故障隔離退疫,到達優(yōu)雅降級,來提升用戶體驗鸽素;
70%的中斷是由變化引起的褒繁,代碼回滾不是一件壞事;
做到服務(wù)快速失敗與獨立性馍忽。團隊是無法控制他們所依賴的服務(wù)情況棒坏;
緩存燕差、艙壁、斷路器和限流器等架構(gòu)模式與技術(shù)有助于構(gòu)建可靠的微服務(wù)架構(gòu)俊抵。