能够真正阻塞 Redis 服务器的命令,主要集中在键全量遍历、大集合读取、大 key 删除以及复杂排序几类操作上,这些命令在单线程模型下会把事件循环卡住,导致所有客户端请求排队,很多入门资料把 BLPOP 这类命令也列为黑名单,但它们阻塞的是调用方连接,并不会卡死服务器,需要区分对待。
redis哪些命令会阻塞服务器:先看这份黑名单
单线程模型为什么容不下耗时命令
Redis 是单线程串行处理命令,一个命令没执行完,后续命令只能等着,行业共识认为,Redis 的速度优势正来自这种无锁设计,但代价是对单命令耗时极度敏感,一旦某个命令执行了上百毫秒,整个实例的延迟就会瞬间飙升,你可以把 Redis 想象成一个只有一个人的客服窗口,前面那个人问十分钟,后面所有人都得陪站。
全量遍历类命令是第一批元凶
KEYS:直接遍历整个键空间,键数量越大,耗时越长。HGETALL key:返回哈希表全部字段和值,大哈希会构造巨大的回复缓冲区。SMEMBERS key:返回集合全部成员,大集合同理。LRANGE key 0 -1:返回列表全部元素,长列表下同样危险。
这些命令的共性是时间复杂度为 O(N),而 N 来自键总数或单一键的内部元素个数,在测试环境数据量小,感觉不到;线上数据量上来,一抓一个准。
同步删除与排序命令也不省油
DEL key 在删除大 key 时,会同步释放该 key 占用的内存,如果这个 key 是一个包含数百万成员的集合,内存回收过程可能持续数百毫秒甚至数秒,另一个典型是 SORT key,它会对集合或列表元素排序,复杂度可达 O(N+MLog(M)),数据量大时同样卡顿。
这时候要学会换工具:用 SCAN 族命令代替 KEYS,用 HDEL 分批删除哈希字段,用 UNLINK 代替 DEL,都能有效降低阻塞风险。
redis大key删除命令对比:DEL与UNLINK谁更安全
DEL 的阻塞本质
当你要删除一个包含大量元素的哈希、集合或列表时,DEL 需要真正执行内存释放,业内专家指出,在一个较大的 set 上执行 DEL,Redis 会在命令执行期间全程占用 CPU,其他操作全部排队,你可以用 slowlog get 看到这类命令的耗时。
UNLINK 的异步思路
Redis 4.0 之后提供 UNLINK,它只把 key 从键空间中摘除,真正的内存回收交给后台线程,这样命令本身立即返回,避免阻塞,但要注意两个边界:
- UNLINK 也不是完全无代价,后台内存回收队列过长时压力会变大。
- 在键很小的时候,UNLINK 和 DEL 的行为几乎一样,会同步删除。
操作上,可以通过 redis-cli --bigkeys 检查哪些 key 比较大,再用 type key 查看类型,最后决定用 DEL 还是 UNLINK。
对比表:DEL 与 UNLINK
| 对比维度 | DEL | UNLINK |
|---|---|---|
| 阻塞风险 | 大 key 删除时高 | 低,后台回收 |
| Redis 版本要求 | 所有版本 | 0 以上 |
| 适用场景 | 小 key、普通 key | 大 key、热 key |
| 注意事项 | 大 key 会卡服务 | 内存回收延后 |
redis阻塞排查场景:线上延迟高怎么定位命令
慢日志是第一步
先执行 CONFIG SET slowlog-log-slower-than 10000,把 10 毫秒以上的命令记录到慢日志,然后跑一段时间,再用 SLOWLOG GET 100 查看最近一百条慢命令,每条都会显示命令名、执行耗时、执行时间点,能快速锁定是哪类命令在拖后腿。
用 Latency Doctor 做体检
Redis 内置延迟诊断工具,在客户端执行 LATENCY DOCTOR,它会根据采样数据给出可能的问题,包括大 key、内存交换、fork 阻塞等,国内不少云厂商的控制台也提供类似的慢查询分析页面,直接勾选 Redis 实例就能看。
常用排查命令清单
INFO commandstats:看每个命令的总调用次数和平均耗时,高耗时命令一眼可见。DEBUG OBJECT key:查看某个 key 的 encoding 和 serializedlength,快速判断是不是大 key。MEMORY USAGE key:给出更准确的内存占用估计。
如果线上已经在抖动,我建议按这个顺序操作:先开慢日志,再看 commandstats,最后用 redis-cli --bigkeys 扫底,大多数情况下,阻塞元凶就在这三步里暴露。
其他容易被忽视的阻塞来源
键集中过期导致间歇性卡顿
大量 key 在同一秒过期,Redis 主循环必须逐个删除过期键,这就好比垃圾桶一秒钟堆满了一百袋垃圾,清洁工大爷得连续弯腰一整天,要避免这种场景,设置过期时间时加一个随机偏移,EXPIRE key seconds + random(0, 100),这个操作看似简单,却能有效分散过期压力。
持久化 fork 与内存淘汰风暴
执行 BGSAVE 或 AOF rewrite 时,Redis 需要 fork 子进程,fork 操作本身会阻塞主线程,内存越大,耗时越明显,虽然有 bgsave 不阻塞 Redis 的说法,但内存高到一定程度,fork 的耗时也会让请求感受到抖动。
当内存达到 maxmemory,Redis 会按淘汰策略逐出 key,如果淘汰的正好是大 key,逐出过程同样会占住主循环,而且这一行为难以预测,比显式删除更让人头疼。把大 key 拆小,比任何事后优化都重要,毕竟增配内存要向云厂商额外付费,长期来看成本不小,而用对命令几乎零成本,如果你正在纠结 Redis 内存扩容价格高不高,我的建议是先排查阻塞命令,把内存空间从浪费里捞回来。
Redis哪些命令会阻塞服务器?三个高频问答
问:KEYS 和 SCAN 哪个会阻塞服务器?
答:KEYS 会同步遍历整个键空间,数据量大时必然阻塞,SCAN 采用游标式迭代,每次只返回少量键,不会阻塞主线程,要遍历键,请直接使用 SCAN,并配合 TYPE 过滤类型。
问:删除大 key 时,DEL 一定阻塞吗?
答:不绝对,key 很小,DEL 也很快,但当一个集合包含数百万元素时,DEL 的耗时就会变得很明显,推荐先判断 key 类型和大小,再决定是否用 UNLINK。
问:BLPOP 这些命令算什么阻塞?
答:BLPOP、BRPOP 阻塞的是发起调用的客户端连接,Redis 服务器可以继续处理其他请求,不过大量阻塞连接会占用文件描述符和内存,在高并发场景下同样需要控制数量和超时时间。
回到最初的问题:真正阻塞 Redis 的命令,都是让单线程主循环停下来长时间忙活的命令。 记住一句话,能用 SCAN 就不用 KEYS,能删大 key 就用 UNLINK,能分批操作就不要全量操作,线上 Redis 的延迟就能稳得住。
首发原创文章,作者:王坚,如若转载,请注明出处:https://idctop.com/article/696186.html





