主頁 > 後端開發 > 微服務架構如何避免大規模故障?

微服務架構如何避免大規模故障?

2021-08-20 06:18:00 後端開發

微服務架構通過一種良好的服務邊界劃分,能夠有效地進行故障隔離,但就像其他分布式系統一樣,在網路、硬體或者應用級別上容易出現問題的機率會更高,服務的依賴關系,導致在任何組件暫時不可用的情況下,就它們的消費者而言都是可以接受的,為了能夠降低部分服務中斷所帶來的影響,我們需要構建一個容錯服務,來優雅地應對特定型別的服務中斷,

本文基于一些在RisingStack的顧問咨詢與開發經驗,介紹了如何運用一些最常用的技術和架構模型,去構建與維護一個高可用的微服務系統,

如果你不熟悉本文中的模式,并不意味著你做錯了什么,畢竟構建一個高可用的系統需要很多額外的付出,

*微服務架構的風險 The Risk of the Microservices Architecture

微服務的架構將應用的邏輯移動到一個服務里面,服務之間通過網路層進行通信互動,通過網路通信互動的方式取代了記憶體的呼叫,同時需要多個物理和邏輯組件之間的相互協作,給系統帶來了額外的延遲性與復雜性,分布式系統復雜性的增加,導致了特定網路故障的可能性變得更大,

微服務允許你實作優雅的服務降級,因為組件可以被單獨的設定為失敗,

團隊可以獨立地設計、開發與部署他們的服務,是微服務的最大優點之一,他們完全擁有整個服務的生命周期,這也意味著團隊無法控制他們的服務依賴,因為這些服務更有可能是不同的團隊在管理,我們需要記住,提供者的服務由于發布中斷、配置等等其他的改變而暫時不可用,他們是由別人控制,并且組件之間獨立活動,

*優雅的服務降級 Graceful Service Degradation

微服務最佳優勢之一,當某個組件單獨失敗時,你可以實作優雅的服務降級,進行故障隔離,例如,一個照片共享的應用,由于中斷,用戶可能無法上傳新的照片,但他們仍然可以瀏覽、編輯和分享他們現有的照片,

微服務的獨立失敗(理論上)

在大多數情況下,在一個分布式系統中,應用程式之間互相依賴,實作一種優雅的服務降級,這是很困難的,你需要采取多種故障切換邏輯(其中一些會在本文后面進行討論),應對臨時的故障與中斷,

服務之間彼此依賴,在沒有故障切換邏輯的情況下,一起失敗,

*變更管理 Change management

谷歌網站的可靠性團隊(SRE)發現,大約70%的中斷是由一個實時系統的改變而引起,當你在服務中更改某些內容時——你部署了新版本的代碼或更改了一些配置——總會導致更高的失敗機率或者引入一個新的bug,

在微服務架構中,服務之間彼此依賴,這就是為什么你應該盡量減少失敗,并限制它們的負面影響,如果要處理來自變更的問題,你可以使用變更管理策略和自動升級,

例如,當需要部署新代碼或者更改某些配置時,你應該逐漸地將這些更改應用于實體的子集,監控它們,甚至當你看到關鍵指標有負面影響時,它們會自動回滾恢復,

變更管理 - 滾動發布

另一個解決方案,就是運行兩個生產環境,只部署其中一個,并且在驗證新版本的運行符合預期之后,才會將負載均衡指向新版本,這被稱為藍綠色部署,或紅黑色部署,

恢復代碼不是一件壞事情,你不應該把壞的代碼留在生產中,然后再思考哪里出了問題,必要的時候,總是要恢復你的改變(回滾),越快越好,

*健康檢查與負載均衡 Health-check and Load Balancing

實體會因為失敗、部署或自動伸縮,而不斷地啟動、重新啟動和停止,這會導致服務暫時或永久不可用,為了避免問題,你的負載均衡應該跳過不健康的實體,因為它們不能滿足你的用戶或子系統的需要,

應用實體健康可以通過外部觀察來決策,你可以反復呼叫 GET /health 請求埋點或自身報告,現代服務發現解決方案,將不斷從實體中收集健康資訊,并配置負載均衡以保證健康的組件路由流量,

*自愈 Self-healing

自我修復可以幫助恢復應用程式,我們談論的自愈,是指應用程式可以做一些必要的步驟來恢復崩潰狀態,在大多數情況下,這樣的操作是經由一個外部系統來實作的,它會監控實體的健康,并在它們較長時間處于錯誤狀態的情況下,重新啟動應用程式,自愈是非常有用的,但是在某些情況下,不斷地重啟應用程式會引起麻煩,由于負載過高或者資料庫連接超時,你的應用程式不停的重啟,會導致無法提供一個正確的健康狀態,

