Redis内存淘汰时Java客户端不会抛出特定异常,而是静默删除键;Jedis等客户端收到正常响应,需通过监控evicted_keys、业务命中率及组合命令(如SET NX)间接感知淘汰影响。

Redis内存淘汰时Java客户端不会抛出特定异常
Redis本身在触发maxmemory策略(如volatile-lru、allkeys-random等)时,只是静默删除键,并不向客户端返回错误。Java客户端(如Lettuce、Jedis)收到的仍是正常响应(例如OK或null),**不会抛出RedisMemoryFullException这类不存在的异常**。所谓“捕获淘汰异常”本质上是个误解——你真正需要关注的是淘汰导致的业务语义丢失:比如SET成功但后续GET返回null,或INCR失败因key已被删。
Jedis中如何感知key可能被淘汰?
Jedis本身不提供淘汰事件通知,但可通过组合操作+状态检查来间接判断:
- 对关键写入,用
SET key value EX seconds NX代替单纯SET,利用NX确保原子性,并检查返回值是否为"OK"(失败说明key已存在且未被删,但不等于没被淘汰过) - 读取后校验业务逻辑合理性:比如缓存用户信息,
GET返回null时,不能直接报错,而应触发回源加载,并记录日志标记"cache-miss-after-write" - 避免依赖
TTL结果判断是否淘汰:因为TTL返回-2表示key不存在(可能被删,也可能根本没设),-1表示无过期时间——二者无法区分是主动删除还是淘汰删除
Lettuce连接池配置要防淘汰引发的连接雪崩
当Redis因内存满频繁淘汰,某些业务请求可能因超时或重试加剧压力。Lettuce默认的连接池和超时设置在此场景下容易放大问题:
- 把
CommandTimeout从默认的60秒调低到1000毫秒,防止慢查询拖垮线程池 - 禁用
autoReconnect = true,改由上层统一做熔断(如Resilience4j),否则自动重连可能在Redis持续高压时产生大量无效连接尝试 - 监控
redis_connected_clients和redis_used_memory_human指标,当used_memory > 95% maxmemory且evicted_keys持续增长时,应降级非核心缓存写入
真正该监控的不是“异常”,而是淘汰指标与业务命中率
靠捕获异常这条路走不通,必须转向可观测性建设:
立即学习“Java免费学习笔记(深入)”;
- 通过
INFO memory定期采集evicted_keys、expired_keys、used_memory_peak_human,画趋势图。突增的evicted_keys比任何Java异常都更早暴露问题 - 在缓存访问层埋点:统计
cache-get-hit-rate(如每分钟GET成功数 / 总GET数),持续低于90%且伴随evicted_keys上升,基本可判定淘汰已影响业务 - 不要在
catch (Exception e)里专门处理“Redis内存满”,这种代码既无依据也难测试——淘汰不是故障,是配置行为;真正要处理的是它引发的业务空值、重复加载、数据不一致
淘汰本身不可怕,可怕的是把它当成黑盒,又不监控它的实际业务影响。


















