分布式彈性故障處理框架——Polly(1)

1 前言之服務雪崩

在我們實施微服務之后,服務間的調用變得異常頻繁,多個服務之前可能存在互相依賴的關系,當某個服務出現故障或者是因為服務間的網絡出現故障,導致服務調用的失敗,進而影響到某個業務服務處理失敗,服務依賴的故障可能導致級聯崩潰,如一個微服務不可用拖垮整個系統。【服務雪崩】

服務雪崩通常遵循 “從局部故障到全局崩潰” 的遞進路徑,可拆解為以下步驟:

  1. 初始故障
    某個基礎服務(如數據庫、緩存、第三方 API)因過載、網絡中斷或 bug 出現響應延遲或失敗。
    例:支付服務因數據庫連接池耗盡,處理請求的時間從 100ms 增至 5s。
  2. 請求堆積
    依賴該故障服務的上游服務(如訂單服務)因等待響應,線程 / 連接被長時間占用,無法釋放資源。
    例:訂單服務調用支付服務時,每個請求都需等待 5s,而線程池容量有限(如 200 線程),很快所有線程被占滿。
  3. 級聯阻塞
    上游服務因資源耗盡,無法處理新請求,導致依賴它的更上游服務(如用戶服務)也出現資源耗盡。
    例:用戶服務調用訂單服務時,因訂單服務無響應,用戶服務的線程也被占滿,無法處理用戶登錄請求。
  4. 全局崩潰
    故障像多米諾骨牌一樣擴散,最終整個系統的核心功能(如下單、支付、登錄)全部失效。

服務雪崩的本質是 “故障的無限制擴散”. 就像是蝴蝶效應最后導致美國得克薩斯州的一場龍卷風

2 如何解決服務雪崩

針對雪崩的形成機制,需從 “限制資源消耗”“隔離故障”“快速失敗” 三個維度設計防護策略:

  1. 熔斷機制(Circuit Breaker)
  • 原理:當某個服務的失敗率超過閾值(如 50% 失敗),暫時 “斷開” 對它的調用,直接返回降級結果,避免資源浪費。
  • 效果:防止故障服務持續消耗上游資源,給故障服務恢復的時間窗口。
  1. 限流機制(Rate Limiting)
  • 原理:限制單位時間內對某個服務的請求量(如每秒 1000 次),防止瞬時流量沖垮服務。
  • 場景:針對下游服務的最大承載能力,提前設置流量閾值。
  1. 隔離機制(Isolation)
  • 原理:為不同服務的調用分配獨立的資源池(線程池、連接池),避免一個服務的故障耗盡全局資源。
  • :訂單服務調用支付服務時使用單獨的線程池(20 線程),調用庫存服務時使用另一個線程池(30 線程),即使支付服務故障,也不會影響庫存服務的調用。
  1. 超時控制(Timeout)
  • 原理:為服務調用設置明確的超時時間(如 2s),超過時間直接終止請求,避免線程被無限期占用。
  • 關鍵:超時時間需根據下游服務的正常響應時間合理設置(通常略高于 99% 請求的處理時間)。
  1. 降級策略(Fallback)
  • 原理:當服務調用失敗時,返回預設的兜底結果(而非直接報錯),保證核心流程可用。
  • :推薦服務故障時,返回默認熱門商品列表;支付服務超時后,返回 “支付中,請稍后查詢”。

3 什么是Polly

Polly 是 .NET 生態中一款強大的 彈性和瞬態故障處理庫,主要用于處理分布式系統中常見的網絡故障、超時、資源限流等問題,通過預定義的策略(如重試、熔斷、超時等)提高應用程序的穩定性和容錯能力。從而增強服務的可用性

3.1 超時策略

超時策略可防止因長時間阻塞導致的資源耗盡或級聯故障.

在 Polly 中,TimeoutStrategy 是控制超時行為的核心枚舉,
定義了兩種不同的超時處理機制:樂觀超時(Optimistic)和悲觀超時(Pessimistic)
Optimistic使用CancellationToken取消服務,默認是使用樂觀超時的處理機制
Pessimistic 不需要使用CancellationToken,強制終端業務邏輯,這種情形可能會導致相關聯的資源沒有關閉。需要對這部分邏輯做處理

