先看现象。CentOS 7.9 上 Redis 6.2,6 核 12G,maxmemory 8gb,策略是 allkeys-lru,某天中午命中率从百分之九十五掉到六十,后端 MySQL 的 QPS 涨了三倍,接口整体变慢。
排查方向其实有限,先把可能性排一排。allkeys-lru 对所有 key 一视同仁,冷数据一起参与竞争,热的反而被挤掉。另一种情况是批量导入脚本一次性灌进几百万冷 key,把原本缓存的热数据全顶出去。
不容易想到的是,单个大 hash 占用几百 M,淘汰只能整对象删,腾出来的空间与实际需求不匹配。
还有一种情况,实例被多个业务共用,一个业务的突发写入把公共缓存冲掉。
第一件事是看命中与未命中的变化曲线
redis-cli info stats | grep -E 'keyspace_hits|keyspace_misses|evicted_keys'
接着看 key 总量和内存占用是否异常
redis-cli dbsize && redis-cli info memory | grep used_memory_human
再往下把策略换成只淘汰带过期时间的 key
redis-cli config set maxmemory-policy volatile-lru
剩下的就是找出体积异常的 key 单独处理
redis-cli --bigkeys
怎么算真的好了,看的是同一批现象。命中率回到百分之九十以上,evicted_keys 增速明显下降,MySQL 的 QPS 回落到原来的水平,接口 p99 与故障前持平。
缓存层最好不要多业务混用,热数据给独立实例;换策略前确认业务代码给 key 都设了 TTL,否则 volatile 类策略等于不淘汰。改动前把原配置备份一份,出问题能马上回滚,这比任何技巧都实用。
