c# 如何在c#中实现断路器(Circuit Breaker)模式

发布时间 - 2026-01-04 00:00:00    点击率:
直接用 Polly 而非手写断路器,因其线程安全、状态严谨、已深度集成生态;手写易致并发探测异常或内存泄漏,Polly 支持 HttpClient 原生集成及自定义策略组合与状态监听。

为什么直接用 Polly 而不是手写断路器

手写一个线程安全、状态切换严谨、支持超时/重试/降级的断路器非常容易出错。比如 CircuitState.HalfOpen 下并发请求可能触发多次探测,或计时器未正确清理导致内存泄漏。生产环境建议直接用成熟库——Polly 是 .NET 生态事实标准,已深度适配 IHttpClientFactoryMicrosoft.Extensions.DependencyInjection

安装与基础用法:Polly + AddCircuitBreaker

从 .NET 6 开始,Microsoft.Extensions.Http.Resilience 提供了原生集成(基于 Polly),推荐优先使用:

dotnet add package Microsoft.Extensions.Http.Resilience

Program.cs 中注册:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpClient()
    .AddCircuitBreaker(policy => policy
        .HandledStatusCodes(500, 502, 503, 504)
        .FailureThreshold(0.3) // 连续失败率阈值
        .SamplingDuration(TimeSpan.FromSeconds(30))
        .MinimumThroughput(10) // 每 30 秒至少 10 次调用才触发统计
        .BreakDuration(TimeSpan.FromMinutes(1))); // 熔断时长