策略類型觸發條件依賴操作協作拋出的異常類型
樂觀超時超時 + 操作響應取消OperationCanceledException
悲觀超時超時(強制觸發)TimeoutRejectedException
     /// <summary>/// Polly的超時策略【使用樂觀處理機制】/// </summary>/// <param name="url"></param>/// <returns></returns>[HttpGet]public async Task<IActionResult> TimeOutOptimisticPolicy(string url) {// 示例:設置 5 秒悲觀超時 超時后將執行回調函數// 超時策略可防止因長時間阻塞導致的資源耗盡或級聯故障// 在 Polly 中,TimeoutStrategy 是控制超時行為的核心枚舉,// 定義了兩種不同的超時處理機制:樂觀超時(Optimistic)和悲觀超時(Pessimistic)// Optimistic使用CancellationToken取消服務,默認是使用樂觀超時的處理機制// Pessimistic不需要使用CancellationToken取消服務// onTimeoutAsync回調函數是在超時發生時執行的附加操作,但它不會改變 ExecuteAsync 的返回值。// 這個回調主要用于日志記錄、監控或其他副作用操作,而不是直接返回 HTTP 響應。using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(3));var token = cts.Token;var timeOutPolicy = Policy.TimeoutAsync<IActionResult>(timeout: TimeSpan.FromSeconds(3),timeoutStrategy: TimeoutStrategy.Optimistic,onTimeoutAsync: (context, timespan, task) =>{Console.WriteLine($"操作超時:{timespan.TotalSeconds}秒");return Task.CompletedTask;});return await  timeOutPolicy. ExecuteAsync(async token =>{try{using (HttpClient client = new HttpClient()){HttpResponseMessage message = await client.GetAsync(url, token);//序列化響應結果string resContent = await message.Content.ReadAsStringAsync();return new OkObjectResult(resContent);}}//任務由于超時異常被取消 ,在任務內部拋出 TaskCanceledException 異常catch (TaskCanceledException e) {return new ObjectResult(new ReturnMessageModel<string>{Code = "408",Message = "操作超時",}){ StatusCode = 408 };}catch (Exception e){return new ObjectResult(new ReturnMessageModel<string>{Code = "500",Message = $"服務錯誤:{e.Message}" + e.GetType().Name,Status = (int)HttpStatusCode.InternalServerError}){ StatusCode = 500 };}}, token);}/// <summary>/// Polly的超時策略【使用悲觀處理機制】/// </summary>/// <param name="url"></param>/// <returns></returns>[HttpGet]public async Task<IActionResult> TimeOutPessimisticPolicy(string url){var timeOutPolicy = Policy.TimeoutAsync<IActionResult>(timeout: TimeSpan.FromSeconds(3),timeoutStrategy: TimeoutStrategy.Pessimistic,onTimeoutAsync: (context, timespan, task) =>{Console.WriteLine($"操作超時:{timespan.TotalSeconds}秒");return Task.CompletedTask;});try{return await timeOutPolicy.ExecuteAsync(async () =>{try{using (HttpClient client = new HttpClient()){HttpResponseMessage message = await client.GetAsync(url);//序列化響應結果string resContent = await message.Content.ReadAsStringAsync();return new OkObjectResult(resContent);}}catch (Exception e){return new ObjectResult(new ReturnMessageModel<string>{Code = "500",Message = $"服務錯誤:{e.Message}" + e.GetType().Name,Status = (int)HttpStatusCode.InternalServerError}){ StatusCode = 500 };}});}catch (TimeoutRejectedException e) {// 服務超時。return new ObjectResult(new ReturnMessageModel<string>{Code = "408",Message = "操作超時",}){ StatusCode = 408 };}}
3.2 重試策略

在分布式系統中,網絡請求可能會因為臨時故障(如網絡抖動、服務暫時不可用)而失敗。Polly 的重試策略(Retry Policy)是處理這類問題的有效工具,它可以在請求失敗時自動重試,提高系統的穩定性和容錯能力

