大話微服務架構故障隔離及容錯處理機制

本文首先介紹微服務架構存在的風險,而後針對如何避免微服務架構的故障,提出了多種有效的微服務架構中的方法和技術,其中例如服務降級、變動管理、健康檢查和修復、斷路器、限流器等。

目錄面試

一、微服務架構的風險算法

二、優雅的服務降級數據庫

三、變動管理瀏覽器

四、健康檢查和負載均衡緩存

五、自我修復性能優化

六、故障轉移緩存(Failover Caching)服務器

七、重試邏輯(Retry Logic)網絡

八、限流器和負載開關(Rate Limiters and Load Shedders)架構

九、快速且單獨失效(Fail Fast and Independently)併發

十、艙壁模式(Bulkheads)

十一、斷路器(Circuit Breakers)

十二、故障測試(Testing for Failures)

1三、總結

1四、要點


微服務架構經過定義明確的服務邊界,能有效地隔離故障。 和其餘分佈式系統同樣,微服務在網絡、硬件和應用層上都會存在更多的問題。因爲服務之間是互相依賴,所以任何組件均可能出錯致使用戶不能訪問。爲儘量減小部分中斷帶來的影響,咱們須要構建容錯能力強的服務,以從容應對發生的某些中斷。

本文介紹了構建和運維高可用的微服務架構系統中最經常使用的技術和架構模式。若是讀者不熟悉上述的模式,那並沒什麼大礙。構建可靠的系統不是一踞而就的。

一、微服務架構的風險

微服務架構將應用邏輯拆分紅服務,服務之間經過網絡交互。因爲是經過網絡調用,而不是在進程中調用,所以這給須要在多個物理和邏輯組件間進行協做的系統帶來了潛在的問題和複雜性。分佈式系統變得愈來愈複雜,也致使網絡特定故障發生的可能性增大。

相比傳統應用龐大的結構,微服務架構最大的一個優勢是團隊能獨立地設計、開發和部署各自的服務。團隊能掌控各自服務的整個生命週期。這也意味者團隊沒法控制服務的依賴關係,由於這些依賴的服務多是由其餘團隊管理。在微服務架構體系下,咱們要牢記提供的服務因爲是其餘人控制,所以可能會因爲發佈、配置、和其餘變動等緣由,從而致使服務暫時不可用,並且組件之間互相獨立。

二、優雅的服務降級

微服務架構最大的優勢之一就是當組件出現故障時,能隔離這些故障而且能作到優雅地服務降級。好比,在圖片分享應用中,當出現故障時,用戶可能沒法上傳圖片,但他們依然能瀏覽、編輯和分享已上傳的圖片。

clipboard.png

微服務故障獨立(理論上)

在大多數狀況下,是很難實現上圖這種優雅地服務降級的,由於在分佈式環境下,應用都是互相依賴的,開發者須要實現若干錯誤處理的邏輯(該部分在本文稍後部分討論)去應對短暫的故障和中斷。

clipboard.png

服務互相依賴,若是無端障轉移的邏輯,則會同時失效

三、變動管理

Google的網站可靠性團隊發現大概70%的故障都是因爲變動而引發的。當對服務進行修改時……例如發佈代碼的新版本或者改變一些配置,則總會有可能引發故障或者引入新的錯誤。

在微服務架構中,服務是互相依賴的。這就是爲何你須要減小故障而且儘量下降它們的負面影響。爲了應對變動帶來的問題,你能夠實施變動策略管理而且實現其自動回滾。

好比,當部署新的代碼或者修改配置時,應該分步將這些變動部署到服務實例羣中的部分實例中,而且進行監控,若是發現關鍵指標出現問題則能自動進行回滾。

clipboard.png

變動管理-回滾部署

另外一個解決方案是運行兩套生產環境。部署的時候只部署變動的應用到其中一套環境中,而且在驗證了新發布的版本符合預期後,纔將負責均衡的流量指向新的應用,這種方法稱爲「藍-綠髮布」或者「紅-黑髮布」。

回退代碼並非壞事情。你不該該在生產環境中部署有問題的代碼,而且應該琢磨哪裏出錯了。當必要時候應該果斷回退代碼,這越早越好。

四、健康檢查和負載均衡

由於故障或部署、自動擴展等緣由,服務實例會不停啓動,從新啓動及中止。這使得服務暫時或一直停用。爲了不發生這些問題,在負載均衡中應該在路由中設置忽略這些實例,由於它們沒法爲子系統或用戶提供服務。

咱們能夠經過外部觀察去判斷應用實例是否健康。你能夠屢次調用Get/health的端點(endpoint)或者經過自身服務的報告得到相關信息。如今的服務發現解決方案會持續從實例中收集健康信息,而且設置負載均衡的路由,讓其只指向健康的實例組件。

