scan可替代keys避免阻塞,但需客户端实现游标循环、应用层去重、合理设count(推荐500–2000)、处理空响应及游标类型错误,集群中须逐节点执行,配合pipeline可提升吞吐。

直接用 SCAN 替换 KEYS 不是简单改个命令,而是要重构遍历逻辑——它不阻塞,但需要客户端自己管游标、去重、容错和分批处理。
为什么 Keys 会引发熔断式故障
KEYS 是同步全量扫描,Redis 单线程会被它独占。当键数超 50 万时,一次 KEYS * 可能卡住 800ms 以上,期间所有请求排队等待,连接池迅速打满,超时、重试、下游级联失败接连发生,监控上表现为 P99 延迟陡升、错误率飙升、CPU 持续 100%——这不是慢,是服务阶段性“失联”。Redis 官方明确标注:仅限调试,生产禁用。
SCAN 的正确打开方式
SCAN 不是“无感替换”,而是引入新交互范式:
- 游标必须循环驱动:从 0 开始,每次取回新游标,直到返回游标为 0 才算完成
- 结果需应用层去重:SCAN 可能重复返回同一 key(尤其哈希表 rehash 期间),建议用 Set 缓存已见 key
- COUNT 要设合理值:太小(如 10)导致网络往返过多;太大(如 10000)单次耗时仍可能达百毫秒;生产推荐 500–2000
- MATCH 只支持 glob:*、?、[a-z] 可用,正则表达式不支持
高并发场景下的关键避坑点
线上出问题,往往栽在细节:
- 游标类型错乱:某些 SDK(如旧版 Jedis)把字符串 "0" 当整数 0 传入,导致无限循环或报 ERR invalid cursor
- 忽略空响应:某次 SCAN 返回空数组但游标非 0,若此时中断循环,会漏掉后续大量 key
- Lua 脚本中误调 SCAN:Redis 明确禁止在脚本中使用 SCAN,会直接报 ERR Error running script
- 集群环境不能直接 SCAN:Redis Cluster 中 SCAN 只作用于当前 slot,需对每个节点单独执行,或改用 redis-cli --cluster call 配合脚本分发
结合 Pipeline 提效的实用模式
单纯 SCAN 只是“不卡”,要真正高效,得搭配批量操作:
- 先 SCAN 分批获取 key 列表(例如每次 1000 个)
- 将这批 key 组装成批量命令(如 DEL key1 key2 ... 或 MGET key1 key2 ...)
- 通过 pipeline 一次性发给 Redis,减少 RTT 次数
- Bash 示例中常用 redis-cli --pipe 接收标准输入流,吞吐提升 3–5 倍











