如何解決微服務架構中的雪崩問題?

ADVERTISEMENT

作者|魏春雷

編輯|Gary

記得在三年前公司因為業務發展需要,就曾經將單體應用遷移到分散式框架上來。當時就遇到了這樣一個問題:系統僅有一個控製單元,它會呼叫多個運算單元,如果某個運算單元(作為服務提供者)不可用,將導致控製單元(作為服務呼叫者)被阻塞,最終導致控製單元崩潰,進而導致整個系統都面臨著癱瘓的風險。

那個時候還不知道這其實就是服務的雪崩效應,雪崩效應好比就是蝴蝶效應,說的都是一個小因素的變化,卻往往有著無比強大的力量,以至於最後改變整體結構、產生意想不到的結果。雪崩效應也是我們目前研發的產品直面的一道坎,下面我們來看有哪些場景會引發雪崩,又如何避免?對於無法避免的雪崩效應,我們又有哪些應對措施?

1. 星火燎原

1.1農民眼中的微服務

近年來,微服務就象一把燎原的大火,竄了出來並在整個技術社群燒了起來,微服務架構被認為是IT軟體服務化架構演進的目標。為什麼微服務這麼火,微服務能給企業帶來什麼價值?

1.1.1 以種植農作物的思想來理解微服務

我們以耕種為例來看如何充分利用一塊田地的:

先在地裡種植了一排排玉米;

後來發現玉米腳下空地可以利用,再間隔一段距離再種上豆角,豆角長大後順著玉米杆往上爬,最後緊緊地纏繞在玉米杆上;

再後來發現每排玉米之間的空隙地還可以再種些土豆,土豆蔓藤以後會交織在一起,肆虐在玉米腳下吞食營養物質;

表面看來一塊土地得到了充分利用,實際上各農作物得不到充分的光照和適宜的營養,如此一來加大了後期除草、鬆土、施肥、灌溉及收割的成本。

下面的耕植思路是不是更好點呢? 一整塊地根據需要分配為若幹大小土地塊,每塊地之間清晰分界,這樣就有了玉米地、土豆地、豆角地,再想種什麼劃塊地再耕作就可以了。

這樣種植好處很多,比如玉米、豆角和土豆需要的營養物質是不一樣的,可由專業技術人員施肥;玉米,豆角和土豆分離,避免豆角藤爬上玉米,纏繞玉米不能自由生長。土豆又汲取玉米需要的營養物質等等問題。

軟體系統實現與農作物的種植方式其實也很類似,傳統的應用在擴充套件性,可靠性,維護成本上表現都不盡人意。如何充分利用大量系統資源,管理和監控服務生命週期都是頭疼的事情,軟體系統設計迫切需要上述的“土地分割種植法”。微服務架構應運而生:在微服務系統中,各個業務系統間通過對訊息(字元序列)的處理都非常友好的RestAPI進行訊息互動。如此一來,各個業務系統根據Restful架構風格統一成一個有機系統。

1.2 微服務架構下的冰山

泰坦尼克號曾經是世界最大的客輪,在當時被稱為是”永不沉沒“的,但卻在北大西洋撞上冰山而沉沒。我們往往隻看到它浮出水面的絢麗多彩,水下的基礎設施如資源規劃、服務註冊發現、部署升級,灰度釋出等都是需要考慮的因素。

1.2.1 優勢

複雜應用分解:複雜的業務場景可被分解為多個業務系統,每個業務系統的每個服務都有一個用訊息驅動API定義清楚的邊界。

契約驅動:每個業務系統可自由選擇技術,組建技術團隊利用Mock服務提供者和消費者,並行開發,最終實現依賴解耦。

ADVERTISEMENT

自由擴充套件:每個系統可根據業務需要獨自進行擴充套件。

獨立部署:每個業務系統互相獨立,可根據實際需要部署到合適的硬體機器上。

良好隔離:一個業務系統資源洩漏不會導致整個系統宕掉,容錯性較好。

1.2.2 面臨的挑戰

服務管理:敏捷迭代後的微服務可能越來越多,各個業務系統之間的互動也越來越多,如何做高效叢集通訊方案也是問題。

