会,del 命令批量删除大量 key 会导致 redis 主线程阻塞,因其实现为同步原子操作,需逐个释放内存,大 value 或大批量删除将显著延长执行时间,引发延迟飙升与 qps 下跌。

DEL 命令直接删大量 key 会卡死 Redis?
会,而且非常容易。只要一次 DEL 操作涉及上万甚至几十万个 key,Redis 主线程就会被阻塞住,期间所有命令排队等待,QPS 断崖下跌,监控里立刻看到延迟飙升。
根本原因是 DEL 是同步、原子、逐个释放内存的操作——它得等每个 key 的 value 对象彻底回收完才返回。大 value(比如一个 50MB 的 hash)会让单次 DEL 耗时几百毫秒,更别说批量了。
- 别用
KEYS pattern | xargs redis-cli DEL:虽然常见,但KEYS本身会遍历整个键空间,阻塞服务器,生产环境禁用 - 小规模清理(DEL,但务必确认 key 数量,别靠猜
- 如果必须用客户端批量删,改用
SCAN+ 分批DEL,每次最多 500–1000 个 key,留出缓冲余量
SCAN + UNLINK 是最稳的渐进式方案
UNLINK 是 DEL 的非阻塞替代品:它立刻返回,把实际内存回收扔给后台线程异步做。配合 SCAN 迭代,就能边扫边删,不卡主线程。
典型 Shell 写法:
redis-cli --scan --pattern 'user:*' | xargs -n 500 redis-cli UNLINK
注意三个关键点:
-
--scan比SCAN命令更安全,它自动处理游标迭代,不用手写循环 -
-n 500控制每批最多删 500 个 key,避免单次网络包过大或服务端压力突增 - 必须用
UNLINK,不是DEL;Redis 4.0+ 才支持,低版本请跳过此方案
Lua 脚本能保证原子性,但有隐藏风险
在脚本里用 SCAN + DEL 看似“一气呵成”,其实只是把多次网络往返压成一次请求,**并不解决阻塞问题**——脚本执行期间仍是单线程运行,若匹配到几千个 key,照样卡住整个 Redis。
真实场景中,只有两种情况适合 Lua:
- 删除数量极小(
- 配合
UNLINK(Redis 6.0+)写脚本,但要注意 Lua 中不能直接调用UNLINK,得用redis.call('UNLINK', key),且需确认版本支持 - 别信网上那些“无限循环 SCAN”的脚本,没设
COUNT或没判断游标终值,极易跑飞、超时、OOM
FLUSHDB / FLUSHALL ASYNC 是真正的全量清空底牌
如果你要删的是整个库(比如测试环境重置、灰度发布前清缓存),FLUSHDB ASYNC 或 FLUSHALL ASYNC 是唯一既快又安全的选择。它启动后台线程清理,主线程完全不受影响。
使用前提很明确:
- Redis 版本 ≥ 6.2(ASYNC 参数从 6.2 开始默认可用;6.0 需编译时开启)
- 确认你要删的是当前 DB(用
SELECT n切好)或全部 DB,别错选错库 - 删完不会立刻释放内存,系统内存回收有延迟,观察
used_memory_rss指标比看dbX:keys更准
真正难的从来不是“怎么删”,而是删之前没想清楚:这个 key 空间有没有被其他服务强依赖?TTL 是否已合理设置?是否该用 EXPIRE 替代硬删?这些比命令本身更容易引发线上事故。