實作一種為微妙的情況而準備的高級自我修復解決方案,可能會很棘手,比如資料庫連接丟失,在這種情況下,你需要為應用程式添加額外的邏輯來處理一些極端情況,并讓外部系統知道不需要立即重啟實體,

*故障切換快取 Failover Caching

服務通常會因為網路問題和系統的變更而失敗,由于自愈和先進的負載均衡,大多數中斷只是暫時的,然而我們還應該找到一個解決方案,讓我們的服務在這些故障中能夠正常作業,這就是故障切換快取,它可以幫助應用程式提供一些必要的資料,

故障切換快取一般使用兩個不同的過期時間,設定一個較短的時間,顯示在正常情況下可以使用多長時間的快取;設定另一個較長的時間,顯示在發生故障期間,可供使用快取資料的時間會有多久,

故障切換快取

很重要的一點是,只有當過時的資料比什么都不做要好的情況出現時,才可運行故障切換緩,

可以通過使用HTTP中的標準回應頭(response header)來設定快取和故障轉移快取,

例如,通過設定 header 引數 max-age 來指定一個資源被重繪時最大時間;也可以通過設定 header 引數 stale-if-error 來決定,在服務失敗的情況下,需要多長時間從快取獲取資料,

現代的CDN和負載均衡器提供了各種快取和故障切換的方式,你也可以為公司建立一個包含了統一的可靠性解決方案的共享標準庫,

*重試機制 Retry Logic

在某些特定的場景下,我們可能無法快取資料,或者我們想對其做出一些更改,但是我們的操作最侄訓是會失敗,在這些情況下,我們可以重新嘗試我們的操作,因為我們可以預計資源在一段時間后會恢復,或者我們的負載均衡將我們的請求轉發到一個健康的實體,

在應用程式和客戶端添加重試邏輯需保持謹慎,因為大量的重試會讓事情變得更糟,甚至會阻止應用程式的恢復,

在分布式系統中,微服務系統重試會觸發多個其他的請求或重試,引起一個級聯效應,為了盡量減少重試帶來的影響,你應該最大限度限制它們的發生次數,并使用指數補償演算法來持續增加重試之間的延遲,

重試由客戶端(瀏覽器,其他微服務等)發起,客戶端不知道這個操作是在處理請求之前失敗還是之后失敗的,你應該準備好應用程式來處理冪等性(idempotency),例如,當操作重試購買時,不應該對用戶進行重復扣費,對于每個事務,使用唯一的 冪等令牌(idempotency-key ),可以幫助處理重試,

*限流與降級 Rate Limiters and Load Shedders

限流是指在一個時間段內,特定的用戶或應用程式可以接識訓處理多少請求的技術,例如,有了限流,你就可以找出引起流量高峰的用戶和微服務,或者可以確保應用不會在負載過高情況下,發生自動擴容都不能拯救,

你還可以限制業務優先級較低的流量,以便為核心業務提供足夠的資源,

限速器可以抑制流量高峰

另外一種型別的限速器稱為并發請求限制,當有一些昂貴的端點不應該超過指定的呼叫次數,但你仍然希望提供流量服務時,選擇這樣的操作是很有用的,

快速降級可以確保總是有足夠的可用資源去服務關鍵的事務,它為高優先級請求保留一些資源,并且不允許低優先級事務使用所有的資源,降級與否是根據系統的整個狀態進行判斷的,而不是基于單個用戶的請求桶大小,服務降級用于幫助恢復系統,當發生一些事故時,它們可以保證核心功能仍然繼續作業,

如需獲取更多有關限流與降級的資訊,推薦前往https://stripe.com/blog/rate-limiters,閱讀Stripe的文章,

*快速且獨立地失敗 Fail Fast and Independently

在微服務體系結構中,我們希望我們的服務能夠快速、獨立地失敗,為了在服務級別上隔離問題,我們可以采用艙壁模式(bulkhead pattern),你稍后可以在這篇文章中讀到更多關于艙壁的資訊,

我們還希望我們的組件快速失敗,因為我們不想等待壞的實體超時,沒有什么比一個掛著的請求和一個沒有回應的UI更令人失望的了,這樣不僅浪費資源,而且還會對用戶體驗造成影響,我們的服務是相互呼叫的,所以更應該額外注意,在這些延遲結束之前,阻止掛起操作,

第一個想到的想法是在每個服務呼叫上運用一個較好級別的超時時間,這種方法的問題在于,你不可能真正知道什么是一個好的超時時間值,因為在某些情況下,網路故障和其他問題只會影響到一兩個操作,在這種情況下,如果只有少數幾個請求超時,你可能不想拒絕這些請求,

