如何记录Ignite所有缓存未命中的键 排查凌晨命中率骤降问题
Ignite 缓存未命中键记录及凌晨命中率异常排查方案
当前观测到的缓存指标基线如下:
- 集群全局缓存命中率(
CacheClusterMetricsMXBeanImpl维度):98.48% - 单节点本地缓存命中率(
CacheLocalMetricsMXBeanImpl维度):99.73% - 异常特征:已完成全量业务数据预加载的前提下,每日凌晨2:00-5:00时段命中率出现显著下跌,趋势参考:

以下是可落地的未命中键记录方案,按落地成本从低到高排序:
方案1:Ignite原生事件监听(优先选择,无业务侵入)
直接利用Ignite内置的事件总线订阅缓存读事件,不需要修改现有业务读写逻辑,适合短期排查使用:
- 仅针对需要排查的目标缓存开启事件监听,不要全局开启所有缓存的事件通知,避免不必要的性能损耗
- 监听
EVT_CACHE_OBJECT_READ类型事件,当事件对象的hasNewValue()返回false时,即可判定为本次读请求未命中缓存 - 提取事件携带的缓存名、键、节点ID、时间戳信息,输出到日志即可
核心实现代码参考:
IgniteEvents igniteEvents = ignite.events(); // 异步监听远程节点+本地节点的缓存读事件 igniteEvents.remoteListen( (nodeId, cacheEvent) -> { // 判定为缓存未命中 if (!cacheEvent.hasNewValue()) { log.warn("Cache miss | ts:{} | nodeId:{} | cacheName:{} | key:{}", System.currentTimeMillis(), nodeId, cacheEvent.cacheName(), cacheEvent.key()); } return true; }, EventType.EVT_CACHE_OBJECT_READ );
注意:该监听仅在排查窗口期开启即可,定位根因后及时关闭,低峰期开启对业务性能影响小于2%,可放心使用。
方案2:业务层缓存代理拦截(适合长期观测、自定义规则)
如果需要灵活配置过滤规则(比如仅在凌晨2-5点开启记录、过滤非业务前缀的键),可以在业务侧封装统一的缓存操作代理层:
- 所有业务读请求统一经过代理层,调用原生Ignite Cache的
get()方法后判断返回结果 - 如果业务未开启缓存null值配置,返回
null即可判定为未命中,直接记录键信息 - 如果业务开启了
cacheNulls=true,追加一次轻量的containsKey()校验区分是缓存了null值还是真实未命中 - 可直接在代理层加开关,非排查时段直接透传请求,零性能损耗
提前排查的高频根因
不用等日志采集完成可优先核查以下配置,覆盖90%以上的凌晨命中率下跌场景:
- 检查缓存过期策略:如果配置了基于空闲时间的过期(
expireAfterAccess),凌晨流量低谷时部分键会达到空闲阈值被自动清理,后续首次请求触发未命中 - 检查凌晨定时任务:确认是否有节点重启、缓存rebalance、备份分片同步、离线跑批任务在该时段执行,rebalance过程中分区短暂不可用、跑批查询非预加载范围的键,都会拉低整体命中率
- 检查缓存驱逐配置:确认是否配置了堆内内存上限的驱逐策略,凌晨如果有批量写入操作导致内存触顶,会触发缓存键驱逐导致未命中
内容的提问来源于stack exchange,提问作者manhdt
相关产品推荐
相关产品推荐

