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

高流量场景下Memcached/IMemoryCache间歇性返回null问题排查

问题根因

该问题和EnyimMemcachedCore、IMemoryCache的组件本身实现无关,高流量+大体积缓存条目是核心触发诱因,直接故障点为以下三类共性问题:

  • 缓存写入静默失效,读取返回null
    Memcached服务端默认单条Value大小上限为1MB,存入的大体积业务数据极易触发该阈值,EnyimMemcachedCore写入超限制数据时会直接返回失败,如果自定义的CacheService.AddCacheData方法未捕获异常、未校验写入返回结果,会出现写入实际失效但业务无感知的情况,读取时自然返回null。
    对IMemoryCache而言,若应用配置了内存回收阈值(SizeLimit),高流量下内存占用快速攀升时,大体积缓存条目会被标记为最高优先级驱逐对象,可能在写入后极短时间内被后台扫描线程回收,读取时恰好命中回收窗口就会返回null。
  • 空值未拦截直接传入下游方法触发异常
    抛出的System.ArgumentNullException: Value cannot be null. (Parameter 's')异常,本质是读取到null的缓存返回值后,未做任何判空校验,直接将null传入了Json反序列化、字符串处理类方法——这类方法的字符串参数s不允许传入null,因此直接抛出参数空异常,和缓存组件本身逻辑无关。
  • 高并发读写竞态导致非预期null
    通过new方式初始化的静态_cacheMemory实例,若内部的读写方法未对同键并发操作加锁控制,高并发下同一个键同时被多个请求覆盖写入时,会出现内存流写入冲突,读取时可能拿到半写入的损坏数据,反序列化时触发空值异常。
    此外静态实例如果内部自行初始化Memcached客户端,而非使用DI注入的单例客户端,高并发下会出现连接泄漏、连接池耗尽,导致读写超时返回null。IMemoryCache本身虽然是线程安全的,但热点键同时被覆盖写+读取时,在条目置换的极短窗口内也可能返回null。
修复方案
    1. 解决写入静默失效问题
    • 对EnyimMemcachedCore:根据业务数据大小调整Memcached服务端单条Value上限(建议不超过10MB,单条缓存值过大会大幅降低序列化、网络传输性能),修改CacheService的写入封装逻辑,捕获写入异常、校验写入返回结果,写入失败时打日志留存上下文,不要静默吞错。
    • 对IMemoryCache:如果没有做精确的内存容量管控,暂时移除SizeLimit配置避免非预期驱逐;如果必须配置内存阈值,给大体积缓存条目设置CacheItemPriority.NeverRemove优先级,避免被优先回收,同时合理配置缓存条目的Size权重,保证内存回收逻辑符合预期。
    1. 所有缓存读取逻辑强制加空值校验
      不管使用哪种缓存组件,读取返回值后先判断是否为空,再做后续反序列化、业务处理,从根源上阻断参数空异常,同时在值为空时走回源逻辑重新加载数据写入缓存,示例代码:
// EnyimMemcachedCore 读取逻辑
var resultsData = _cacheMemory.GetCacheData("flightData_" + _uid);
if (resultsData == null)
{
    // 回源加载源数据
    resultsData = LoadFlightMainDataFromSource(_uid);
    _cacheMemory.AddCacheData("flightData_" + _uid, resultsData, 1800);
}

// IMemoryCache 读取逻辑
var resultsData1 = _memoryCache.Get<string>("flightData_1" + _uid);
if (string.IsNullOrEmpty(resultsData1))
{
    resultsData1 = FlightMainData.Medium;
    _memoryCache.Set("flightData_1" + _uid, resultsData1, DateTimeOffset.UtcNow.AddMinutes(30));
}
    1. 修复高并发竞态问题
    • 废弃自行new的静态_cacheMemory实例,将缓存封装服务通过依赖注入注册为单例,复用EnyimMemcachedCore默认提供的单例Memcached客户端,避免多实例导致的连接池耗尽、连接泄漏问题。
    • 对访问量极高的热点缓存键,用SemaphoreSlim做同键的并发限流,避免同一个键同时被大量请求击穿写入,降低读写竞态概率。
    • 大体积缓存按业务维度拆分为小粒度键存储,不要将整份大对象存在单个缓存键中,既可以规避单条Value大小超限问题,也能降低内存回收时的驱逐优先级,同时提升序列化、网络传输效率。
    1. 补充高流量场景防护
      给缓存过期时间增加1-5分钟的随机偏移量,避免大量缓存键同一时间集中过期导致的请求突增、回源压力过大问题,进一步降低缓存层的并发压力。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 07:51:18