ASP.NET Core 性能优化实战
云原生时代,响应速度直接影响成本与用户留存,性能优化已成为业务稳定运行的刚需。用户通常3秒内决定是否离开页面,一个慢接口就可能引发系统雪崩。
ASP.NET Core 默认性能优异,但低效 LINQ 查询、不当内存分配、冗余中间件等问题,会快速侵蚀其性能优势,尤其在云环境中,会直接增加服务器成本、降低系统可靠性。
中间件优化与请求管道调优
中间件管道是请求处理核心,其执行顺序、数量直接决定延迟,优化核心是减少不必要的计算和流转。
执行顺序至关重要
中间件严格按注册顺序执行,核心原则是将可“短路”的中间件(直接处理请求并返回)置于前端,避免后续冗余处理:
var app = builder.Build(); // ✅ 短路优先:无需经过认证、MVC 等复杂处理 app.UseHealthChecks("/health"); // 健康检查,直接返回状态 app.UseStaticFiles(); // 静态文件,直接返回资源 // 安全相关紧随其后 app.UseCors(); app.UseAuthentication(); // 身份认证 app.UseAuthorization(); // 权限校验 // 业务处理放最后 app.MapControllers();移除不必要的中间件
每一个中间件都会增加管道开销,优化第一步是“瘦身”:纯API应用移除UseStaticFiles(),无需会话管理则不注册会话中间件,内部服务可移除UseHttpsRedirection()。
编写轻量级自定义中间件
自定义中间件需避免阻塞调用、高频内存分配和重复查询,尤其在高频请求路径中。
反模式示例——每次请求都查询数据库,频繁分配资源:
// ❌ 反模式:每次请求都查库,重复IO publicclassHeavyMiddleware { privatereadonly RequestDelegate _next; public HeavyMiddleware(RequestDelegate next) => _next = next; public async Task InvokeAsync(HttpContext context) { var bannedIps = await LoadBannedIpsFromDatabase(); if (bannedIps.Contains(context.Connection.RemoteIpAddress?.ToString())) { context.Response.StatusCode = 403; return; } await _next(context); } }优化方案:用缓存减少重复数据库访问,避免高频分配:
// ✅ 优化:缓存结果,降低IO和分配开销 publicclassLeanMiddleware { privatereadonly RequestDelegate _next; privatereadonly IMemoryCache _cache; public LeanMiddleware(RequestDelegate next, IMemoryCache cache) { _next = next; _cache = cache; } public async Task InvokeAsync(HttpContext context) { // 缓存5分钟,仅查库一次 var bannedIps = await _cache.GetOrCreateAsync("banned-ips", async entry => { entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(5); returnawait LoadBannedIpsFromDatabase(); }); if (bannedIps!.Contains(context.Connection.RemoteIpAddress?.ToString())) { context.Response.StatusCode = 403; return; } await _next(context); } }高效使用 async/await
async/await 提升系统吞吐量,但使用不当会增加开销,核心原则:异步用于I/O操作,同步用于CPU计算,避免冗余和阻塞。
避免为简单操作使用 async
纯CPU计算且耗时极短的方法,使用async会生成状态机,增加开销,同步返回即可。
// ❌ 不必要的 async:无I/O操作,纯CPU计算 public async Task<string> GetGreetingAsync(string name) { return await Task.FromResult($"Hello, {name}"); } // ✅ 同步返回,简洁高效 public string GetGreeting(string name) => $"Hello, {name}";在库代码中使用 ConfigureAwait(false)
类库、服务层无需同步上下文的代码中,使用ConfigureAwait(false)可减少线程切换和状态管理开销。
public async Task<Product?> GetProductAsync(int id) { return await _dbContext.Products .AsNoTracking() .FirstOrDefaultAsync(p => p.Id == id) .ConfigureAwait(false); }并行化独立 I/O 调用
多个独立异步I/O操作,用Task.WhenAll并行执行,总耗时等于最慢操作,大幅提升效率。
// ❌ 顺序执行:总耗时 = 两者之和 var user = await _userService.GetUserAsync(userId); var orders = await _orderService.GetOrders