Redis SCAN 游标分页的重复处理与幂等遍历方案
Redis SCAN 不是“每次固定返回一页”的分页接口:某一轮返回空数组不代表结束,重复 key 也不一定是 Redis 出错。可靠的做法是让游标决定是否结束,再让业务处理具备去重或幂等能力。
官方地址:https://redis.io/docs/latest/commands/scan/
- 从游标 0 开始,始终使用上一次返回的游标;只有返回 0 才结束。
MATCH、TYPE和COUNT改变筛选或工作提示,不能当作稳定分页协议。- 重复结果要么由本次任务的
seen集合过滤,要么交给可重复执行的副作用收敛。
先把游标和返回集合分开理解
SCAN cursor [MATCH pattern] [COUNT count] [TYPE type] 每次返回两个值:新的 cursor 和本次拿到的 key。第一次传 0,随后把服务端返回的 cursor 原样传回;当 cursor 再次变为 0,才完成一次 full iteration。Redis 官方还明确说明,单次返回数量没有固定保证,甚至可能返回空集合,所以不能写成“keys 为空就 break”。

以 COUNT 100 为例,它只是告诉 Redis 每轮大致投入多少扫描工作,并不承诺返回 100 个 key。MATCH 过滤发生在取出元素之后,匹配很少时连续出现空页是正常现象;此时仍要继续推进游标。
重复结果要在业务层收敛
SCAN 只保存一个游标,集合在遍历过程中又可能扩缩容,因此同一个元素可能被返回多次。小规模、需要一次性汇总的任务可以把 seen 集合放在整次遍历的生命周期内;但 key 数量很大时,内存去重本身也会变成压力。清理、刷新索引、补写标记这类操作,更适合设计成重复执行不会改变最终结果的幂等动作。
// ScanAndApply 按游标遍历 key,并在本次任务内过滤重复结果。
func ScanAndApply(ctx context.Context, rdb *redis.Client, match string, apply func(string) error) error {
cursor := uint64(0)
seen := make(map[string]struct{}) // 小批量任务使用;超大任务应改用幂等副作用
for {
keys, next, err := rdb.Scan(ctx, cursor, match, 100).Result()
if err != nil {
return fmt.Errorf("scan cursor %d: %w", cursor, err) // 保留游标,便于日志定位
}
for _, key := range keys {
if _, exists := seen[key]; exists {
continue // 重复返回不再次执行非幂等动作
}
seen[key] = struct{}{}
if err := apply(key); err != nil {
return fmt.Errorf("apply key %q: %w", key, err) // 业务失败立即交给上层重试
}
}
cursor = next
if cursor == 0 {
return nil // 空页也走到这里,只有游标归零才完成
}
}
}
这段模板适合有限规模的一次性任务。若任务要覆盖数百万 key,不要盲目扩大 seen;可以把处理记录写入带任务 ID 的 Redis Set 或数据库唯一键,让重复调用自然收敛,同时保留失败重试能力。

参数选择与数据变化期间的边界
| 参数或现象 | 正确理解 | 处理建议 |
|---|---|---|
| cursor | 服务端返回的下一位置 | 原样传递,直到变为 0 |
| COUNT | 每轮工作量提示 | 按延迟和负载调节,不当页大小 |
| MATCH | 返回前过滤 | 允许空页,不能提前结束 |
| 遍历中增删 key | 结果可能重复、遗漏或不稳定 | 缩短单轮时间,副作用保持幂等 |
如果必须生成严格一致的快照,SCAN 不是这个协议;它的价值是把大集合拆成小步读取,减少长时间阻塞。生产任务还应记录任务 ID、最近一次 cursor、已处理数量和最后一个错误,失败后从头重跑时依靠幂等设计兜底,而不是把 cursor 当成永久断点。
常见问题
SCAN 返回空数组是不是扫描结束?
不是。只有返回的 cursor 等于 0 才结束;MATCH 稀疏或 COUNT 较小时出现空页很常见。
COUNT 设置成 100 是否一定返回 100 个 key?
不一定。COUNT 是工作量提示,返回数量可能更少、更多或为零,调用方必须继续使用返回游标。
重复 key 应该全部放进 seen 集合吗?
小批量汇总可以这样做;大批量任务更应让删除、写标记或刷新动作可重复执行,再用任务记录或唯一约束控制最终状态。
Redis Query Engine JSON 路径索引的字段设计
- 上一篇
- Redis Query Engine JSON 路径索引的字段设计
- 下一篇
- Redis Sentinel 认证配置的一致性清单
-
- 数据库 · Redis | 1小时前 |
- Redis RDB 与 AOF 持久化组合的恢复取舍
- 157浏览 收藏
-
- 数据库 · Redis | 1小时前 | redis sentinel 认证配置 masterauth
- Redis Sentinel 认证配置的一致性清单
- 393浏览 收藏
-
- 数据库 · Redis | 1小时前 |
- Redis Query Engine JSON 路径索引的字段设计
- 137浏览 收藏
-
- 数据库 · Redis | 12小时前 |
- Redis EXPIRE 条件参数如何避免覆盖更长 TTL
- 207浏览 收藏
-
- 数据库 · Redis | 12小时前 |
- Redis Cluster 槽位统计辅助容量规划的方法
- 137浏览 收藏
-
- 数据库 · Redis | 13小时前 |
- Redis Pipeline 降低往返延迟的批量边界
- 321浏览 收藏
-
- 数据库 · Redis | 13小时前 |
- Redis ACL 按命令类别限制应用权限的配置
- 115浏览 收藏
-
- 数据库 · Redis | 13小时前 | Redis · cluster · redis Redis Cluster CROSSSLOT Hash Tag hash slot
- Redis Cluster 多 key 操作的哈希标签设计
- 246浏览 收藏
-
- 数据库 · Redis | 13小时前 |
- Redis GEOSEARCH 查询附近地点的范围条件
- 116浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 500次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 559次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 587次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 539次使用
-
- MMBench
- MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
- 350次使用
-
- MySQL 明明加了索引,为什么查询还是很慢?先查这 6 个点
- 2026-06-27 374浏览
-
- 接口返回的数据和数据库不一致怎么办?按数据生命周期排查
- 2026-06-27 398浏览
-
- Go与Redis实现分布式互斥锁和红锁
- 2022-12-22 117浏览
-
- Go+Redis实现延迟队列实操
- 2023-02-23 426浏览
-
- 关于golangtest缓存问题
- 2023-01-01 298浏览