固定次數重試策略

  /// <summary>/// 固定次數重試策略/// </summary>/// <param name="url"></param>/// <returns></returns>[HttpGet]public async Task<IActionResult> RetryPolicy(string url) {// 重試策略,對所有捕獲的異常進行重試次數策略,當重試次數<= 設定值時,均會進入回調函數邏輯var policy = Policy.Handle<Exception>().RetryAsync(3, (exception, retryCount) => {Console.WriteLine($"重試第 {retryCount} 次: {exception.Message}");});try{return await policy.ExecuteAsync(async () =>{using (HttpClient client = new HttpClient()){HttpResponseMessage message = await client.GetAsync(url);//序列化響應結果string resContent = await message.Content.ReadAsStringAsync();return new OkObjectResult(resContent);}});}catch (Exception e) {return new ObjectResult(new ReturnMessageModel<string>{Code = "500",Message = $"服務錯誤:{e.Message}" + e.GetType().Name,Status = (int)HttpStatusCode.InternalServerError}){ StatusCode = 500 };}}
3.3 降級策略

服務降級(Service Degradation 是一種應對系統過載或依賴服務故障的彈性策略,通過暫時犧牲部分非核心功能或服務質量,確保系統核心功能的可用性和穩定性.一般是碰到異常時會給一個默認回調的形式去代替原有的服務

        /// <summary>/// 模擬從緩存中獲得暫時的響應數據/// </summary>/// <returns></returns>private async Task<HttpResponseMessage> GetDataFromRedis() {HttpResponseMessage httpResponse = new HttpResponseMessage();httpResponse.StatusCode = HttpStatusCode.OK;var resdata=new  ReturnMessageModel<bool>("0",0,"從緩存中獲得數據",true);string json = JsonConvert.SerializeObject(resdata);httpResponse.Content = new StringContent(json, Encoding.UTF8, "application/json");return httpResponse;}/// <summary>/// 服務降級策略【降級策略常常搭配其他策略一起使用】/// </summary>/// <param name="url"></param>/// <returns></returns>[HttpGet]public async Task<ReturnMessageModel<string>> DegradationPolicy(string url) {// 定義重試策略var retryPolicy = Policy<HttpResponseMessage>.Handle<Exception>().RetryAsync(3,onRetryAsync: (ex, times) => {Debug.WriteLine($"當前重試次數為 {times}");return Task.CompletedTask;});//  定義降級策略var fallbackPolicy = Policy<HttpResponseMessage>.Handle<Exception>().FallbackAsync(async (cancellaction) =>{//  該回調函數中執行降級的邏輯,比如說從緩存中獲取邏輯Debug.WriteLine("進行了服務降級策略");return await GetDataFromRedis();});// Polly 處理策略,先重試,后降級// Policy.WrapAsync 包含多種執行策略// 在Polly中,策略的包裹順序非常重要,因為策略的執行順序是從最外層策略開始,逐層向內執行。// 當我們使用PolicyWrap時,通過Policy.WrapAsync方法組合策略,會形成一個策略管道,請求首先進入最先包裹的策略(最外層),然后依次向內傳遞,直到執行用戶提供的原始委托。var policy = Policy.WrapAsync(fallbackPolicy,retryPolicy);// 使用降級策略去處理任務HttpResponseMessage res=   await policy.ExecuteAsync(async() =>{using (HttpClient client = new HttpClient()){HttpResponseMessage message = await client.GetAsync(url);return message;}});string resContent = await res.Content.ReadAsStringAsync();return new ReturnMessageModel<string>(resContent);}
3.4 熔斷策略

Polly 的熔斷策略(Circuit Breaker)用于在系統檢測到持續故障時,自動斷開(熔斷)對特定服務的請求,防止系統資源被耗盡并快速失敗。當熔斷器處于開啟狀態時,所有請求會立即被拒絕(拋出 BrokenCircuitException),直到經過設定的恢復期后,熔斷器會進入半開狀態,允許部分請求嘗試恢復服務。如果這些請求成功,則關閉熔斷器;否則,繼續保持開啟。

熔斷器包含三個狀態

Closed(閉合):正常狀態,操作允許執行。

Open(斷開):熔斷狀態,所有操作被快速失敗,不再嘗試執行。

Half-Open(半開):熔斷器嘗試恢復,允許少量操作執行以測試依賴服務是否恢復。

Polly提供兩種熔斷器策略:

  1. 基于連續失敗次數的熔斷器(Basic Circuit Breaker)

  2. 基于高級失敗率(滑動窗口)的熔斷器(Advanced Circuit Breaker)

熔斷器狀態需要跨多個調用共享,因此通常將熔斷器策略實例聲明為靜態或通過依賴注入容器注入(單例生命周期)。

BasicCircuitBreaker代碼演示

  // 靜態熔斷器實例(狀態持久化)private static readonly AsyncCircuitBreakerPolicy _circuitBreaker = Policy.Handle<Exception>().CircuitBreakerAsync(exceptionsAllowedBeforeBreaking: 4,durationOfBreak: TimeSpan.FromSeconds(30),onBreak: (ex, breakDelay) =>{Debug.WriteLine($"熔斷開啟!持續 {breakDelay.TotalSeconds} 秒。");},onReset: () =>{Debug.WriteLine("熔斷關閉,恢復正常請求。");},onHalfOpen: () =>{Debug.WriteLine("熔斷器進入半開狀態,嘗試恢復。");});
       /// <summary>/// 熔斷策略[基于連續失敗次數的熔斷器]/// </summary>/// <param name="url">請求API</param>/// <returns></returns>[HttpGet]public async Task<ReturnMessageModel<string>> BasicCircuitBreakPolicy(string url) {// 重試策略var retryPolicy = Policy.Handle<Exception>().RetryAsync(5, (ex, qty) => {Thread.Sleep(100);Debug.WriteLine($"當前重試次數為 {qty} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}");return Task.CompletedTask;});// 先重試 再熔斷 最后降級服務var fallbackPolicy = Policy<string>.Handle<Exception>().FallbackAsync("先熔斷降級策略結果", onFallbackAsync: _ => {Debug.WriteLine($"降級策略將要執行 {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}");return Task.CompletedTask;}).WrapAsync(_circuitBreaker.WrapAsync(retryPolicy));string res = await fallbackPolicy.ExecuteAsync(async() =>{using (HttpClient client = new HttpClient()){HttpResponseMessage message = await client.GetAsync(url);string messageStr=await message.Content.ReadAsStringAsync();return messageStr;}});return new ReturnMessageModel<string>(res); }

在這里插入圖片描述

Advanced Circuit Breaker代碼演示,將上述的基礎異常次數_circuitBreaker熔斷器換成_advancedCircuitBreaker

   private static readonly AsyncCircuitBreakerPolicy _advancedCircuitBreaker = Policy.Handle<Exception>().AdvancedCircuitBreakerAsync(failureThreshold: 0.5, // 失敗率閾值(50%)samplingDuration: TimeSpan.FromSeconds(10), // 采樣時間窗口(10秒)minimumThroughput: 5, // 最小吞吐量(10秒內至少8個請求)durationOfBreak: TimeSpan.FromSeconds(30), // 熔斷持續時間onBreak: (ex, breakDelay) =>{Debug.WriteLine($"熔斷開啟!持續 {breakDelay.TotalSeconds} 秒。");},onReset: () =>{Debug.WriteLine("熔斷關閉,恢復正常請求。");},onHalfOpen: () =>{Debug.WriteLine("熔斷器進入半開狀態,嘗試恢復。");});

在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/91852.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/91852.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/91852.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【機器學習深度學習】大模型推理速度與私有化部署的價值分析

目錄 前言 一、主流推理框架速度對比 二、為什么 HuggingFace 框架更適合微調驗證&#xff1f; 三、大模型私有化部署的必要性分析 ? 私有化部署的主要動因 1. 數據隱私與業務安全 2. 可控性與性能保障 ? 哪些情況不建議私有部署&#xff1f; 四、總結與選型建議 &…

elementui-admin構建

1、vue-element-admin vue-element-admin是基于element-ui 的一套后臺管理系統集成方案。 功能&#xff1a;介紹 | vue-element-adminA magical vue adminhttps://panjiachen.github.io/vue-element-admin-site/zh/guide/# GitHub地址&#xff1a;https://github.com/PanJia…

深入排查:編譯環境(JDK)與運行環境(JRE/JDK)不一致時的常見 Java 錯誤及解決方案

深入排查&#xff1a;編譯環境&#xff08;JDK&#xff09;與運行環境&#xff08;JRE/JDK&#xff09;不一致時的常見 Java 錯誤及解決方案 在后端 Java 項目中&#xff0c;編譯環境&#xff08;JDK&#xff09; 與 運行環境&#xff08;JRE/JDK&#xff09; 版本不一致&…

[JS逆向] 微信小程序逆向工程實戰

博客配套代碼與工具發布于github&#xff1a;微信小程序 &#xff08;歡迎順手Star一下?&#xff09; 相關爬蟲專欄&#xff1a;JS逆向爬蟲實戰 爬蟲知識點合集 爬蟲實戰案例 逆向知識點合集 前言&#xff1a; 微信小程序對于很多嘗試JS逆向的人群來說&#xff0c;都是一個…

基于5G系統的打孔LDPC編碼和均勻量化NMS譯碼算法matlab性能仿真

目錄 1.引言 2.算法仿真效果演示 3.數據集格式或算法參數簡介 4.算法涉及理論知識概要 4.1打孔技術 4.2 均勻量化NMS譯碼 5.參考文獻 6.完整算法代碼文件獲得 1.引言 在5G通信系統中&#xff0c;信道編碼技術是保障高速率、高可靠性數據傳輸的核心支撐&#xff0c;而低…

基于Java標準庫讀取CSV實現天地圖POI分類快速導入PostGIS數據庫實戰

目錄 前言 一、天地圖POI分類簡介 1、數據表格 2、分類結構 二、從CSV導入到PG數據庫 1、CSV解析流程 2、數據轉換及入庫 3、入庫成果及檢索 三、總結 前言 在之前的博客中&#xff0c;曾經對高德地圖和百度地圖的POI分類以及使用PostGIS數據庫來進行管理的模式進行了詳…

人-AI交互中的信息論不同于傳統的信息論,其信息的增量≠不確定性的減量

在人機交互&#xff08;Human-AI Interaction, HAI&#xff09;領域&#xff0c;信息論的應用確實與傳統的信息論有所不同。這種差異主要源于人機交互HAI中信息的復雜性、動態性以及人類認知的特點。1. 傳統信息論的核心概念傳統信息論由克勞德香農&#xff08;Claude Shannon&…

K8s 通過 Scheduler Extender 實現自定義調度邏輯

1. 為什么需要自定義調度邏輯 什么是所謂的調度? 所謂調度就是指給 Pod 對象的 spec.nodeName 賦值 待調度對象則是所有 spec.nodeName 為空的 Pod 調度過程則是從集群現有的 Node 中為當前 Pod 選擇一個最合適的 實際上 Pod 上還有一個平時比較少關注的屬性&#xff1a;…

7.19 換根dp | vpp |滑窗

lcr147.最小棧通過兩個棧 維護實現class MinStack { public:stack<int> A, B;MinStack() {}void push(int x) {A.push(x);if(B.empty() || B.top() > x)B.push(x);}void pop() {if(A.top() B.top())B.pop();A.pop();}int top() {return A.top();}int getMin() {retur…

以太坊的心臟與大腦:詳解執行客戶端(EL)與共識客戶端(CL)

好的&#xff0c;各位技術同道&#xff0c;歡迎再次光臨我的博客。在上一篇文章中&#xff0c;我們聊了如何搭建一個以太坊測試節點&#xff0c;并提到了節點需要同時運行“執行客戶端”和“共識客戶端”。很多朋友對此表示了濃厚興趣&#xff0c;想深入了解這兩者究竟是什么&a…

Debian-10,用glibc二進制預編譯包,安裝Mysql-5.7.44 筆記250716

Debian-10,用glibc二進制預編譯包,安裝Mysql-5.7.44 筆記250716 &#x1f4e6; 一步腳本 #!/bin/bash### 安裝依賴 apt install -y libaio1 libnuma1 libncurses5### 下載MySQL-5.7.44 的 glib二進制包: mysql-5.7.44-linux-glibc2.12-x86_64.tar.gz ,(如果不存在) mkdir…

用邏輯回歸(Logistic Regression)處理鳶尾花(iris)數據集

# 導入必要的庫 import numpy as np import pandas as pd import matplotlib.pyplot as plt import seaborn as sns from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split from sklearn.linear_model import LogisticRegression from…

華大北斗TAU1201-1216A00高精度雙頻GNSS定位模塊 自動駕駛專用

在萬物互聯的時代&#xff0c;您還在為定位不準、信號丟失而煩惱嗎&#xff1f;TAU1201-1216A00華大北斗高精度定位模塊TAU1201是一款高性能的雙頻GNSS定位模塊&#xff0c;搭載了華大北斗的CYNOSURE III GNSS SoC 芯片&#xff0c;該模塊支持新一代北斗三號信號體制&#xff0…

堅持繼續布局32位MCU,進一步完善產品陣容,96Mhz主頻CW32L012新品發布!

在全球MCU市場競爭加劇、國產替代加速的背景下&#xff0c;嵌入式設備對核心控制芯片的性能、功耗、可靠性及性價比提出了前所未有的嚴苛需求。為適應市場競爭&#xff0c;2025年7月16日&#xff0c;武漢芯源半導體正式推出基于CW32L01x系列低功耗微控制器家族的全新成員&#…

用線性代數推導碼分多址(CDMA)

什么是碼分多址 碼分多址&#xff1a;CDMA允許多個用戶同時、在同一頻率上傳輸數據。它通過給每個用戶分配唯一的、相互正交的二進制序列來實現區分。用戶的數據比特被這個碼片序列擴展成一個高速率的信號&#xff0c;然后在接收端通過相同的碼片序列進行相關運算來回復原數據 …

mac 配置svn

1.查看brew的版本&#xff1a;brew install subversion2.安裝brew命令&#xff1a;bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"3.把路徑添加到path環境變量&#xff1a;echo export PATH"/opt/homebrew/b…

使用 .NET Core 的原始 WebSocket

在 Web 開發中&#xff0c;后端存在一些值得注意的通信協議&#xff0c;用于將更改通知給已連接的客戶端。所有這些協議都用于處理同一件事。但鮮為人知的協議很少&#xff0c;鮮為人知的協議也很少。今天&#xff0c;將討論 WebSocket&#xff0c;它在開發中使用最少&#xff…

編程實現Word自動排版:從理論到實踐的全面指南

在現代辦公環境中&#xff0c;文檔排版是一項常見但耗時的工作。特別是對于需要處理大量文檔的專業人士來說&#xff0c;手動排版不僅費時費力&#xff0c;還容易出現不一致的問題。本文將深入探討如何通過編程方式實現Word文檔的自動排版&#xff0c;從理論基礎到實際應用&…

力扣經典算法篇-25-刪除鏈表的倒數第 N 個結點(計算鏈表的長度,利用棧先進后出特性,雙指針法)

1、題干 給你一個鏈表&#xff0c;刪除鏈表的倒數第 n 個結點&#xff0c;并且返回鏈表的頭結點。 示例 1&#xff1a;輸入&#xff1a;head [1,2,3,4,5], n 2 輸出&#xff1a;[1,2,3,5] 示例 2&#xff1a; 輸入&#xff1a;head [1], n 1 輸出&#xff1a;[] 示例 3&…

VIT速覽

當我們取到一張圖片&#xff0c;我們會把它劃分為一個個patch&#xff0c;如上圖把一張圖片劃分為了9個patch&#xff0c;然后通過一個embedding把他們轉換成一個個token&#xff0c;每個patch對應一個token&#xff0c;然后在輸入到transformer encoder之前還要經過一個class …