Azure App Service上.NET 7 Web API连续请求时性能下降排查
问题描述
部署在Azure App Service中的.NET 7 Web API,在连续发送非并发请求时性能逐渐下降:依次发送25个请求,响应时间从不足1秒开始,每次增加0.1-0.2秒,最终超过6秒。
该API使用GroupDocs.Conversion实现Word文档转PDF功能,核心代码如下:
Program.cs
var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); var app = builder.Build(); app.UseSwagger(); app.UseSwaggerUI(); app.UseHttpsRedirection(); app.UseAuthorization(); app.MapControllers(); app.Run();
PdfConverterController
[HttpPost] [Route("convert/word")] public IActionResult ConvertWord(IFormFile fileToConvert, [FromQuery] string? password) { if (fileToConvert == null || fileToConvert.Length == 0) return BadRequest("No file uploaded."); try { var outputPath = Path.Combine(Path.GetTempPath(), fileToConvert.FileName + ".pdf"); var decodedPassword = string.Empty; if (!string.IsNullOrEmpty(password)) decodedPassword = Encoding.UTF8.GetString(Convert.FromBase64String(password)); var loadOptions = new WordProcessingLoadOptions { Password = decodedPassword, Format = (WordProcessingFileType)FileType.FromExtension(Path.GetExtension(fileToConvert.FileName)), }; using (Converter converter = new Converter(fileToConvert.OpenReadStream, () => loadOptions)) { var convertOptions = new PdfConvertOptions(); converter.Convert(outputPath, convertOptions); } var ms = new MemoryStream(); using (var fs = new FileStream(outputPath, FileMode.Open)) fs.CopyTo(ms); System.IO.File.Delete(outputPath); return File(ms.ToArray(), MediaTypeNames.Application.Pdf); } catch (Exception ex) { return StatusCode(StatusCodes.Status500InternalServerError, ex.Message); } }
已尝试的排查动作:
- 使用using声明或单实例HttpClient调用API,无明显改善
- 本地控制台程序中GroupDocs.Conversion运行正常
- App Service为PremiumV3规格,排除资源瓶颈
- 优化资源释放逻辑并手动触发GC,均无效
- 通过发布管道部署时问题更严重
排查建议
- 检查GroupDocs.Conversion非托管资源泄漏:虽然代码用
using包裹了Converter,但GroupDocs内部可能存在未正确释放的非托管资源(如字体缓存、Office组件句柄)。尝试升级到最新稳定版本,修复已知泄漏问题;同时排查是否有静态初始化的GroupDocs对象未被清理。 - 替换临时文件为内存流输出:当前代码将转换结果写入临时磁盘再读取,可能存在Azure临时磁盘IO波动或文件锁定问题。改用GroupDocs支持的直接输出到
MemoryStream的重载(如converter.Convert(ms, convertOptions)),跳过磁盘IO步骤,验证性能是否稳定。 - 启用Azure App Service诊断追踪:在Azure门户开启应用日志、服务器日志和Application Insights,拆分每个请求的耗时(如
Converter初始化、转换、文件读写各阶段),同时监控内存、文件句柄的变化趋势,确认是否存在内存持续增长或句柄泄漏。 - 优化临时文件命名逻辑:当前用
fileToConvert.FileName + ".pdf"作为临时文件名,重复文件名可能导致文件锁定或删除失败。改用Guid.NewGuid().ToString() + ".pdf"生成唯一文件名;删除文件时增加重试逻辑(捕获IOException后延迟重试),确保临时文件彻底清理。 - 排查发布管道部署的特殊配置:发布管道部署后问题更严重,需检查部署过程是否修改了App Service权限(如临时目录权限、字体文件访问权限),或部署包是否缺失GroupDocs依赖的字体/组件。对比手动部署和管道部署的文件目录、权限差异。
- 分析非托管内存占用:使用Azure内存快照工具或第三方性能分析工具(如dotTrace),抓取请求前后的内存快照,重点排查非托管内存增长情况——若非托管内存持续上涨,说明GroupDocs存在未释放的非托管资源,需调整组件使用方式或联系官方支持。
- 测试GroupDocs对象复用:非并发场景下,尝试复用
Converter或相关配置对象(需确认线程安全性),避免每次请求都初始化全新实例,降低重复初始化开销。
内容的提问来源于stack exchange,提问作者Ryan Thomas
相关产品推荐
相关产品推荐