應用管理: 每個業務系統部署後對應著一個程式,程式可以啟停。如果機器掉電或者宕機了,如何做無縫切換都需要強大的部署管理機製。

負載均衡:為應對大流量場景及提供系統可靠性,同一個業務系統也會做分散式部署即一個業務例項部署在多臺機器上。如果某個業務系統掛掉了,如何按需做自動伸縮分散式方案方案也需要考慮。

問題定位:單體應用的日誌集中在一起,出現問題定位很方便,而分散式環境的問題定界定位,日誌分析都較為困難。

雪崩問題:分散式系統都存在這樣一個問題,由於網路的不穩定性,決定了任何一個服務的可用性都不是 100% 的。當網路不穩定的時候,作為服務的提供者,自身可能會被拖死,導致服務呼叫者阻塞,最終可能引發雪崩效應。

Michael T. Nygard 在精彩的《Release It!》一書中總結了很多提高系統可用性的模式,其中非常重要的兩條是:使用超時策略和使用熔斷器機製

超時策略:如果一個服務會被系統中的其它部分頻繁呼叫,一個部分的故障可能會導致級聯故障。例如,呼叫服務的操作可以配置為執行超時,如果服務未能在這個時間內響應,將回覆一個失敗訊息。然而,這種策略可能會導致許多併發請求到同一個操作被阻塞,直到超時期限屆滿。這些阻塞的請求可能會儲存關鍵的系統資源,如記憶體、執行緒、資料庫連線等。因此,這些資源可能會枯竭,導致需要使用相同的資源系統的故障。在這種情況下,它將是優選的操作立即失敗。設定較短的超時可能有助於解決這個問題,但是一個操作請求從發出到收到成功或者失敗的訊息需要的時間是不確定的。

熔斷器模式:熔斷器的模式使用斷路器來檢測故障是否已得到解決,防止請求反覆嘗試執行一個可能會失敗的操作,從而減少等待糾正故障的時間,相對與超時策略更加靈活。

一年一度的雙十一已經悄然來臨,下面將介紹某購物網站一個Tomcat容器在高併發場景下的雪崩效應來探討Hystrix的執行緒池隔離技術和熔斷器機製。

2. 從雪崩看應用防護

2.1 雪崩問題的本質:Servlet Container在高並發下崩潰

我們先來看一個分散式系統中常見的簡化的模型。Web伺服器中的Servlet Container,容器啟動時後臺初始化一個排程執行緒,負責處理Http請求,然後每個請求過來排程執行緒從執行緒池中取出一個工作者執行緒來處理該請求,從而實現併發控製的目的。

Servlet Container是我們的容器,如Tomcat。一個使用者請求有可能依賴其它多個外部服務。考慮到應用容器的執行緒數目基本都是固定的(比如Tomcat的執行緒池預設200),當在高並發的情況下,如果某一外部依賴的服務(第三方系統或者自研系統出現故障)超時阻塞,就有可能使得整個主執行緒池被佔滿,增加記憶體消耗,這是長請求擁塞反模式(一種單次請求時延變長而導致系統效能惡化甚至崩潰的惡化模式)。

更進一步,如果執行緒池被佔滿,那麼整個服務將不可用,就又可能會重複產生上述問題。因此整個系統就像雪崩一樣,最終崩塌掉。

2.2 雪崩效應產生的幾種場景

流量激增:比如異常流量、使用者重試導致系統負載升高;

ADVERTISEMENT

快取重新整理:假設A為client端,B為Server端,假設A系統請求都流向B系統,請求超出了B系統的承載能力,就會造成B系統崩潰;

程式有Bug:程式碼迴圈呼叫的邏輯問題,資源未釋放引起的記憶體洩漏等問題;

硬體故障:比如宕機,機房斷電,光纖被挖斷等。

執行緒同步等待:系統間經常採用同步服務呼叫模式,核心服務和非核心服務共用一個執行緒池和訊息佇列。如果一個核心業務執行緒呼叫非核心執行緒,這個非核心執行緒交由第三方系統完成,當第三方系統本身出現問題,導致核心執行緒阻塞,一直處於等待狀態,而程式間的呼叫是有超時限制的,最終這條執行緒將斷掉,也可能引發雪崩;

2.3 雪崩效應的常見解決方案

