电商站点的 Redis 6.2 设了 maxmemory 4G 和 allkeys-lru,大促前发现命中率从 92% 掉到 40%,数据库 QPS 翻了三倍,redis-cli INFO 里 evicted_keys 每秒都在涨。

一开始怀疑是「maxmemory 只留了很少的余量,写入一多就开始连续淘汰」,查了一圈,方向不对。

真正麻烦的地方在于,几个原因的现象几乎一样。allkeys-lru 会把过期时间长的热点也淘汰掉,不只是冷数据。也可能是没有区分缓存和持久化数据,两类 key 混在一个实例里。

不容易想到的是,key 没有设置 TTL,LRU 只能按访问时间判断,冷热分不开。

动手时先看淘汰量和内存分布

redis-cli INFO stats | grep evicted_keys && redis-cli INFO memory | grep used_memory_human

接着确认当前淘汰策略

redis-cli CONFIG GET maxmemory-policy

再往下改成只淘汰带 TTL 的 key

redis-cli CONFIG SET maxmemory-policy volatile-lru

末了找出大 key 并补上 TTL

redis-cli --bigkeys

改完先别撤,确认这几项。evicted_keys 增长明显放缓,命中率回到 85% 以上,数据库 QPS 回到大促前的水平。

这里还有个坑。volatile-lru 在没设 TTL 时会退化成不淘汰并直接报错,策略和 TTL 必须成对设计;缓存和队列不要放同一个实例。线上能稳定复现的问题都不算难,难的是只在大流量下才出现的那种。

作者 9823189