分散式系統關註點——99%的人都能看懂的「熔斷」以及最佳實踐

来源:https://www.cnblogs.com/Zachary-Fan/archive/2018/11/19/circuitbreaker.html
-Advertisement-
Play Games

如果這是第二次看到我的文章,歡迎右側掃碼訂閱我喲~ > 本文長度為3319字,建議閱讀9分鐘。 閱讀目錄 熔斷是什麼 熔斷怎麼做 做熔斷的最佳實踐 總結 熔斷是什麼 熔斷怎麼做 做熔斷的最佳實踐 總結 熔斷是什麼 熔斷怎麼做 做熔斷的最佳實踐 總結 熔斷是什麼 熔斷怎麼做 做熔斷的最佳實踐 總結 熔 ...


如果這是第二次看到我的文章,歡迎右側掃碼訂閱我喲~  >

本文長度為3319字,建議閱讀9分鐘。

 

閱讀目錄

 

當我們工作所在的系統處於分散式系統初期的時候,往往這時候每個服務都只部署了一個節點。

 

那麼在這樣的背景下,如果某個服務A需要發佈一個新版本,往往會對正在運行的其它依賴服務A的程式產生影響。甚至,一旦服務A的啟動預熱過程耗時過長,問題會更嚴重,大量請求會阻塞,產生級聯影響,導致整個系統卡慢。

 

▲點擊圖片可查看大圖

 

舉個誇張的例子來形容:一幢樓的下水管是從最高樓直通到最低樓的,這個時候如果你家樓下的管道口堵住了,那麼所有樓上的污水就會倒灌到你家。如果這導致你家的管道口也堵住了,之後又會倒灌到樓上一層,以此類推。

 

然而實際生活中一旦你發現了這個問題,必然會想辦法先避免影響到自己家,然後跑到樓下讓他們趕緊疏通管道。此時,避免影響自己家的辦法就可被稱之為「熔斷」。

 

一、熔斷是什麼

熔斷本質上是一個過載保護機制。這一概念來源於電子工程中的斷路器,可能你曾經被這個東西的“跳閘”保護過。

 

▲圖片來源於網路,版權歸原作者所有

 

在互聯網系統中的熔斷機制是指:當下游服務因訪問壓力過大而響應變慢或失敗,上游服務為了保護自己以及系統整體的可用性,可以暫時切斷對下游服務的調用。

 

做熔斷的思路大體上就是:一個中心思想,分四步走

 

二、熔斷怎麼做

首先,需秉持的一個中心思想是:量力而行。因為軟體和人不同,沒有奇跡會發生,什麼樣的性能撐多少流量是固定的。這是根本。

 

然後,這四步走分別是:

  1. 定義一個識別是否處於“不可用”狀態的策略

  2. 切斷聯繫

  3. 定義一個識別是否處於“可用”狀態的策略,並嘗試探測

  4. 重新恢復正常

 

定義一個識別是否處於“不正常”狀態的策略

相信軟體開發經驗豐富的你也知道,識別一個系統是否正常,無非是兩個點。

  • 是不是能調通

  • 如果能調通,耗時是不是超過預期的長

 

但是,由於分散式系統被建立在一個並不是100%可靠的網路上,所以上述的情況總有發生,因此我們不能將偶發的瞬時異常等同於系統“不可用”(避免以偏概全)。由此我們需要引入一個「時間視窗」的概念,這個時間視窗用來“放寬”判定“不可用”的區間,也意味著多給了系統幾次證明自己“可用”機會。但是,如果系統還是在這個時間視窗內達到了你定義“不可用”標準,那麼我們就要“斷臂求生”了。

 

這個標準可以有兩種方式來指定。

  • 閾值。比如,在10秒內出現100次“無法連接”或者出現100次大於5秒的請求。

  • 百分比。比如,在10秒內有30%請求“無法連接”或者30%的請求大於5秒。

 

最終會形成這樣這樣的一段代碼。

全局變數 errorcount = 0; //有個獨立的線程每隔10秒(時間視窗)重置為0。
全局變數 isOpenCircuitBreaker = false;

//do some thing...

if(success){
    return success;
}
else{
    errorcount++;
    if(errorcount == 不可用閾值){
        isOpenCircuitBreaker = true;
    }
}

 

切斷聯繫

