c# 如何在c#中实现断路器(Circuit Breaker)模式
发布时间 - 2026-01-04 00:00:00 点击率:次直接用 Polly 而非手写断路器,因其线程安全、状态严谨、已深度集成生态;手写易致并发探测异常或内存泄漏,Polly 支持 HttpClient 原生集成及自定义策略组合与状态监听。
为什么直接用 Polly 而不是手写断路器
手写一个线程安全、状态切换严谨、支持超时/重试/降级的断路器非常容易出错。比如 CircuitState.HalfOpen 下并发请求可能触发多次探测,或计时器未正确清理导致内存泄漏。生产环境建议直接用成熟库——Polly 是 .NET 生态事实标准,已深度适配 IHttpClientFactory 和 Microsoft.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攻击?(原理和示例)


Name}");
},
onReset: () => Console.WriteLine("Circuit reset"),
onHalfOpen: () => Console.WriteLine("Circuit half-open: allowing one probe"));