LazyCache.AspNetCore中GetAsync负载下响应超20ms的优化方案咨询
解决LazyCache.AspNetCore负载下GetAsync响应超时问题
先排查计时准确性问题
你代码中类级别的_watch字段是线程不安全的,高并发场景下多个请求会同时修改这个实例,导致计时结果完全失真——可能你看到的20ms根本不是GetAsync的真实耗时,而是多个请求的计时互相干扰的结果。
修复方式:将Stopwatch改为方法内的局部变量,确保每个请求独立计时:
// 移除类级别的_stopwatch字段 public async Task TestAsync(UserInfo user){ var key = await CreateCustomTokenAsync(user.X); // 局部变量,每个请求独立实例化 using var watch = Stopwatch.StartNew(); var val = await cache.GetAsync<string>(key); if (val == user.Y) { var timeTaken = watch.Elapsed.TotalMilliseconds; log(timeTaken); return; } // ... }
优化缓存实例的生命周期
你直接new CachingService()的方式会导致每个请求(或每个类实例)创建独立的缓存实例,不仅无法共享缓存数据,还会额外消耗内存和锁资源,高并发下必然拖慢性能。
正确做法:在AspNetCore中通过依赖注入注册并使用IAppCache:
- 启动类中注册服务:
builder.Services.AddLazyCache();
- 在你的类中注入
IAppCache:
private readonly IAppCache _cache; // 构造函数注入 public YourService(IAppCache cache) { _cache = cache; } public async Task TestAsync(UserInfo user){ // 使用注入的_cache实例,全局单例共享缓存 var key = await CreateCustomTokenAsync(user.X); using var watch = Stopwatch.StartNew(); var val = await _cache.GetAsync<string>(key); // ... }
排查缓存命中率
如果大部分请求都无法命中缓存(比如缓存键生成不稳定、缓存过期时间过短、内存不足导致缓存被回收),GetAsync会触发缓存填充逻辑(即使你当前代码没写工厂方法,后续如果有GetOrAddAsync也会有影响),这会大幅增加耗时。
验证方式:添加缓存命中日志,统计命中率:
var val = await _cache.GetAsync<string>(key); if (val == null) { log("缓存未命中"); // 后续填充缓存逻辑 } else { log("缓存命中"); }
如果命中率低于90%,需要调整缓存键的稳定性、延长合理的过期时间,或者优化服务器内存配置。
检查服务器内存与GC状态
高负载下如果服务器内存不足,.NET的垃圾回收会频繁触发Full GC,导致线程停顿,间接让GetAsync的耗时增加。可以通过以下方式排查:
- 查看服务器的内存使用率,确保有足够的空闲内存供缓存使用
- 使用性能计数器(如
.NET CLR Memory下的% Time in GC)查看GC停顿时间,如果超过1%,需要优化内存分配或调整GC配置
LazyCache内部配置优化
LazyCache默认基于IMemoryCache,可以通过配置调整其性能:
- 避免使用过长或过于复杂的缓存键,减少查找时的字符串比较开销
- 如果缓存值是复杂类型,可配置更高效的序列化器(默认使用System.Text.Json,可替换为MessagePack等二进制序列化器)
- 调整
MemoryCache的压缩配置,对大对象启用压缩(但注意压缩会增加CPU开销,需权衡)
内容的提问来源于stack exchange,提问作者Negin
相关产品推荐
相关产品推荐