切斷聯繫要儘可能的“果斷”,既然已經認定了對方“不可用”,那麼索性就預設“失敗”,避免做無用功,也順帶能緩解對方的壓力。

 

分散式系統中的程式間調用,一般都會通過一些RPC框架進行。

那麼,這個時候作為客戶端一方,在自己進程內通過代理髮起調用之前就可以直接返回失敗,不走網路

這就是常說的「fail fast」機制。就是在前面提到的代碼段之前增加下麵的這段代碼。

if(isOpenCircuitBreaker == true){
    return fail;
}

//do some thing...

 

定義一個識別是否處於“可用”狀態的策略,並嘗試探測

切斷聯繫後,功能的完整性必然會受影響,所以還是需要儘快恢復回來,以提供完整的服務能力。這事肯定不能人為去干預,及時性必然會受到影響。那麼如何能夠自動的識別依賴系統是否“可用”呢?這也需要你來定義一個策略。

 

一般來說這個策略與識別“不可用”的策略類似,只是這裡是一個反向指標。

  • 閾值。比如,在10秒內出現100次“調用成功”並且耗時都小於1秒。

  • 百分比。比如,在10秒內有95%請求“調用成功”並且98%的請求小於1秒。

 

同樣包含「時間視窗」、「閾值」以及「百分比」。

 

稍微不同的地方在於,大多數情況下,一個系統“不可用”的狀態往往會持續一段時間,不會那麼快就恢復過來。所以我們不需要像第一步中識別“不可用”那樣,無時無刻的記錄請求狀況,而只需要在每隔一段時間之後去進行探測即可。所以,這裡多了一個「間隔時間」的概念。這個間隔幅度可以是固定的,比如30秒。也可以是動態增加的,通過線性增長或者指數增長等方式。

 

這個用代碼表述大致是這樣。

全局變數 successCount = 0; 
//有個獨立的線程每隔10秒(時間視窗)重置為0。
//並且將下麵的isHalfOpen設為false。

全局變數 isHalfOpen = true;
//有個獨立的線程每隔30秒(間隔時間)重置為true。

//do some thing...
if(success){
    if(isHalfOpen){
        successCount ++;
        if(successCount = 可用閾值){
            isOpenCircuitBreaker = false;
        }
    }
    
    return success;
}
else{
    errorcount++;
    if(errorcount == 不可用閾值){
        isOpenCircuitBreaker = true;
    }
}

 

另外,嘗試探測本質上是一個“試錯”,要控制下“試錯成本”。所以我們不可能拿100%的流量去驗證,一般會有以下兩種方式:

  1. 放行一定比例的流量去驗證。

  2. 如果在整個通信框架都是統一的情況下,還可以統一給每個系統增加一個專門用於驗證程式健康狀態檢測的獨立介面。這個介面額外可以多返回一些系統負載信息用於判斷健康狀態,如CPU、I/O的情況等。

 

重新恢復正常

一旦通過了衡量是否“可用”的驗證,整個系統就恢復到了“正常”狀態,此時需要重新開啟識別“不可用”的策略。就這樣,系統會形成一個迴圈。

▲點擊圖片可查看大圖

 

這就是一個完整的熔斷機制的面貌。瞭解了這些核心思想,用什麼框架去實施就變得不是那麼重要了,因為大部分都是換湯不換藥。

 

上面聊到的這些可以說是主幹部分,還有一些最佳實踐可以讓你在實施熔斷的時候拿捏的更到位。

 

三、做熔斷的最佳實踐

什麼場景最適合做熔斷

一個事物在不同的場景里會發揮出不同的效果。以下是我能想到最適合熔斷發揮更大優勢的幾個場景:

  • 所依賴的系統本身是一個共用系統,當前客戶端只是其中的一個客戶端。這是因為,如果其它客戶端進行胡亂調用也會影響到你的調用。

  • 所以依賴的系統被部署在一個共用環境中(資源未做隔離),並不獨占使用。比如,和某個高負荷的資料庫在同一臺伺服器上。

  • 所依賴的系統是一個經常會迭代更新的服務。這點也意味著,越“敏捷”的系統越需要“熔斷”。

  • 當前所在的系統流量大小是不確定的。比如,一個電商網站的流量波動會很大,你能抗住突增的流量不代表所依賴的後端系統也能抗住。這點也反映出了我們在軟體設計中帶著“面向懷疑”的心態的重要性。

 

做熔斷時還要註意的一些地方

