UNLINK 删除千万级 Hash 安全的前提是 lazyfree-lazy-user-del 配置为 yes,否则会 silently 退化为同步 DEL;需检查运行时状态(如未被 WATCH、refcount=1、内存充足),并配合 EXPIRE 使用,避免监控误判内存释放。
直接用 UNLINK 删除千万级 Hash 是安全的,但必须确认 Redis 配置和运行时状态,否则它会悄悄退化成同步 DEL,照样卡主线程。
即使 Redis 版本 ≥ 4.0,UNLINK 默认仍走同步逻辑——它只在 lazyfree-lazy-user-del 配置开启时才启用后台释放。这个配置默认是 no,不手动改就等于没开。
CONFIG GET lazyfree-lazy-user-del → 返回 ["lazyfree-lazy-user-del","yes"] 才有效CONFIG SET lazyfree-lazy-user-del yes(重启后失效)redis.conf 中添加或修改为 lazyfree-lazy-user-del yes,然后重启UNLINK、FLUSHDB、FLUSHALL 等命令,不影响 DEL
UNLINK 在遇到某些运行时约束时,会自动降级为同步删除,且不报错、不提示——你看到返回 (integer) 1,但主线程其实已被阻塞。
WATCH 监控的 Key:事务未提交前调用 UNLINK,会立刻同步删refcount > 1 的 Key:例如刚被 OBJECT REFCOUNT 查出是 2,或正参与 RENAME、RESTORE 等操作INFO memory 中 mem_not_counted_for_lazyfree 明显上升,说明后台线程已拒收新任务INFO memory,观察 used_memory_human 是否缓慢下降,同时 lazyfree_pending_objects 先升后降设置过期时间(EXPIRE / PEXPIRE)是预防大Key堆积的第一道防线,但过期不是即时清理——Redis 用惰性+定期双策略,冷数据可能滞留数分钟。此时 UNLINK 是主动清场的补位动作,不是替代方案。
EXPIRE 自动回收,不用手动 UNLINK
expired_keys 持续增长,可定时 SCAN + UNLINK 主动收割UNLINK:redis.call("UNLINK", key) 会报错 ERR unknown command;需拆成脚本外判断 + 外部调用redis-cli --scan --pattern "profile:hash:*" | head -500 | xargs redis-cli UNLINK(控制批次防压垮 BIO 线程)真正容易被忽略的是:UNLINK 后 used_memory 不立刻下降,而很多监控告警依赖这个指标做“内存已释放”判断。如果你的运维流程里有“删完立刻检查内存回落”的断言,那得改成查 lazyfree_pending_objects 是否归零,或者加几秒延迟再验。