針對上述雪崩情景,有很多應對方案,但沒有一個萬能的模式能夠應對所有場景。

針對流量激增,採用自動擴縮容以應對突發流量,或在負載均衡器上安裝限流模組。

針對快取重新整理,參考Cache應用中的服務過載案例研究

針對硬體故障,多機房容災,跨機房路由,異地多活等。

針對同步等待,使用Hystrix做故障隔離,熔斷器機製等可以解決依賴服務不可用的問題。

通過實踐發現,執行緒同步等待是最常見引發的雪崩效應的場景,本文將重點介紹使用Hystrix技術解決服務的雪崩問題。後續再分享流量激增和快取重新整理等應對方案。

3. 隔離和熔斷

Hystrix 是由Netflix釋出,旨在應對複雜分散式系統中的延時和故障容錯,基於Apache License 2.0協議的開源的程式庫,目前託管在GitHub上。

Hystrix採用了命令模式,客戶端需要繼承抽象類HystrixCommand並實現其特定方法。為什麼使用命令模式呢?使用過RPC框架都應該知道一個遠端介面所定義的方法可能不止一個,為了更加細粒度的保護單個方法呼叫,命令模式就非常適合這種場景。

命令模式的本質就是分離方法呼叫和方法實現,在這裡我們通過將介面方法抽象成HystricCommand的子類,從而獲得安全防護能力,並使得的控製力度下沉到方法級別。

Hystrix核心設計理念基於命令模式,命令模式UML如下圖:

可見,Command是在Receiver和Invoker之間新增的中間層,Command實現了對Receiver的封裝。那麼Hystrix的應用場景如何與上圖對應呢?

API既可以是Invoker又可以是Reciever,通過繼承Hystrix核心類HystrixCommand來封裝這些API(例如,遠端介面呼叫,資料庫的CRUD操作可能會產生延時),就可以為API提供彈性保護了。

3.1 資源隔離模式

ADVERTISEMENT

Hystrix之所以能夠防止雪崩的本質原因,是其運用了資源隔離模式,我們可以用蓄水池做比喻來解釋什麼是資源隔離。生活中一個大的蓄水池由一個一個小的池子隔離開來,這樣如果某一個水池的水被汙染,也不會波及到其它蓄水池,如果只有一個蓄水池,水池被汙染,整池水都不可用了。軟體資源隔離如出一轍,如果採用資源隔離模式,將對遠端服務的呼叫隔離到一個單獨的執行緒池後,若服務提供者不可用,那麼受到影響的隻會是這個獨立的執行緒池。

(1)執行緒池隔離模式:使用一個執行緒池來儲存當前的請求,執行緒池對請求作處理,設定任務返回處理超時時間,堆積的請求堆積入執行緒池佇列。這種方式需要為每個依賴的服務申請執行緒池,有一定的資源消耗,好處是可以應對突發流量(流量洪峰來臨時,處理不完可將資料儲存到執行緒池隊裡慢慢處理)。這個大家都比較熟悉,參考Java自帶的ThreadPoolExecutor執行緒池及佇列實現。執行緒池隔離參考下圖:

執行緒隔離的優點:

請求執行緒與依賴程式碼的執行執行緒可以完全隔離第三方程式碼;

當一個依賴執行緒由失敗變成可用時,執行緒池將清理後並立即恢復可用;

執行緒池可設定大小以控製並髮量,執行緒池飽和後可以拒絕服務,防止依賴問題擴散。

執行緒隔離的缺點:

增加了處理器的消耗,每個命令的執行涉及到排隊(預設使用SynchronousQueue避免排隊)和排程;

增加了使用ThreadLocal等依賴執行緒狀態的程式碼複雜性,需要手動傳遞和清理執行緒狀態。

(2)訊號量隔離模式:使用一個原子計數器來記錄當前有多少個執行緒在執行,請求來先判斷計數器的數值,若超過設定的最大執行緒個數則丟棄該類型的新請求,若不超過則執行計數操作請求來計數器+1,請求返回計數器-1。這種方式是嚴格的控製執行緒且立即返回模式,無法應對突發流量(流量洪峰來臨時,處理的執行緒超過數量,其他的請求會直接返回,不繼續去請求依賴的服務),參考Java的訊號量的用法。