與所有事物一樣,熔斷也不是一個完美的事物,我們特別需要註意2個問題。

 

首先,如果所依賴的系統是多副本或者做了分區的,那麼要註意其中個別節點的異常並不等於所有節點都存在異常,所以需要區別對待。

 

其次,熔斷往往應作為最後的選擇,我們應優先使用一些「降級」或者「限流」方案。因為“部分勝於無”,雖然無法提供完整的服務,但儘可能的降低影響是要持續去努力的。比如,拋棄非核心業務、給出友好提示等等,這部分內容我們會在後續的文章中展開。

 

四、總結

本文主要聊了熔斷的作用以及做法,並且總結了一些我自己的最佳實踐。

 

上面的這些代碼示例中也可以看到,熔斷代碼所在的位置要麼在實際方法之前,要麼在實際方法之後。它非常適合AOP編程思想的發揮,所以我們平常用到的熔斷框架都會基於AOP去做。

 

熔斷只是一個保護殼,在周圍出現異常的時候保全自身。但是從長遠來看平時定期做好壓力測試才能更好的防範於未然,降低觸發熔斷的次數。如果清楚的知道每個系統有幾斤幾兩,在這個基礎上再把「限流」和「降級」做好,這基本就將“高壓”下觸發熔斷的概率降到最低了。

 

 

Question: 

你覺得還有什麼時候需要熔斷呢?歡迎給我留言交流哦。

 

 

相關文章:

 

作者:Zachary(個人微信號:Zachary-ZF)

微信公眾號(首發):跨界架構師<-- 點擊後閱讀熱門文章,或右側掃碼關註 -->

定期發表原創內容:架構設計丨分散式系統丨產品丨運營丨一些深度思考


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1.創建模式:簡單工廠 單例模式: ArticleDao介面: public interface ArticleDao { public void addArticle(String article) ; public void delArticle(int id) ; public void up ...
  • 1. 例子 1. 做一個鴨子模擬器,裡面有很多不同的鴨子,有的可以游泳,有的可以睡覺,有的可以呱呱叫,一般套路是定義一個鴨子的超類,在 超類里定義睡覺,游泳,呱呱叫的方法,再讓不同的鴨子子類繼承這個超類,實現自己的display()方法來表現鴨子的行為,像下麵這樣: 2. 但如果要加一個可以吃火鍋的 ...
  • 系統架構設計師-軟體水平考試高級-理論-資料庫。其中涉及資料庫模式(三級抽象,兩層映射),數據模型,關係代數,規範化理論,事務處理等。 ...
  • 原型模式 prototype也是常用的一種設計模式,java中已經內置,藉助於Object的clone方法,本文對原型模式進行了簡單介紹,以及Java實現,並且介紹了對象的深拷貝與淺拷貝。 ...
  • 一、概念 工廠方法模式:用來封裝對象的創建。工廠方法模式(Factory Method Pattern)通過讓 子類 決定該創建的對象是什麼,來達到將對象創建的過程封裝的目的。這樣,關於超類的代碼和子類創建對象的代碼之間就解耦了。 角色:  1、抽象工廠(Creator):定義了一個抽象的 ...
  • 有時候,當一個重要的項目進展不順利時,就有了重新開始的願望。有時這來自管理層,但通常來自開發人員自己。他們說,如果他們只有第二次機會,並且可以重新開始,那麼他們可以建立正確的系統。 但這幾乎從未發生過。從我這拿走。我見過公司多次嘗試,我可以毫無例外地說,當一個團隊開始用基本相同的方法重建相同的系統時 ...
  • 基於隊列和基於消息的TTL TTL是time to live 的簡稱,顧名思義指的是消息的存活時間。rabbitMq可以從兩種維度設置消息過期時間,分別是隊列和消息本身。 隊列消息過期時間 Per Queue Message TTL: 通過設置隊列的x message ttl參數來設置指定隊列上消息 ...
  • 縱覽武俠江湖,制勝法門不外兩項,內功和外功。二者得一可天下去得,但最終皆入內外兼修之境倚天是自內而外,先修內功九陽真經,然後以此為基礎,加上太極拳和太極劍,最終成就天下第一高手笑傲是自外而內,先學獨孤九劍,後學吸星大法,最後學易筋經。神雕也不外如是,玉女心經算是外功,內功則是獨孤求敗之法門。只修內不 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...