Azure部署的.NET Core 2.0 Web API出现TCP连接泄漏问题
排查Azure上ASP.NET Core Web API的TCP连接泄漏问题
我之前帮不少团队解决过Azure App Service里TCP连接持续增长的问题,结合你提到的技术栈(ASP.NET Core MVC、EF Core、SignalR),咱们一步步拆解排查方向,精准定位问题:
1. 先明确是哪种连接在泄漏
首先得搞清楚增长的TCP连接到底是HTTP/SignalR的客户端连接,还是EF Core的数据库连接。Azure有现成的监控可以帮你快速区分:
- 登录Azure门户,进入你的App Service,打开「监控」->「指标」:
- 查看
TCP Connections(总TCP连接数)的趋势 - 同时查看
Http Connections(HTTP活跃连接数)和WebSocket Connections(SignalR的WebSocket连接数)
- 查看
- 如果用的是Azure SQL数据库,去对应的SQL资源里查看
Active Connections指标
对比这些指标的增长趋势,就能快速定位是哪类连接出了问题。
2. 排查SignalR WebSocket连接泄漏
SignalR的WebSocket连接很容易因为客户端异常断开、清理逻辑不到位导致残留,这是最常见的原因之一:
- 检查Hub的断开逻辑:确保
OnDisconnectedAsync方法正确实现,并且没有吞异常导致框架的默认清理流程中断:public override async Task OnDisconnectedAsync(Exception exception) { try { // 这里放你的业务清理逻辑,比如移除用户-连接ID的映射 await _userConnectionManager.RemoveConnection(Context.ConnectionId); } catch (Exception ex) { // 一定要记录日志,别让异常打断后续的框架清理 _logger.LogError(ex, "Failed to clean up connection {ConnectionId}", Context.ConnectionId); } // 必须调用基类方法,框架会处理底层WebSocket连接的释放 await base.OnDisconnectedAsync(exception); } - 调整SignalR的超时配置:如果客户端网络异常断开,服务器需要及时检测到并释放连接。可以在Startup/Program.cs里调整:
services.AddSignalR(options => { options.KeepAliveInterval = TimeSpan.FromSeconds(10); // 主动发心跳的间隔 options.ClientTimeoutInterval = TimeSpan.FromSeconds(30); // 多久没收到客户端响应就判定断开 }); - 查看WebSocket连接指标:如果
WebSocket Connections和总TCP连接的增长趋势完全一致,那基本可以确定是SignalR连接没正确释放。
3. 排查EF Core数据库连接泄漏
EF Core默认用连接池,但如果使用不当,也会导致连接被长期占用无法回收:
- 检查DbContext的使用方式:绝对不要手动
new MyDbContext()却不释放,也不要在using块之外持有DbContext实例。正确的做法是依赖注入(框架自动管理生命周期),或者用using包裹:// 推荐:依赖注入DbContext public class MyApiController : ControllerBase { private readonly MyDbContext _dbContext; public MyApiController(MyDbContext dbContext) { _dbContext = dbContext; } } // 手动创建时必须用using using var dbContext = new MyDbContext(_configuration.GetConnectionString("Default")); var data = await dbContext.MyEntities.ToListAsync(); - 检查异步操作是否完整:如果异步方法没加
await,会导致DbContext被长时间持有,连接池无法回收连接。比如:// 错误:没加await,DbContext会被一直占用 _dbContext.MyEntities.AddAsync(new Entity()); // 正确:必须await异步操作 await _dbContext.MyEntities.AddAsync(new Entity()); - 开启EF Core连接日志:可以在配置里开启日志,查看连接的获取和释放情况:
services.AddDbContext<MyDbContext>(options => { options.UseSqlServer(_configuration.GetConnectionString("Default")) .LogTo(message => _logger.LogInformation(message), LogLevel.Information); });
如果Azure SQL的Active Connections和总TCP连接同步增长,那重点排查EF Core的连接使用。
4. 排查ASP.NET Core HTTP连接的异常情况
虽然框架自动管理HTTP连接,但有些自定义逻辑可能会导致连接残留:
- 检查自定义中间件/过滤器:有没有在中间件里持有HttpContext,或者未正确完成请求处理?比如操作
context.Response.Body后没释放,或者异步操作卡住没完成。 - 查看异常请求指标:在App Service的指标里查看
Http 5xx Errors,如果有大量异常请求,可能会导致连接没正常关闭。 - 调整Kestrel连接限制:可以在Program.cs里设置Kestrel的连接上限,避免无限制增长:
builder.WebHost.ConfigureKestrel(options => { options.Limits.MaxConcurrentConnections = 1000; // 根据你的流量调整 options.Limits.MaxConcurrentUpgradedConnections = 500; // WebSocket升级连接的上限 });
5. 用诊断工具深入分析
如果上面的排查还没找到根源,就需要用工具抓更详细的信息:
- Azure内置诊断工具:在App Service的「诊断和解决问题」里搜索「TCP连接」,可以查看当前连接的状态、远程IP、端口,判断是哪些连接在持续增长。
- Application Insights依赖跟踪:启用AI的依赖跟踪,查看所有出站连接(数据库、外部API)的生命周期,有没有未完成的依赖调用。
- dotnet-counters实时监控:在本地或者Azure的SSH会话里运行
dotnet-counters,实时查看Socket连接数和EF Core连接池的使用情况:dotnet-counters monitor --process-id <你的App Service进程ID> --counters System.Net.Sockets,Microsoft.EntityFrameworkCore
按照这个流程一步步排查,应该能快速定位到连接泄漏的根源。
内容的提问来源于stack exchange,提问作者Klaus Rubba
相关产品推荐
相关产品推荐

