当前位置: 首页 > news >正文

分布式弹性故障处理框架——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.lryc.cn/news/589972.html

相关文章:

  • PyCharm(入门篇)
  • Python设计模式深度解析:建造者模式(Builder Pattern)完全指南
  • vivo S30评测:用设计诠释科技,以性能书写情怀
  • Git版本控制完全指南:从入门到精通
  • RoMa: Robust Dense Feature Matching论文精读(逐段解析)
  • 【Call For Paper| EI会议】第五届计算机图形学、人工智能与数据处理国际学术会议 (ICCAID 2025)
  • Weblogic历史漏洞利用
  • 5.Java类与对象
  • SenseGlove力反馈手套:医疗、生产制造、军事模拟与远程机器人控制新革命
  • python基础语法9,用os库实现系统操作并用sys库实现文件操作(简单易上手的python语法教学)
  • 【人工智能99问】损失函数有哪些,如何选择?(6/99)
  • Matlab数字信号处理——基于谱减法与LMS自适应滤波的语音增强系统设计与实现
  • 项目管理——产品开发项目管理办法参考模板
  • 评估遥感云雾浓度的无参化指标(适用于其它合成雾的场景)
  • 【语音技术】影视技能实现方法详细介绍
  • 数据结构--准备知识
  • SSM框架学习——day3
  • 二代身份证识别技术的发展:从机器学习到深度学习
  • RocketMQ性能优化实战指南:原理与实践
  • WebSocket 防护的重要性及应对策略:从原理到实战
  • Java 二维数组详解:从基础语法到实战应用,彻底掌握多维数据结构
  • Cursor 接入api中转平台流程
  • es 启动中的一些记录
  • 【Deepseek-R1+阿里千问大模型】四步完成本地调用本地部署大模型和线上大模型,实现可视化使用
  • web前端用MVP模式搭建项目
  • 外网访问禅道软件项目管理系统,简单几步将本地内网IP端口设置互联网在线用
  • 第3章 Excel表格格式设置技巧
  • Node.js:创建第一个应用
  • 重塑旧物价值,引领绿色潮流——二手回收小程序系统开发纪实
  • 小程序中状态管理Redux