五、自我修復

自我修復能幫助恢復應用。咱們討論下當應用遇到崩潰狀態後,如何經過相關的步驟去自我修復。在大多數狀況下,是經過外部系統監控實例的狀態,當服務出現故障一段時間後則會重啓服務。在大多數狀況下,自我修復的功能是至關有用的,然而,在某些狀況下因爲不斷地重啓服務會帶來相關的問題。例如當服務過載或者數據庫鏈接超時,則會致使應用不能反饋正確的服務健康狀態。

對於一些場景-好比數據庫連接丟失,這個時候實現高級的自我修復功能是頗爲棘手的。在這種狀況下,須要爲應用添加額外的邏輯去處理這些特例,而且讓外部系統知道服務的實例不須要當即從新啓動。

六、故障轉移緩存(Failover Caching)

由於網絡問題和系統中的變動,服務一般會出現故障。然而,這些故障中斷大可能是暫時的,這要歸功於自我修復和高級負載平衡的功能,咱們應該找到一個解決方案,能使服務即便在出現故障的時候也能工做。這就是故障轉移緩存(Failover Caching),它能幫助爲咱們的應用提供必需的數據。

失效轉移緩存一般使用兩個不一樣的過時日期:其中更短的日期指示在正常狀況下能使用緩存的時間,而更長的一個日期則指示在故障失效的時候,能使用緩存中的數據時長。

clipboard.png

故障轉移緩存

特別須要提醒的是,只有當提供過期的數據比沒有數據更好的狀況下,才能使用故障轉移緩存。

要設置緩存和故障轉移緩存,能夠在HTTP中使用標準響應頭。

例如,使用max-age頭能夠指定某個資源爲新資源的最大時間(譯者注:意即設定max-age後,瀏覽器再也不發送請求到服務器)。可使用stale-if-error 頭去肯定在出現故障的狀況下,從緩存獲取資源的時間長短。

如今的CDN和負載均衡器提供了各類緩存和故障轉移的解決方案,可是你也能夠在你的公司中創建一個共享庫,其中包括這些標準的可靠性解決方案。

七、重試邏輯(Retry Logic)

在某些狀況下,咱們可能沒法緩存數據,或者想對數據進行變動,可是操做最終失敗了。在這種狀況下,咱們就能夠選擇重試操做,由於咱們能夠預期資源將在一段時間後恢復,或者負載均衡會將請求發送到健康的實例上。

你應該當心地爲應用程序和客戶端添加劇試邏輯,由於更大量的重試操做可能會使事情變得更糟,甚至阻止應用程序恢復。

在分佈式系統中,微服務系統重試可能會觸發多個其餘請求或重試操做,並致使級聯效應。爲減小重試帶來的影響,你應該減小重試的數量,並使用指數退避算法(exponential backoff algorithm)來持續增長重試之間的延遲時間,直到達到最大限制。

因爲重試是由客戶端(瀏覽器,其餘微服務等)發起的,而且客戶端在處理請求先後是不知道草走失敗的,你應該爲你的應用程序提供冪等處理能力。例如,當你重試購買操做時,不該該向客戶收兩次錢。給每一個事務使用惟一的冪等鍵(idempotency-key)是解決重試問題的方法。

八、限流器和負載開關(Rate Limiters and Load Shedders)

限流是指在一段時間內,定義某個客戶或應用能夠接收或處理多少個請求的技術。例如,經過限流,你能夠過濾掉產生流量峯值的客戶和微服務,或者能夠確保你的應用程序在自動擴展(Auto Scaling)失效前都不會出現過載的狀況。

你還能夠阻止較低優先級的流量,以便爲關鍵事務提供足夠的資源。

clipboard.png

限流器能夠阻止流量峯值

另外有一種限流器,稱爲 「併發請求限流器(concurrent request limiter)」。當你有一些比較昂貴和重要的端點(endpoint),但願它不該該被調用超過指定的次數,但仍然想要提供流量服務時,這個限流器就十分有用了。

使用負載開關能夠確保對於關鍵的事務總能提供足夠的資源保障。它爲高優先級的請求保留一些資源,而且不容許低優先級的事務去佔用這些資源。負載開關會根據系統的總體狀態作出決定,而不是基於單個用戶的請求桶(request bucket)大小。負載設備有助於你的系統恢復,由於它們在持續發生故障事件時,依然能保持核心功能正常工做。

九、快速且單獨失效(Fail Fast and Independently)

在微服務體系架構中,咱們但願服務能夠快速、單獨地失效。爲了在服務層面隔離故障,咱們可使用隔板模式(bulkhead pattern)。能夠在本文稍後看到相關介紹。

