redis慢日志中全是set/del却卡顿,说明瓶颈不在命令执行本身,而是内存淘汰机制同步释放大key阻塞主线程;需通过info memory与evicted_keys验证,并用memory usage+scan精准定位高危key,启用lazyfree-lazy-eviction并配合unlink、ttl随机化等措施根治。

slowlog里全是SET/DEL却卡顿,说明不是命令慢,而是淘汰在拖后腿
Redis主线程执行SET、DEL前,若used_memory_dataset已逼近maxmemory,会先同步触发淘汰逻辑——尤其遇到大Key,释放内存过程直接阻塞主线程。此时SLOWLOG GET 10看到的“慢命令”只是表象,真正瓶颈在驱逐环节。
验证方法:redis-cli info memory | grep -E "(used_memory_dataset|maxmemory)",若前者长期 > 85% 后者,且redis-cli info stats | grep evicted_keys持续增长,基本可锁定是淘汰引发的卡顿。
用--bigkeys扫不出真凶?得换MEMORY USAGE + SCAN组合拳
redis-cli --bigkeys只统计逻辑长度(如STRLEN),对实际内存占用完全无感。一个JSON字符串可能STRLEN才1KB,但因Redis内部编码升级(embstr→raw)、SDS头开销、ziplist转hashtable等,真实内存吃掉5MB——--bigkeys根本看不见。
更关键的是:频繁淘汰往往由“一堆中等大小Key + 高频写入”驱动,而非单个显眼大Key。比如每秒新增1000个20KB的session,--bigkeys可能只扫到最老的那个,漏掉正在堆积的新生代。
精准定位步骤:
- 先用
SCAN遍历所有db(注意加-n指定db编号,--bigkeys默认只查db0) - 对每个key执行
MEMORY USAGE <key></key>,抓出真实内存>10KB或元素数>1w的候选 - 结合
OBJECT FREQ <key></key>(需Redis 4.0+)看访问频次,高内存+高访问=高危对象
lazyfree-lazy-eviction yes是止血第一刀
Redis 4.0+默认淘汰是同步释放内存,遇到大Key就卡死。开启lazyfree-lazy-eviction yes后,主线程只做标记,真正释放交由bio线程异步处理——这是最直接有效的缓解手段。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
但要注意:
- 它不能替代根治,只是把阻塞从主线程转移到后台,仍需配合大Key治理
- 必须同时改
DEL为UNLINK,否则删除操作本身仍会同步阻塞 -
UNLINK对大Key生效,小Key仍走DEL路径,性能无损
evicted_keys持续涨但没大Key?检查TTL设置和淘汰策略搭配
如果evicted_keys稳定上升,但MEMORY USAGE扫描没发现明显大Key,大概率是TTL集中过期+淘汰策略叠加导致的雪崩式清空。
典型诱因:
- 批量缓存预热时所有key设相同TTL(如全设
EXPIRE key 3600),1小时后整批失效 - 误用
volatile-ttl策略,优先删马上过期的key,加速雪崩节奏 - 漏设TTL的key长期霸占内存,最终逼Redis启用
allkeys-*兜底策略,误杀热数据
实操建议:
- 统一改用
allkeys-lfu,天然保护高频key - TTL必须加随机偏移(如Java用
ThreadLocalRandom.current().nextInt(300)) - 禁用
volatile-ttl,提高maxmemory-samples至10,降低采样偏差
真正危险的从来不是单个大Key,而是高频写入+TTL抖动缺失+淘汰策略不匹配这三者的隐性叠加——它们不会立刻报错,但会在某次流量高峰时突然让evicted_keys飙升,而你翻遍--bigkeys也找不到那个“罪魁祸首”。