关键点:

  • FailureThreshold 不是固定次数,而是失败率;低流量下即使只失败 1 次也可能不触发熔断(因未达 MinimumThroughput
  • BreakDuration 是“硬暂停”,期间所有请求直接抛 BrokenCircuitException,不会转发
  • 该配置仅对 HttpClient 生效;若需保护普通方法(如数据库访问),仍需手动包装 Policy

保护非 HTTP 方法:用 Policy.WrapAsync 组合策略

比如封装一个可能抛异常的仓储方法:

private readonly AsyncCircuitBreakerPolicy _circuitBreaker = Policy
    .Handle(ex => ex.Number is 1205 or 1222) // 死锁/超时
    .Or()
    .CircuitBreakerAsync(
        exceptionsAllowedBeforeBreaking: 3,
        durationOfBreak: TimeSpan.FromMinutes(2));

调用时必须显式包裹:

try
{
    await _circuitBreaker.ExecuteAsync(async () => await _repository.FetchDataAsync());
}
catch (BrokenCircuitException)
{
    // 返回缓存或默认值
    return _cache.GetOrAdd("fallback", _ => new List());
}

注意:

  • 不要把 ExecuteAsync 写在循环里——每次调用都计入熔断统计,高频调用会快速触发熔断
  • exceptionsAllowedBeforeBreaking 是绝对次数,和时间窗口无关;适合低频、高价值操作(如支付确认)
  • 若需同时加重试,用 Policy.WrapAsync(retryPolicy, circuitBreaker),顺序很重要:外层是熔断器,内层是重试

自定义状态监听与诊断:别只靠日志

熔断器状态变化(如 Open → HalfOpen)是关键信号,但默认不输出。启用监听:

var breaker = Policy
    .Handle()
    .CircuitBreakerAsync(3, TimeSpan.FromMinutes(1),
        onBreak: (ex, ts) => {
            Console.WriteLine($"Circuit broken for {ts.TotalMinutes} min due to {ex.GetType().Name}");
        },
        onReset: () => Console.WriteLine("Circuit reset"),
        onHalfOpen: () => Console.WriteLine("Circuit half-open: allowing one probe")); 

生产环境应将这些回调对接到指标系统(如 Prometheus 的 counter),而不是仅打印日志。特别注意 onHalfOpen——它只在第一个试探请求前触发,不代表试探成功。

真正难的是状态同步:分布式场景下,单机熔断器无法共享状态。这时得上 Redis 或专用服务(如 Resilience4j 的集中式断路器),Polly 默认不解决这个问题。


# redis  # app  # ai  # win  # microsoft  # c#  # 并发请求  # .net  # 为什么  # red  # 分布式  # 封装  # 循环  # 线程  # 并发  # 数据库  # http  # prometheus  # 重试  # 自定义  # 死锁  # 的是  # 而不是  # 若需  # 第一个  # 失败率  # 计时器  # 不代表 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: 如何快速生成ASP一键建站模板并优化安全性?  JavaScript实现Fly Bird小游戏  如何用PHP快速搭建高效网站?分步指南  laravel怎么用DB facade执行原生SQL查询_laravel DB facade原生SQL执行方法  IOS倒计时设置UIButton标题title的抖动问题  猪八戒网站制作视频,开发一个猪八戒网站,大约需要多少?或者自己请程序员,需要什么程序员,多少程序员能完成?  Laravel Blade模板引擎语法_Laravel Blade布局继承用法  JavaScript如何实现音频处理_Web Audio API如何工作?  Laravel如何生成API文档?(Swagger/OpenAPI教程)  Laravel如何获取当前登录用户信息_Laravel Auth门面使用与Session用户读取【技巧】  Android中Textview和图片同行显示(文字超出用省略号,图片自动靠右边)  深圳网站制作平台,深圳市做网站好的公司有哪些?  Laravel如何生成PDF或Excel文件_Laravel文档导出工具与使用教程  Python正则表达式进阶教程_复杂匹配与分组替换解析  ai格式如何转html_将AI设计稿转换为HTML页面流程【页面】  在centOS 7安装mysql 5.7的详细教程  java ZXing生成二维码及条码实例分享  Laravel如何实现API速率限制?(Rate Limiting教程)  laravel服务容器和依赖注入怎么理解_laravel服务容器与依赖注入解析  PythonWeb开发入门教程_Flask快速构建Web应用  Laravel如何处理文件下载请求?(Response示例)  php中::能调用final静态方法吗_final修饰静态方法调用规则【解答】  Win11怎么开启自动HDR画质_Windows11显示设置HDR选项  独立制作一个网站多少钱,建立网站需要花多少钱?  详解jQuery中的事件  制作旅游网站html,怎样注册旅游网站?  ,怎么在广州志愿者网站注册?  Laravel怎么处理异常_Laravel自定义异常处理与错误页面教程  青岛网站建设如何选择本地服务器?  Laravel怎么返回JSON格式数据_Laravel API资源Response响应格式化【技巧】  网站设计制作书签怎么做,怎样将网页添加到书签/主页书签/桌面?  Laravel怎么做数据加密_Laravel内置Crypt门面的加密与解密功能  如何在腾讯云服务器快速搭建个人网站?  Laravel全局作用域是什么_Laravel Eloquent Global Scopes应用指南  网站制作价目表怎么做,珍爱网婚介费用多少?  edge浏览器无法安装扩展 edge浏览器插件安装失败【解决方法】  Laravel怎么上传文件_Laravel图片上传及存储配置  如何快速搭建FTP站点实现文件共享?  Laravel如何实现数据导出到CSV文件_Laravel原生流式输出大数据量CSV【方案】  PHP 实现电台节目表的智能时间匹配与今日/明日轮播逻辑  高防服务器如何保障网站安全无虞?  图册素材网站设计制作软件,图册的导出方式有几种?  Laravel怎么实现模型属性的自动加密  如何快速生成橙子建站落地页链接?  bootstrap日历插件datetimepicker使用方法  html文件怎么打开证书错误_https协议的html打开提示不安全【指南】  如何在阿里云ECS服务器部署织梦CMS网站?  如何快速重置建站主机并恢复默认配置?  胶州企业网站制作公司,青岛石头网络科技有限公司怎么样?  Laravel如何保护应用免受CSRF攻击?(原理和示例)