咱們也但願咱們的組件可以快速失效(fail fast),由於咱們不但願等到斷開的實例直到超時。沒有什麼比掛起的請求和無響應的界面更使人失望。這不只浪費資源,並且還會讓用戶體驗變得更差。咱們的服務是互相調用的,因此在這些延遲疊加前,應該特別注意防止那些超時的操做。

你想到的第一個辦法,多是對每一個服務的調用都定義超時的級別。這種作法的問題是,你不能真正知道到底什麼是恰當的超時值,由於當網絡故障和其餘問題發生時,某些狀況下只會影響一兩次操做。在這種狀況下,若是隻有其中一些發生超時,你可能不想拒絕全部這些請求。

咱們能夠說,經過使用超時(timeout)來實現微服務中的快速失敗是一種反模式,這是應該避免的。可使用基於操做的成功/失敗統計次數的熔斷模式,而不是使用超時。

十、艙壁模式(Bulkheads)

在工業領域中,常使用艙壁將劃分爲幾個部分,以便在有某部分船體發生破裂時,其餘部分依然能密封安然無恙。

艙壁的概念也能夠在軟件開發中用於隔離資源。

經過使用艙壁模式,咱們能夠保護有限的資源不被用盡。例如,若是咱們有兩種類型的操做的話,它們都是和同一個數據庫實例進行通訊,而且數據據庫限制鏈接數,這時咱們可使用兩個鏈接池而不是使用一個共享的鏈接池。因爲這種客戶端和資源分離,超時或過分使用池的操做不會令全部其餘操做失效。

泰坦尼克號沉沒的主要緣由之一是其艙壁設計失敗,水能夠經過上面的甲板倒在艙壁的頂部,最後整個船淹沒。

clipboard.png

泰坦尼克號故障的艙壁

十一、斷路器(Circuit Breakers)

爲了限制操做的持續時間,咱們可使用超時。超時能夠防止掛起操做並保證系統能夠響應。然而,在微服務架構通訊中使用靜態、微調的超時是一種反模式,由於咱們處於高度動態的環境中,幾乎不可能肯定在每種狀況下都能正常工做的準確的時間限制。

咱們可使用斷路器來處理錯誤,而不是使用小型和特定基於事務的靜態超時機制。斷路器以現實世界的電子元件命名,由於它們的行爲是都是相同的。你能夠保護資源,並經過使用斷路器協助它們進行恢。斷路器在分佈式系統中很是有用,由於重複的故障可能會致使雪球效應,並使整個系統崩潰。

當在短期內屢次發生指定類型的錯誤,斷路器會開啓。開啓的斷路器能夠拒絕接下來更多的請求 – 就像防止真實的電子流動同樣。斷路器一般在必定時間後關閉,以便爲底層服務提供足夠的空間來恢復。

請記住,並非全部的錯誤都應該觸發斷路器。例如,你可能但願忽略客戶端問題,好比4xx響應代碼的請求,但要包括5xx服務器端故障。一些斷路器還能夠有半開關狀態。在這種狀態下,服務發送第一個請求以檢查系統的可用性,同時讓其餘請求失敗。若是這個第一個請求成功,則將斷路器恢復到關閉狀態並繼續接受流量。不然,保持打開狀態。

clipboard.png

斷路器

十二、故障測試(Testing for Failures)

你應該持續地測試系統的常見問題,以確保你的服務可各種故障環境下運行。你應常常測試故障,以讓你的團隊對可能發生的事故有所準備。

關於測試,你可使用外部服務來識別服務實例組,並隨機終止運行組中的一個實例。經過使用這個方法,能夠針對單個實例故障進行測試,你甚至能夠關閉整個服務組來模擬雲提供商層面的故障中斷。

1三、總結

實施和運維可靠的服務並不容易。這須要你付出不少努力,還要花費公司更多的成本。

說到這裏順便給你們推薦一個Java架構方面的交流學習社羣:650385180,裏面不只能夠交流討論,還有面試經驗分享以及免費的資料下載,包括Spring,MyBatis,Netty源碼分析,高併發、高性能、分佈式、微服務架構的原理,JVM性能優化這些成爲架構師必備的知識體系。相信對於已經工做和遇到技術瓶頸的碼友,在這個羣裏會有你須要的內容。

可靠性有不少層次和方面,所以針對你的團隊找出合適的解決方案是至關重要的。你應該將可靠性成爲業務決策流程中的一個因素,併爲此分配足夠的預算和時間。

1四、要點

  • 動態環境和分佈式系統-如微服務將致使更高的故障機會。
  • 服務應單獨失效,實現優雅的服務降級以提高用戶體驗。
  • 70%的問題是由變動引發的,恢復可用代碼並不老是壞事。
  • 快速,單獨地失敗。團隊沒法控制其服務依賴關係。
  • 架構模式和技術,如緩存、隔離技術、斷路器和限流器有助於構建可靠的微服務
相關文章
相關標籤/搜索