如何使用IDistributedCache避免Azure AppService内存泄漏问题
场景与现状概述
我们的业务场景为:每次请求生成包含100个评估ID的报表,提交后将生成100份PDF/Word格式报表,多数报表页数在1000-1300页。目前已完成基于DistributedCache的报表数据输出流缓存POC,通过缓存避免数据无变化时的重复处理,性能提升显著:
- PDF报表:首次生成100份耗时约28分钟,缓存返回耗时约12分钟
- Word报表:首次生成100份耗时约14分钟,缓存返回耗时约1分钟
测试了DistributedCacheEntryOptions的两种过期策略后,计划采用AbsoluteExpiration选项。当前面临的问题是:若60分钟内提交10次请求(每次含100个不同评估ID),缓存将存储1000份报表数据,需找到避免Azure App Service内存泄漏的最佳实践。
具体优化方案
1. 规范AbsoluteExpiration配置
放弃使用DateTime.Now配置绝对过期时间(存在服务器时间偏差风险),改用AbsoluteExpirationRelativeToNow确保缓存条目在生成后准时过期,代码调整如下:
var cacheEntryOptions = new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(60) };
该配置能严格控制缓存生命周期,避免缓存数据无限累积。
2. 切换至Azure托管分布式缓存服务
不要依赖App Service自带的内存缓存(哪怕是分布式模式),直接采用Azure Redis Cache或Azure Managed Cache:
- 这类服务独立于App Service实例,缓存数据不占用App Service内存,从架构层面杜绝内存泄漏风险
- 支持自动过期清理、弹性扩容,轻松承载1000份大体积报表的缓存需求
- 稳定性与性能优于App Service自带缓存,适配大文件流的缓存场景
3. 优化缓存Key设计
采用报表类型-评估ID的唯一Key格式,例如:pdf-report-{EvaluationId}、word-report-{EvaluationId}:
- 便于后续按评估ID或报表类型批量清理缓存(如有提前过期需求)
- 避免Key冲突,确保每个报表的缓存条目独立可管理
4. 配置缓存监控与主动清理
- 在Azure Portal中为托管缓存服务配置内存使用率告警,当占用率超过阈值(如80%)时触发通知
- 结合Azure Functions定时任务,定期扫描并清理过期或冗余缓存条目,补充自动过期策略的不足
5. 大体积缓存数据优化
针对1000-1300页的大体积报表,优化缓存内容:
- 对缓存的报表数据流进行GZip压缩,减少存储占用与传输耗时
- 若报表数据可拆分,优先缓存结构化数据而非最终文件流,生成报表时再组装,进一步降低缓存体积
6. 禁用App Service本地缓存
若之前启用了App Service本地缓存功能,建议立即禁用——本地缓存会将分布式缓存数据同步到实例内存,可能导致内存占用过高,确保所有缓存操作直接指向Azure托管缓存服务。
内容的提问来源于stack exchange,提问作者VamKris

