You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 15:57:17