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

从 IApplicationBuilder 到 RequestDelegate:ASP.NET Core 请求管线的性能与可观测性实战 - ryan

很多团队做性能优化时,第一反应是改 SQL、加缓存、扩机器。结果接口还是慢,而且慢得不稳定。

这类问题里,有一部分根因并不在业务代码,而在请求进入业务之前就已经产生了: 中间件顺序、重复序列化、过重日志、异常处理位置不当,都会把每个请求的固定成本悄悄抬高。

这篇文章我们不讲抽象概念,直接从一个真实工程场景出发,拆开 ASP.NET Core 请求管线,回答三个问题:

  • 请求管线到底是怎么执行的
  • 哪些中间件写法会稳定拉低吞吐
  • 如何在不牺牲可观测性的前提下,把链路成本控制住

1. 问题背景: 为什么明明 CPU 不高,RT 却在抖

先看一个常见现象:

  • 峰值时段 P95 从 35ms 涨到 90ms
  • CPU 只到 45%
  • 数据库监控正常
  • 线程池没有明显爆满

像商场收银台排队: 收银员速度没变,库存系统也没卡,但每位顾客在真正结账前都要先填两张表、复印一次小票、走一段绕路。单人多花 10 秒,队伍就会在高峰时段整体失控。

在 Web 服务里,这段“真正结账前的绕路”就是请求管线上的固定开销。

典型问题包括:

  • 将高成本日志中间件放在链路最前面,且对所有请求都做完整 Body 记录
  • 鉴权、异常处理、路由等中间件顺序错误,导致重复执行或额外分支判断
  • 在中间件中做同步阻塞 I/O
  • 将一些本该按采样写出的指标,变成了每请求都完整打点

2. 原理解析: IApplicationBuilder 如何变成 RequestDelegate

ASP.NET Core 启动时,IApplicationBuilder 会把你注册的中间件构造成一个 RequestDelegate 链。

关键点只有两个,但经常被忽略:

  1. 中间件按“注册顺序”进入,按“逆序”包裹执行。每个中间件把后续链路作为自己的 next,形成嵌套闭包。
  2. 任意中间件都可以不调用 next(),从而短路后续链路。

一个简化模型如下:

RequestDelegate app = context => Task.CompletedTask;app = MiddlewareC(app);
app = MiddlewareB(app);
app = MiddlewareA(app);// 实际执行顺序: A -> B -> C -> Endpoint -> C -> B -> A

这意味着:

  • 前置中间件越重,所有请求都要付出这笔成本
  • 末端短路逻辑的位置决定了多少中间件能被跳过
  • 可观测性埋点放在不同层,看到的是不同粒度与成本

常见顺序误区

  • UseRouting() 之前做基于 Endpoint 元数据的判断: 信息还没解析出来
  • 在全局异常处理中间件之后再包一层局部 try/catch: 导致异常路径重复记录
  • 在静态资源请求也走完整业务日志链路: 无效开销

3. 示例代码: 从“能跑”到“跑得稳”

下面先看一个“看起来没问题,但成本偏高”的写法。

using System.Diagnostics;
using Microsoft.AspNetCore.HttpLogging;var builder = WebApplication.CreateBuilder(args);builder.Services.AddHttpLogging(options =>
{options.LoggingFields = HttpLoggingFields.All;
});var app = builder.Build();app.UseHttpLogging(); // 对所有请求做重日志,静态文件也不例外
app.Use(async (ctx, next) =>
{var sw = Stopwatch.StartNew();await next();sw.Stop();// 每请求都写详细日志,高并发下会有明显写放大app.Logger.LogInformation("{Path} took {Elapsed}ms", ctx.Request.Path, sw.Elapsed.TotalMilliseconds);
});app.UseRouting();
app.MapGet("/ping", () => Results.Ok("pong"));app.Run();

再看一版更适合线上场景的写法。

using System.Diagnostics;
using Microsoft.AspNetCore.RateLimiting;var builder = WebApplication.CreateBuilder(args);builder.Services.AddOpenApi();
builder.Services.AddRateLimiter(options =>
{options.AddFixedWindowLimiter("api", limiter =>{limiter.Window = TimeSpan.FromSeconds(1);limiter.PermitLimit = 200;limiter.QueueLimit = 100;limiter.AutoReplenishment = true;});
});var app = builder.Build();app.UseExceptionHandler("/error");
app.UseRouting();
app.UseRateLimiter();// 仅对 API 路径做轻量计时,并且避免记录敏感/大体积内容
app.UseWhen(ctx => ctx.Request.Path.StartsWithSegments("/api"),branch =>{branch.Use(async (ctx, next) =>{var start = Stopwatch.GetTimestamp();await next();var elapsedMs = (Stopwatch.GetTimestamp() - start) * 1000d / Stopwatch.Frequency;if (elapsedMs > 50){app.Logger.LogWarning("slow request {Method} {Path} {StatusCode} {ElapsedMs:F2}ms",ctx.Request.Method,ctx.Request.Path,ctx.Response.StatusCode,elapsedMs);}});});app.MapGet("/error", () => Results.Problem("unexpected error"));app.MapGroup("/api").RequireRateLimiting("api").MapGet("/orders/{id:int}", (int id) => Results.Ok(new { id, status = "Paid" }));app.MapGet("/health", () => Results.Ok("ok"));app.Run();

