SCAN 是什么
SCAN 是 Redis 提供的游标式增量遍历命令:每次调用只扫描一部分键并返回一个游标,调用方带上新游标继续下一轮,直到游标回到 0 表示遍历结束。它把大范围的枚举工作切成很多次轻量调用,中间可以插入其他请求,因此不会像 KEYS 那样长时间独占主线程。生产环境枚举键空间的唯一正确方式就是 SCAN 家族。
基本信息
| 语法 | SCAN cursor [MATCH pattern] [COUNT n] [TYPE type] |
|---|---|
| 结束条件 | 返回的游标为 0 |
| COUNT 语义 | 每批工作的提示值,不是返回条数上限,也不保证下限 |
| TYPE 过滤 | TYPE string|hash|list|set|zset|stream,需 6.0 及以上 |
| 性能 | 单次调用复杂度随 COUNT 变化,总体为 O(N),不阻塞服务 |
典型使用场景
- 批量清理某前缀的历史键,边扫边删并把无关键跳过,避免一次性删除引发大量阻塞
- 数据盘点与审计:统计某类键的数量、抽样检查 TTL 与编码是否符合预期
- 迁移或重建:把符合模式的键逐个读到应用侧,再写入新的数据结构或新实例
- 容量治理:结合 TYPE 过滤找出大 key、无 TTL 的键、本该淘汰却仍在的键
- 定时任务里做渐进式修复,把一次重活拆到多轮扫描之间,削掉尖峰
常用示例
常用示例
redis-cli SCAN 0 MATCH user:* COUNT 1000 # 首轮扫描,COUNT 只是提示
redis-cli SCAN 12345 MATCH user:* COUNT 1000 # 用返回的游标继续
redis-cli SCAN 0 COUNT 1000 TYPE hash # 只找 hash 类型的键
redis-cli HSCAN user:1001 0 COUNT 100 # 遍历单个 Hash 的字段
redis-cli SSCAN tags 0 MATCH 'go*' # 遍历 Set 成员
redis-cli ZSCAN board 0 COUNT 100 # 遍历 ZSet 成员与分数
redis-cli --scan --pattern 'user:*' # redis-cli 封装的循环扫描SCAN 家族对照
| 命令 | 遍历对象 | 返回内容 |
|---|---|---|
| SCAN | 当前库的全部键 | 键名 |
| HSCAN | 指定 Hash | 字段与值成对返回 |
| SSCAN | 指定 Set | 成员 |
| ZSCAN | 指定 ZSet | 成员与其分数成对返回 |
| MATCH | 过滤模式 | glob 风格,如 user:* 与 a?c |
SCAN 的保证与不保证:保证遍历期间一直存在、从头到尾没被删过的键一定会被返回;不保证返回结果不重复,也不保证遍历期间新增或删除的键被如何对待。因此消费端必须能容忍重复,实现上常用幂等写入或集合去重。
COUNT 的作用是调节每批工作量:值太小会导致往返次数暴增、总耗时变长;值太大会让单次调用变重,靠近 KEYS 的阻塞表现。默认 10 偏保守,线上批量任务常用 100 到 1000,并在压测环境确认单次调用的耗时。
不要在业务高峰期对全库执行 KEYS:KEYS 是 O(N) 且一次性扫描全部键,会阻塞主线程直到扫完,几百万键的实例上足以造成秒级停顿并引发超时雪崩。HGETALL、SMEMBERS、LRANGE key 0 -1 对超大集合有同样的风险。