Hystrix預設採用執行緒池隔離機製,當然使用者也可以配置 HystrixCommandProperties為隔離策略為ExecutionIsolationStrategy.SEMAPHORE。

訊號隔離的特點:

訊號隔離與執行緒隔離最大不同在於執行依賴程式碼的執行緒依然是請求執行緒,該執行緒需要通過訊號申請;

如果客戶端是可信的且可以快速返回,可以使用訊號隔離替換執行緒隔離,降低開銷。

執行緒池隔離和訊號隔離的區別見下圖,使用執行緒池隔離,使用者請求了15條執行緒,10條執行緒依賴於A執行緒池,5條執行緒依賴於B執行緒池;如果使用訊號量隔離,請求到C客戶端的訊號量若設定了15,那麼圖中左側使用者請求的10個訊號與右邊的5個訊號量需要與設定閾值進行比較,小於等於閾值則執行,否則直接返回。

建議使用的場景:根據請求服務級別劃分不同等級業務執行緒池,甚至可以將核心業務部署在獨立的伺服器上。

3.2 熔斷器機製

熔斷器與家裡面的保險絲有些類似,當電流過大時,保險絲自動熔斷以保護我們的電器。假設在沒有熔斷器機製保護下,我們可能會無數次的重試,勢必持續加大服務端壓力,造成惡性迴圈;如果直接關閉重試功能,當服務端又可用的時候,我們如何恢復?

熔斷器正好適合這種場景:當請求失敗比率(失敗/總數)達到一定閾值後,熔斷器開啟,並休眠一段時間,這段休眠期過後熔斷器將處與半開狀態(half-open),在此狀態下將試探性的放過一部分流量(Hystrix隻支援single request),如果這部分流量呼叫成功後,再次將熔斷器閉合,否則熔斷器繼續保持開啟並進入下一輪休眠週期。

建議使用場景:Client端直接呼叫遠端的Server端(server端由於某種原因不可用,從client端發出請求到server端超時響應之間佔用了系統資源,如記憶體,資料庫連線等)或共享資源。

不建議的場景如下:

應用程式直接訪問如記憶體中的資料,若使用熔斷器模式隻會增加系統額外開銷。

作為業務邏輯的異常處理替代品。

總結思考

本文從自己曾經開發的項目應用的分散式架構引出服務的雪崩效應,進而引出Hystrix(當然了,Hystrix還有很多優秀的特性,如快取,批量處理請求,主從分擔等,本文主要介紹了資源隔離和熔斷)。主要分三部分進行說明:

第一部分:以耕種田地的思想引出軟體領域設計的微服務架構, 簡單的介紹了其優點,著重介紹面臨的挑戰:雪崩問題。

第二部分:以Tomcat Container在高並發下崩潰為例揭示了雪崩產生的過程,進而總結了幾種誘發雪崩的場景及各種場景的應對解決方案,針對同步等待引出了Hystrix框架。

第三部分:介紹了Hystrix背景,資源隔離(總結了執行緒池和訊號量特點)和熔斷機製工作過程,並總結各自使用場景。

如Martin Fowler 在其文中所說,儘管微服務架構未來需要經歷時間的檢驗,但我們已經走在了微服務架構轉型的道路上,對此我們可以保持謹慎的樂觀,這條路依然值得去探索。

作者介紹

魏春雷,現任高階軟體工程師,為普元新一代數字化企業雲平臺開發團隊的一員,先後參與SRM(軟體資源管理)和負責SCM(軟體配置管理)領域系統的開發。2011年碩士畢業於西安交通大學電信學院,後進入華為西安研究所固定網路接入部門,先後開發了接入網的智慧光纖規劃和分散式網路評估系統。2016年進入普元資訊,業餘愛好:平時喜歡騎行、籃球、羽毛球和唱歌。

推薦一個對技術人員的成長很有幫助的線下會議,將於4月16~18日舉行的QCon全球軟體開發大會(北京站),目前已經邀請來自Google、Facebook、LinkedIn、Airbnb、百度、阿裡巴巴、騰訊等公司的100多位一線技術專家,是難得的線下交流學習的機會。具體詳戳 「 閱讀原文 」驚喜不停!

科技

» 聊聊架構

ADVERTISEMENT