Azure App Service连接Azure SQL间歇性耗尽连接池问题排查求助
解决Azure App Service中.NET 6应用的SQL连接池耗尽问题
问题描述
基于.NET 6构建的应用部署在Azure App Service,连接Azure SQL数据库执行读写操作,多数情况正常,但偶尔会出现连接池耗尽错误,错误信息如下:
Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool.
This may have occurred because all pooled connections were in use and max pool size was reached.
问题持续数分钟后自行恢复,已完成以下排查:
- 确认代码未不必要打开过多连接
- 所有连接均通过
using正确关闭 - Azure SQL服务器无资源使用峰值
- 连接池最大连接数已提升至250,但仍每1-2天间歇性发作
排查与解决方案
1. 追踪连接生命周期,定位泄漏点
虽然示例代码中使用using确保连接释放,但仍可能存在未覆盖的场景(如静态变量存储连接、异步操作未正确await等)。添加自定义日志追踪每个连接的创建与释放:
修改连接获取方法,添加创建日志:
protected DbConnection GetOpenConnection() { var connection = new SqlConnection(configurationProvider.ConnectionString); connection.Open(); _logger.LogInformation("创建SQL连接 {ConnId},时间:{Time}", connection.ClientConnectionId, DateTime.UtcNow); return connection; }
在使用连接的方法中添加释放日志:
public int? GetUncommitedFilesCount(string machineName) { using (var connection = GetOpenConnection()) { try { // 原有查询逻辑 var command = connection.CreateCommand(); command.CommandText = @"Select UncommittedFilesCount from Machine Where MachineName = @MachineName"; var parameter = command.CreateParameter(); parameter.ParameterName ="@MachineName"; parameter.Value = machineName; command.Parameters.Add(parameter); var result = command.ExecuteScalar(); return result == null ? null : Convert.ToInt32(result); } finally { _logger.LogInformation("释放SQL连接 {ConnId},时间:{Time}", connection.ClientConnectionId, DateTime.UtcNow); } } }
通过App Insights查看日志,对比连接创建与释放的时间差,找出长时间未释放的连接,定位对应的业务逻辑。
2. 用SQL Server DMV分析连接状态
在问题发作时,执行以下查询查看Azure SQL的连接详情,判断是连接泄漏还是长时间占用:
SELECT c.session_id, c.connect_time, DATEDIFF(second, c.last_read, GETDATE()) AS idle_seconds, c.status, s.program_name, s.host_name, t.text AS last_executed_query FROM sys.dm_exec_connections c JOIN sys.dm_exec_sessions s ON c.session_id = s.session_id LEFT JOIN sys.dm_exec_requests r ON c.session_id = r.session_id OUTER APPLY sys.dm_exec_sql_text(r.sql_handle) t WHERE s.program_name LIKE '%你的应用程序名%'
- 若存在大量
status = 'sleeping'且idle_seconds超过连接池Idle Timeout(默认60秒)的连接,说明连接池回收机制异常,需调整Idle Timeout参数。 - 若存在
status = 'running'且执行时间过长的连接,说明查询或事务耗时过久,需优化业务逻辑。
3. 优化查询与事务,减少连接占用时间
- 添加索引:针对示例中的查询,为
MachineName字段创建包含查询字段的索引,加快查询速度:CREATE NONCLUSTERED INDEX IX_Machine_MachineName ON Machine(MachineName) INCLUDE(UncommittedFilesCount); - 缩短事务时长:避免在事务中包含非数据库操作(如调用外部API、文件IO),确保事务尽快提交/回滚。
- 异步操作规范:所有异步数据库操作必须使用
await,避免因线程阻塞导致连接长时间占用。
4. 调整连接池参数适配业务场景
在连接字符串中调整以下参数(根据实际负载调整):
Server=tcp:yourserver.database.windows.net,1433;Initial Catalog=yourdb;User ID=youruser;Password=yourpassword;Encrypt=True; Max Pool Size=250; Connect Timeout=30; -- 延长连接等待时间,避免快速超时 Idle Timeout=30; -- 缩短空闲连接回收时间,释放池资源 Min Pool Size=5; -- 保留少量空闲连接,减少创建开销
5. 检查Azure SQL连接数限制
Azure SQL数据库的连接数受DTU/vCore规格限制:
- Basic DTU:最大300连接
- Standard S0:最大1200连接
- 更高规格的实例连接数上限更高
在Azure门户查看SQL数据库的连接数指标,若接近上限,需升级SQL实例规格,或优化应用连接复用策略。
内容的提问来源于stack exchange,提问作者Matthew van Boheemen
相关产品推荐
相关产品推荐