我們可以說,在微服務中使用超時來實作快速失敗的例子是一種反模式,你應該避免它,你可以依賴于操作成功/失敗統計資料的斷路器(circuit-breaker)模式,而不是超時,

*艙壁 Bulkheads

艙壁被用來將一艘船劃分成多個部分,這樣就可以在船體破裂的情況下對部分封閉,

隔離壁的概念可以應用于軟體開發中,做到資源隔離,

通過采用艙壁模式,我們可以保護有限的資源不被耗盡,例如,如果我們有兩種操作,它們與相同的資料庫實體互動,我們的連接數量有限,那么我們可以使用兩個連接池,而不是共享連接池,由于此客戶端資源分離,當發生超時或者過度使用連接池的操作,不會導致所有其他操作的關閉,

泰坦尼克號沉沒的主要原因之一,就是它的艙壁有一個設計上的失敗,水可以通過艙壁頂部上的甲板注入,淹沒整個船體,

泰坦尼克的艙壁(他們沒有作業)

*斷路器 Circuit Breakers

為了限制操作的持續時間,我們可以使用超時,超時可以防止掛起操作并保持系統回應,然而,在微服務通信中使用靜態的、微調的超時是一種反模式,因為我們處在一個高度動態的環境中,幾乎不可能發現正確的時間限制,以確保在每個場景下都能很好地作業,

我們可以使用熔斷來處理錯誤,而不是使用小的特定事務的靜態超時,斷路器是以真實世界電子元件命名的,因為它們的行為是相同的(簡單的說,這種模式主要是參考電路熔斷,如果一條線路電壓過高,保險絲會熔斷,防止火災),你可以保護資源,幫助他們用斷路器恢復,它們在分布式系統中非常有用,因為重復的失敗會導致滾雪球效應(snowball effect),導致整個系統癱瘓,

當一個特定型別的錯誤在短時間內多次出現時,斷路器就會打開,斷路器的打開,阻止了進一步的資源請求——就像真的阻止了電流的流動,斷路器通常在一定時間后關閉,為基礎服務提供足夠的空間來恢復,

請記住,并非所有的錯誤都應該觸發斷路器,例如,你可能希望跳過客戶端問題,比如跳過 4xx 狀態碼回應的請求,但不包括 5xx 服務器端錯誤的請求,一些斷路器也可以有半開狀態,在此狀態下,服務發送第一個請求檢測系統的可用性,同時讓其他請求失敗,如果第一個請求成功,它將斷路器恢復到一個關閉狀態,并允許流量進入,否則,它就會打開,

*測驗失敗 Testing for Failures

你應該不斷地測驗你的系統以防止常見問題,以確保你的服務能夠承受住各種失敗,你應該頻繁地測驗失敗,讓你的團隊為發生事故而做好準備,

對于測驗,你可以使用一個外部服務來標識實體組,并隨機終止該組中的一個實體,有了這個,你就可以為單個實體的失敗做準備,你甚至可以關閉整個可用區來模擬云提供商的中斷,

最流行的測驗解決方案之一是由Netflix提供的ChaosMonkey彈性工具,

*結尾

實作和運行可靠的服務并不容易,這需要你付出很大的努力,也要花費你的公司很多錢,

可靠性有很多的層次和方面,所以為你的團隊找到最好的解決方案是很重要的,你應該將可靠性作為業務決策程序中的一個因素,并為它分配足夠的預算和時間,

*主要識訓

動態環境和分布式系統——比如微服務——會導致更大的失敗機率,
服務應該單獨失敗,實作優雅的降級,用以改善用戶體驗,
70%的中斷是由變更引起的,恢復代碼并不是件壞事,
快速和獨立的失敗,團隊無法控制他們服務的依賴,
架構模式和技術,如快取、艙壁、限流、熔斷,有助于建立可靠的微服務,

原文:https://blog.risingstack.com/designing-microservices-architecture-for-failure/

譯文:https://blog.csdn.net/xushuai110/article/details/77726447

近期熱文推薦:

1.1,000+ 道 Java面試題及答案整理(2021最新版)

2.別在再滿屏的 if/ else 了,試試策略模式,真香!!

3.臥槽!Java 中的 xx ≠ null 是什么新語法?

4.Spring Boot 2.5 重磅發布,黑暗模式太炸了!

5.《Java開發手冊(嵩山版)》最新發布,速速下載!

覺得不錯,別忘了隨手點贊+轉發哦!

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/294841.html

標籤:其他

上一篇:微服務體系中的分層設計和領域劃分!

下一篇:requests模塊的使用

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more