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

SSRS批量生成PDF报表卡顿停滞的问题排查求助

SSRS批量生成PDF报表停滞问题排查与解决建议

场景说明

通过.NET控制台应用,基于WCF对接SQL Server报表服务器,批量生成数百份参数不同的同一份SSRS PDF报表(每份约1MB)。采用基础异步并发方式生成,核心代码如下:

并发任务代码

var listOfTasks = customers
    .Select(async customer =>
    {
        var parameters = new Dictionary<string, string>
        {
            { "CustomerId", customer.Id },
            { "BillDate", billDate }
        };
        await GenerateInvoice(parameters);
    })
    .ToList();

await Task.WhenAll(listOfTasks);

报表生成逻辑

private async Task GenerateInvoice(Dictionary<string, string> parameters)
{
    var reportBytes = await _renderSsrs.ConvertToAsync(
       "\reportPath\InvoiceReport", 
       parameters, 
       FormatType.PDF);

    var filePath = $@"C:\temp\Invoices\Invoice-{parameters["CustomerId"]}.pdf";

    await CreateFileFromBytesAsync(reportBytes, filePath);
}

问题表现

  • 初期约50份报表生成速度正常,后续逐渐变慢直至完全停滞,不再产出PDF
  • SQL Server端存在大量处于睡眠状态、等待命令的开放连接
  • 同一份报表的数据检索时间波动极大
  • 最终进程因「报表执行已过期或无法找到」异常终止
  • 已调整rsreportserver.config中的MaxActiveReqForOneUser从20改为50,无改善;sp_who2未检测到阻塞进程,Profiler数据平稳、CPU活动下降

原因分析

  1. 无限制并发耗尽资源:直接用Task.WhenAll发起所有请求,瞬间创建数百个并发任务,报表服务器的连接池、内存、处理线程被占满,后续请求排队等待直至超时。
  2. WCF客户端连接未释放:若ConvertToAsync中WCF客户端实例未妥善关闭/释放,会导致连接池耗尽,新请求无法获取可用连接。
  3. 报表服务器资源瓶颈:虽无数据库阻塞,但报表服务器的渲染、内存资源已达上限,新请求无法被及时处理,最终触发超时。
  4. 数据库连接池不足:报表数据源的连接池配置过小,大量请求抢占数据库连接,导致数据检索延迟飙升。

解决建议

1. 限制并发数

用SemaphoreSlim控制同时执行的任务数量,避免瞬间压垮服务器(建议先从10-20的并发数测试):

var semaphore = new SemaphoreSlim(15);
var listOfTasks = customers
    .Select(async customer =>
    {
        await semaphore.WaitAsync();
        try
        {
            var parameters = new Dictionary<string, string>
            {
                { "CustomerId", customer.Id },
                { "BillDate", billDate }
            };
            await GenerateInvoice(parameters);
        }
        finally
        {
            semaphore.Release();
        }
    })
    .ToList();

await Task.WhenAll(listOfTasks);

2. 优化WCF客户端管理

确保WCF客户端实例使用后及时释放,用using包裹实现自动释放:

using (var rsClient = new ReportExecutionServiceSoapClient())
{
    // 报表渲染逻辑
}

3. 调整报表服务器配置

  • 修改rsreportserver.config:提高MemoryLimit(报表服务器可用内存上限)、MaxQueueThreads和MaxWorkerThreads(报表处理线程数)
  • 启用报表缓存:针对固定参数(如BillDate)设置缓存,减少重复数据检索

4. 优化数据库连接

  • 调整报表数据源的连接池配置(如Max Pool Size),适当提高连接池容量
  • 优化报表查询语句,减少单报表的数据检索时间,降低数据库负载

5. 延长超时设置

在WCF客户端配置中延长超时时间,避免排队等待导致的超时:

<bindings>
  <basicHttpBinding>
    <binding name="ReportExecutionServiceSoap" receiveTimeout="00:10:00" sendTimeout="00:10:00">
    </binding>
  </basicHttpBinding>
</bindings>

6. 监控排查

  • 查看SSRS日志(默认路径:C:\Program Files\Microsoft SQL Server Reporting Services\SSRS\LogFiles)获取具体错误信息
  • 监控报表服务器的内存、CPU、磁盘IO使用情况,定位资源瓶颈
  • 用SQL Server Profiler跟踪报表查询,排查慢查询或资源争抢问题

内容的提问来源于stack exchange,提问作者Shandy Sawyer

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 21:15:22