KEYS会阻塞Redis主线程,因全量扫描键空间导致服务停顿;SCAN则基于游标增量迭代,不阻塞且支持模式匹配,但需客户端循环处理、注意弱一致性及使用限制。

为什么 Keys 命令在生产环境会阻塞
KEYS 是全量扫描,Redis 会一次性遍历整个键空间,期间无法处理其他请求。当数据库有几百万个 key 时,这个操作可能持续几百毫秒甚至秒级,直接导致服务超时、连接堆积、监控告警。这不是“慢”,而是“停服级阻塞”。
-
KEYS在 Redis 6.0 之前完全阻塞主线程;6.0+ 虽做了部分优化,但仍是同步全量遍历,不解决根本问题 - 它不支持模式匹配的分页,无法中断或限速
- 运维平台或监控脚本偷偷调用
KEYS *是线上事故常见诱因
Scan 的工作原理和基本用法
SCAN 是基于游标的增量式迭代器,每次只返回少量 key(默认 10 个),并返回下一个游标值,由客户端决定是否继续。它不保证一次遍历完所有 key,也不保证结果唯一(可能重复或漏掉刚过期/刚写入的 key),但完全不阻塞主线程。
- 游标初始值为
0,每次调用返回新游标,直到返回游标为0表示完成 - 使用
MATCH参数做模式匹配,如SCAN 0 MATCH user:* COUNT 100 -
COUNT是提示值,不是硬限制:实际返回数量可能更少(尤其数据分布稀疏时)或略多(内部哈希表桶遍历机制导致)
127.0.0.1:6379> SCAN 0 MATCH order:2024* COUNT 50 1) "42" # 下一个游标 2) 1) "order:20240101:abc" 2) "order:20240102:def" 3) "order:20240103:xyz"
Scan 替代 Keys 的实操要点
直接把 KEYS pattern 换成 SCAN 不够,必须适配其异步、分片、不可靠特性:
- 客户端必须实现游标循环逻辑,不能只调一次
SCAN - 若需精确去重,应在应用层用
Set缓存已见 key(注意内存开销) - 避免在高并发写入场景下依赖
SCAN做“实时一致性校验”,它本质是快照式弱一致 - 生产脚本中建议显式设置
COUNT(如 500–1000),太小导致 RTT 过多,太大增加单次耗时 -
SCAN不支持正则,MATCH只支持 glob 风格通配符:*、?、[abc]
容易被忽略的坑
SCAN 看似简单,但几个细节常引发线上问题:
- 游标传错类型:比如把字符串
"0"当整数0传入某些 SDK(如早期 Jedis),导致无限循环或报错ERR invalid cursor - 没处理空结果:某次
SCAN返回空数组但游标非零,仍需继续,否则漏数据 - 在 Lua 脚本里误用
SCAN:Redis 禁止在脚本中使用非确定性命令,SCAN属于被禁用列表,会报ERR Error running script - 把
SCAN当作原子操作:它不提供事务语义,两次调用之间 key 可能已被删或改名
真正安全的生产扫描,往往需要配合业务节奏——比如低峰期执行、带超时控制、失败自动退避,而不是指望一个命令解决所有问题。


















