直接DEL大Key会阻塞主线程、引发雪崩,必须禁用;安全清理需UNLINK替代DEL,结合MEMORY USAGE实测内存、SCAN分批删除、慢日志验证访问模式,并同步治理业务写入逻辑。

直接 DEL 大 Key 是生产事故高发动作,必须禁用。安全清理的核心是“不阻塞主线程、可控、可观测”。
怎么识别真正危险的大 Key?别只看数量,要看内存和访问模式
仅靠 redis-cli --bigkeys 扫描不够——它只报每种类型里最大的那个,且不反映真实内存占用。比如一个 Hash 有 3000 个 field,但每个 value 是 20KB 的 JSON,总内存可能超 60MB,而 --bigkeys 默认不会标红这种。
- 优先用
redis-cli MEMORY USAGE实测内存,SAMPLES 100 SAMPLES对Hash/ZSet很关键:值太小(如 1)会低估,太大(如 10000)拖慢命令本身 - 结合
redis-cli --scan --pattern "*" | xargs -I {} redis-cli memory usage {} 2>/dev/null | sort -nr | head -20快速拉出内存 Top20(注意加2>/dev/null过滤不存在的 key) - 查慢日志确认是否已被高频访问:
redis-cli slowlog get 100,重点看耗时 >100ms 且含HGETALL/LRANGE/ZRANGEBYSCORE的记录
删除时用 UNLINK 而不是 DEL,但 UNLINK 不是万能解药
UNLINK 把释放内存的操作丢给后台线程,避免主线程卡死,但它只解决“释放”这一步。如果大 Key 正在被频繁读写,UNLINK 后仍可能触发大量内存拷贝或网络传输压力。
-
UNLINK在 Redis 4.0+ 可用,低版本必须用分批方案 -
UNLINK不保证立即释放内存:后台线程处理速度受lazyfree-lazy-user-del yes配置和当前负载影响,需观察INFO memory中的lazyfree_pending_objects - 对超大
Hash或ZSet,即使UNLINK成功,主从同步 backlog 和 RDB fork 时的 COW 开销依然存在
分批删除 Hash / ZSet 类大 Key 的实操要点
Python 示例里常见的 hscan + hdel 循环,容易因单次扫描太多 field 导致阻塞。关键在控制每次交互的数据量和节奏。
- 用
HSCAN,COUNT 500 COUNT别设超过 1000;每次删完 sleep 10–50ms,防止打满 CPU 和网络 - 删
ZSet用ZREMRANGEBYRANK比0 499 ZREM单个 member 快得多,但要注意 rank 是否连续(如有ZREMRANGEBYSCORE删除过,rank 可能有空洞) - 脚本中必须加异常捕获和游标持久化:中断后能从上次
cursor继续,否则重头扫可能重复删或漏删
清理后必须验证的三件事
删完不等于结束。很多团队删完就走,结果第二天发现接口又慢了——因为旧逻辑还在持续往新 Key 写数据,或者没清干净残留。
- 确认
MEMORY USAGE返回值归零,且EXISTS返回 0;有些场景UNLINK后 key 名还存在但已不可读,得用TYPE验证 - 检查
INFO stats中的evicted_keys和expired_keys是否突增——说明淘汰策略被意外触发 - 盯 15 分钟
INFO memory的used_memory_dataset和mem_fragmentation_ratio:如果碎片率 >1.5 且内存没明显下降,说明释放的内存块没被复用,可能需要后续MEMORY PURGE(Redis 7.0+)或重启实例
最常被忽略的是业务侧写入逻辑没改。清理掉一个 user:1001:profile 大 Hash,结果下游服务每分钟还在 HSET 新字段进去——两天后它又回来了。治理大 Key,一半靠运维命令,一半靠推动代码层加阈值校验和拆分逻辑。