这版改动的核心不是“少写几个中间件”,而是:

  • 明确将异常处理放在统一入口
  • 将高成本观测从“全量”调整到“有条件采样/告警”
  • 让非 API 请求不走完整业务观测链
  • 将限流作为入口保护,避免高峰把后端拖垮

4. 工程实践建议: 性能和可观测性不是二选一

4.1 给中间件分层,而不是平铺

建议按职责分为三层:

  • 入口治理层: 异常处理、限流、基础安全
  • 路由与授权层: 路由、认证、授权
  • 业务观测层: 业务日志、慢请求告警、特定埋点

这样做的好处是顺序稳定,审查成本低,新人也不容易“插错位置”。

4.2 指标全量,日志分级

  • 指标(如请求总量、P95、错误率)建议全量
  • 明细日志建议按状态码、耗时阈值、采样率输出

全量日志在中高流量场景会迅速放大 I/O 成本,最后变成“为了观测而损失性能”。

4.3 用工具验证,不靠体感

至少建立这套最小验证闭环:

  • 压测: bombardierwrk
  • 运行时计数器: dotnet-counters monitor --process-id <pid>
  • 分布式追踪: OpenTelemetry + Jaeger/Tempo

先拿到基线,再改顺序,再对比 P95/P99 和吞吐,不要只看平均值。

4.4 中间件评审清单(可直接落地)

每次新增中间件前,团队至少回答 4 个问题:

  • 是否必须作用于所有请求
  • 失败时是否会影响主链路可用性
  • 是否涉及同步阻塞 I/O
  • 观测收益是否大于新增成本

5. 总结

ASP.NET Core 请求管线的优化,本质上是控制“每个请求必须支付的固定成本”。

IApplicationBuilderRequestDelegate 的构建机制决定了中间件顺序就是性能策略。把顺序理顺、把观测做轻、把入口治理做实,通常比“盲目微优化业务代码”更快见效。

如果你线上也出现过“CPU 不高但接口发抖”的情况,建议先做两件事:

  • 把现有中间件按执行顺序画出来
  • 按慢请求阈值重新设计日志输出策略

很多时候,系统的稳定性拐点,就在这两步里。

http://www.jsqmd.com/news/453185/

相关文章:

  • Java二维码
  • 2026武汉公装装修实力推荐:武汉信为装饰工程有限公司,厂房/店铺/餐饮/写字楼全系公装解决方案 - 品牌推荐官
  • 2026东莞深圳自动售货机TOP6口碑推荐|莞深无人无人售货机厂家优选推荐 - 品牌智鉴榜
  • 2026年3月郑州喷码机/激光喷码机/打标机/贴标机/生产日期喷码机厂家哪家好 - 2026年企业推荐榜
  • 2026年 南通开发区猫科诊疗机构推荐榜:专业宠物医院与特色治疗服务深度解析 - 品牌企业推荐师(官方)
  • 详细介绍:第十四课:Redis 在后端到底扮演什么角色?——缓存模型全景图
  • 记一次 .NET 某低代码开发框架 内存暴涨分析
  • kde nero启动后提示检测到设置了 GTK_IM_MODULE 和 QT_IM_MODULE
  • 2026年湖南专业家装公司价格大揭秘,旧房翻新费用多少钱 - 工业品网
  • 聊聊2026年预制直埋保温管性价比高的供应商排名,集中供热必备 - 工业设备
  • 2026年广州口碑不错的360航空软包汽车脚垫供应商,哪家值得选 - 工业品牌热点
  • 2026年 南通崇川区异宠医院推荐榜:环境优越、专业诊疗与暖心服务的口碑之选 - 品牌企业推荐师(官方)
  • 聊聊福安客厅沙发优质供应商,哪家品牌值得推荐? - mypinpai
  • 总结2026年厦门高压发电机出租排名前十的公司 - 工业品网
  • 2026年松筒线生产厂推荐,靠谱的品牌有哪些? - myqiye
  • 2026年高强缝纫线耐磨厂家哪家性价比高,中祥线业实力揭秘 - 工业推荐榜
  • 2026年聊聊全国靠谱的螺杆泵认证厂家,螺杆泵性价比哪家高 - 工业品牌热点
  • 研发测试质量规范(草稿)
  • 2026年泉州性价比高的仿古砖龙头制造商排名,好用品牌大盘点 - mypinpai
  • 中电金信:规范与灵活兼得,让数据模型更“好用”
  • 2026年松筒线制造企业十大排名,松筒线来样定制服务靠谱吗 - myqiye
  • 2026年靠谱的垃圾桶源头厂家有哪些,专业的垃圾桶公司费用多少 - 工业推荐榜
  • 保温管制造企业怎么选,河北宝温管道性价比值得考虑吗 - 工业设备
  • 聊聊杭州地区靠谱的保温管专业制造商,费用怎么收取? - 工业设备
  • 2026年全国小型电动环卫车哪家靠谱?技术成熟 专业服务适配各类需求 - 深度智识库
  • 2026年分析理发器厂商,广州艾渼为何口碑这么好 - 工业品网
  • 2026年评价高的市政护栏厂家推荐:防撞护栏公司口碑推荐 - 行业平台推荐
  • 2026年评价高的护栏厂家推荐:桥梁护栏/临时护栏厂家选择指南 - 行业平台推荐
  • 信息系统项目管理师-归纳
  • AI元人文:空论——指月之间