scan在redis集群中只扫描当前节点是分片机制决定的正常行为,非设计缺陷;它仅作用于所连节点负责的slot,不感知集群拓扑,也不会重定向或报错,需手动遍历所有master节点并聚合结果。

SCAN在Redis集群里只扫当前节点,不是设计缺陷,是分片机制决定的
Redis集群把16384个slot分散到多个节点,SCAN命令本身不感知集群拓扑——它只对当前连接的节点生效。你连上节点A执行SCAN 0,它只会查A负责的那部分slot里的key,其余16383个slot的数据根本不会被触达。这不是bug,而是分片系统的基本约束:命令作用域天然受限于路由终点。
直接连单个节点SCAN会漏掉99%数据,且不报错
常见误操作是用redis-cli -h node-a -p 6379 SCAN 0 MATCH *,看起来执行成功、返回了一堆key,但实际可能只覆盖了不到1%的全量数据。更危险的是:它不会提示“你只扫了部分”,也不会报错或警告。漏扫是静默发生的,尤其当你的key分布不均(比如大量key集中在少数slot)时,问题更隐蔽。
- 若该节点是slave,且
slave-read-only yes(默认),SCAN会直接返回READONLY You can't write against a read only slave.错误 - 若连的是master,但key不属于它的slot范围,
SCAN会安静地跳过,不重定向也不报错 - 用
redis-cli -c(集群模式)执行SCAN,行为不可控:可能随机重定向,也可能卡在某个游标不动,无法保证收敛
正确做法:先获取所有Master节点,再逐个SCAN并拼接结果
必须手动做两件事:定位所有主节点 + 对每个主节点独立发起完整SCAN循环。关键点不在“怎么SCAN”,而在“扫谁”和“怎么聚合”:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 用
CLUSTER NODES获取节点列表,过滤出角色为master、状态非fail、且有有效地址(非noaddr)的行 - 对每个master节点,单独建立连接,执行
SCAN 0 MATCH * COUNT 1000循环,直到游标返回"0"才认为该节点扫完 - 结果需去重:不同节点间不可能有重复key(slot唯一),但同一节点内
SCAN本身可能因rehash重复返回某些key,建议用Set结构暂存 - 别并发扫全部16384个slot——实际只需扫master节点数(通常3–7个),但每个节点内部SCAN要串行迭代,避免压垮单节点
Spring Boot或JedisCluster调用SCAN时,默认只打到一个节点
像RedisTemplate.scan()或JedisCluster.scan()这类封装,底层往往只取哈希槽0所在节点发起请求,其余slot完全遗漏。日志里看到cursor=0就停,或者返回数量远少于DBSIZE,基本就是这个原因。
- Spring Boot中需弃用默认
RedisTemplate,改用JedisCluster实例,再调用getClusterNodes()遍历 - 不要依赖
SCAN返回空列表就终止——必须以游标是否为"0"为唯一结束条件 - count值建议设为1000~5000:太小(如10)导致网络往返次数爆炸;太大(如20000)可能触发单次响应超时或OOM
真正容易被忽略的不是“怎么写脚本”,而是对游标状态的机械处理——比如把SCAN响应第一项当成key、忽略后续游标值、或中断后硬重置为0。这些都会让漏扫变成必然,而不是概率事件。










