MemoryCache的PostEvictionCallback何时触发?过期被覆盖如何解决?
.NET MemoryCache 问题解答
回调触发时间判定
首先明确MemoryCache的两个基础逻辑:
- 对同一个key调用
Set方法时,会直接覆盖原有缓存条目,原有条目会立刻触发注册的PostEvictionCallback,驱逐原因为EvictionReason.Replaced。也就是说在13:35到13:54之间的每次IncrementValue调用,都会触发一次旧条目的UpdateDatabase回调。 - 最后一次更新缓存的时间为13:54,本次
Set指定的过期策略是AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1),所以最后一条缓存的过期时间为13:54加1小时即14:54,该条目自然过期触发的UpdateDatabase回调时间为14:54,不会是14:45。
固定缓存过期时间的修复方案
对于每次调用Set会刷新过期时间的问题,有两种成熟的落地解决方案:
方案1:用可变引用类型包装值,避免重复调用Set(改造成本最低)
该方案不需要修改过期时间逻辑,仅调整缓存存储结构即可,全程仅首次初始化调用一次Set,不会修改原有过期时间,也不会触发重复覆盖导致的驱逐回调,如果不需要每次缓存更新都同步写库,仅需过期时一次性落库,该方案完全符合需求:
// 定义可变的计数包装类 public class CacheCounter { public int Count { get; set; } } // 首次初始化缓存逻辑(仅key不存在时执行1次) public void InitCounter(string key) { var options = new MemoryCacheEntryOptions() { AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1) }; options.RegisterPostEvictionCallback(UpdateDatabase); _cache.Set(key, new CacheCounter { Count = 0 }, options); } // 自增逻辑无需调用Set,直接修改引用对象属性即可 public void IncrementValue(string key) { // 可自行补充key不存在时的初始化兜底逻辑 var counter = _cache.Get<CacheCounter>(key); counter.Count++; } // 调整UpdateDatabase的取值逻辑适配新的存储结构 private void UpdateDatabase(object key, object value, EvictionReason reason, object state) { var counter = (CacheCounter)value; _repository.AddNew(key.ToString(), counter.Count); }
方案2:缓存首次过期时间,每次更新时复用该时间
如果必须每次调用Set更新值,可以在首次创建缓存时记录固定的绝对过期时间,后续更新时复用该时间即可避免过期时间被刷新:
public void IncrementValue(string key) { int currentCount = _cache.Get<int>(key); // 尝试读取已缓存的过期时间 if (!_cache.TryGetValue($"{key}_expire", out DateTimeOffset expireTime)) { // 首次创建时计算固定的绝对过期时间,同时缓存该时间 expireTime = DateTimeOffset.Now.AddHours(1); _cache.Set($"{key}_expire", expireTime, new MemoryCacheEntryOptions { AbsoluteExpiration = expireTime }); } var options = new MemoryCacheEntryOptions() { // 复用首次计算的绝对过期时间,不使用相对当前时间的过期策略 AbsoluteExpiration = expireTime }; options.RegisterPostEvictionCallback(UpdateDatabase); _cache.Set(key, currentCount + 1, options); }
内容的提问来源于stack exchange,提问作者schweppes0x
相关产品推荐
相关产品推荐

