尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
Redis面试常问2-- 从海量数据里查询某一固定前缀的key? SCAN cursor 实战避坑指南
1. 从十亿 key 里捞出固定前缀为什么 KEYS 一按就出事面试官抛出「10 亿个 key 里找某个固定前缀的 10 万个」时很多人第一反应是KEYS k1*。这条命令在本地测试库上跑得飞快因为你的测试库可能只有几千个 key。但线上 Redis 是单线程处理命令的KEYS会一次性扫描整个键空间把匹配结果全部攒进内存再返回。10 亿 key 的库上执行一次Redis 主线程会被占住几秒甚至几十秒期间所有其他请求全部排队等待表现为接口大面积超时、连接池被打满、监控上 QPS 断崖式下跌。所以这道题真正考的不是「怎么查」而是「怎么在不阻塞服务的前提下查」。答案是SCAN系列命令它把一次全量遍历拆成多次小步遍历每次只返回一小批 key 和一个游标cursor你拿着游标继续下一次直到游标回到 0 表示遍历结束。整个过程 Redis 主线程只在每次调用时短暂工作其他请求可以穿插执行。SCAN适合谁适合所有需要在生产环境按前缀、按模式批量处理 key 的场景清理过期缓存、统计某业务线 key 数量、迁移数据、排查脏数据。它不适合要求强一致快照的场景因为遍历期间 key 可能被增删改SCAN只保证「在遍历期间一直存在的 key 一定会被返回一次」不保证不重复、不保证返回顺序。先把几个关键点说清楚后面配置和脚本都围绕它们展开SCAN cursor MATCH pattern COUNT count是完整形态。cursor是游标第一次传 0MATCH是模式匹配比如k1*COUNT是每次扫描的提示数量注意是提示不是精确值Redis 可能返回 0 个也可能返回几十个。返回值是一个二元组新的游标 这一批 key 列表。新游标为 0 时结束。MATCH是在服务端对每个扫描到的 key 做模式匹配被过滤掉的 key 不返回但它们仍然消耗了这次扫描的额度。这意味着如果你前缀命中率很低比如 10 亿里只有 10 万个匹配你可能要扫很多轮才凑齐但每轮依然很快不会阻塞。COUNT默认是 10这个值偏小海量数据下会导致往返次数极多。调大能减少网络往返但单次扫描时间会变长。经验值放在 100 到 1000 之间比较稳具体看你的 key 总量和能接受的单次延迟。还有一个容易忽略的点SCAN的游标不是「偏移量」不能理解成第几个 key。它是 Redis 内部哈希表桶的遍历位置所以你不能用「游标除以总数」来估算进度。判断是否遍历完唯一标准就是游标是否回到 0。理解了这些你就明白为什么面试官要追问数据规模和场景规模决定COUNT怎么调场景决定要不要去重、能不能容忍重复。下面进入实操先解决「在哪跑、用什么连」的问题。2. TaoToken 前置准备把调用入口和 Key 配好要跑通后面的脚本你得有一个能发 Redis 命令或者能调用大模型帮你生成/调试脚本的环境。这里我用 TaoToken 作为统一的接入入口来演示因为它同时提供模型对话和 API 调用能力调试脚本、生成代码、验证请求都能在一个地方完成省得来回切工具。TaoToken 是什么、能做什么它是一个聚合式的 AI 能力接入平台你可以把它理解成一个统一的「调用网关」把模型对话、API Key 管理、编码辅助这些能力收拢到一套账号和一套 Key 下。适合谁适合需要快速验证脚本、又不想在多个平台之间反复注册配置的开发者尤其是做 Redis 运维脚本、批量数据处理这类需要边写边调的场景。第一步打开官网注册并登录。地址是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 注册流程就是常规的邮箱加密码登录后进入控制台。第二步创建 API Key。进入控制台后找到 API Keys 页面路径是 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 。点新建给它起个能认出来的名字比如redis-scan-debug然后复制生成的 Key。这个 Key 只显示一次先存到安全的地方后面配置里要用。第三步确认你要用的模型 ID。在模型对话页面 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentmodel-chatutm_campaignrewrite 里可以看到当前可选的模型列表记下你打算用的那个 Model ID比如某个通用对话模型或者代码模型。后面配置里 Base URL、API Key、Model ID 这三件套要配套使用缺一个都调不通。如果你是要做长期的编码和 Agent 任务比如持续生成和优化 Redis 运维脚本可以看下 Coding Plan 页面 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 它更适合高频、长周期的编码场景。只是临时验证脚本的话用按量的 API 就够了。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 里面写了不同语言和工具的接入方式遇到报错先翻这里。API 的基础地址是 https://taotoken.net/api 注意这个地址不带任何查询参数配置 Base URL 时就用它。这里要提醒一句TaoToken 是帮你调用模型和 API 的入口不是 Redis 本身。你的 Redis 实例还是你自己的脚本连的是你的 Redis 地址。TaoToken 的作用是让你在写脚本、排错、生成配置的时候有个顺手的 AI 辅助环境。把 Key 和模型配好之后我们就可以进入真正的 SCAN 脚本环节了。3. 可复制的 SCAN 游标循环配置与脚本这一节是核心给你能直接抄走改改就用的东西。先给一份配置片段把 Base URL、Key、Model ID 三件套写清楚这样你用任何兼容 OpenAI 协议的工具都能接上 TaoToken。{ base_url: https://taotoken.net/api, api_key: sk-你的TaoToken密钥, model_id: 你的模型ID, timeout: 60 }如果你用的是 Claude Code 这类工具配置通常放在 settings 文件里格式类似这样{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_API_KEY: sk-你的TaoToken密钥, ANTHROPIC_MODEL: 你的模型ID } }注意ANTHROPIC_BASE_URL后面不要加/v1之类的后缀就用https://taotoken.net/api具体以接入文档为准。Key 和 Model ID 必须和你在控制台看到的一致写错了会直接 401。配置好之后重点来了SCAN 的游标循环脚本。下面给 Python 版本用redis-py逻辑清晰改前缀就能用。import redis r redis.Redis(host127.0.0.1, port6379, db0, password你的密码, decode_responsesTrue) def scan_by_prefix(pattern, count500, batch_limitNone): cursor 0 seen set() total 0 while True: cursor, keys r.scan(cursorcursor, matchpattern, countcount) for k in keys: if k not in seen: seen.add(k) total 1 # 这里处理你的业务逻辑比如打印、写文件、删除 print(k) if batch_limit and total batch_limit: break if cursor 0: break return seen if __name__ __main__: result scan_by_prefix(k1*, count500) print(f共获取 {len(result)} 个 key)几个参数说明。pattern就是你的前缀加星号比如k1*。count500是每轮扫描提示数量海量数据下别用默认的 10。seen这个 set 用来去重因为 SCAN 在遍历期间如果发生 rehash同一个 key 可能被返回多次这是官方文档明确说明的行为不是 bug。batch_limit是可选的如果你只想拿前 10 万个就停可以设上避免全量扫完浪费时间。如果你用 JavaJedis 或 Lettuce 的写法类似核心都是ScanParams加循环ScanParams params new ScanParams().match(k1*).count(500); String cursor 0; SetString result new HashSet(); do { ScanResultString scanResult jedis.scan(cursor, params); result.addAll(scanResult.getResult()); cursor scanResult.getCursor(); } while (!0.equals(cursor));关键点count是提示值Redis 可能返回比它多也可能比它少不要写依赖精确数量的逻辑。match在服务端过滤命中率低时多扫几轮是正常的。游标用字符串接收不要转成整数因为大 key 空间下游标可能超出 int 范围。还有一个实战技巧如果你要处理的是删除操作不要边扫边删同一个前缀因为删除会改变哈希表结构可能影响遍历完整性。稳妥做法是先扫出来存到集合或临时文件再批量删。或者用SCAN扫出来后分批UNLINK非阻塞删除比DEL更友好。配置和脚本都齐了接下来验证它到底跑没跑通、结果对不对。4. 验证请求与遍历完整性怎么确认没漏没重脚本写完不代表就对了得验证。验证分两层一是请求本身通不通二是遍历结果完不完整。先验证请求。如果你是用 TaoToken 的模型对话来辅助调试直接在对话页面发一条测试消息看能不能正常返回。如果是用 API 方式用 curl 打一发curl https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer sk-你的TaoToken密钥 \ -H Content-Type: application/json \ -d { model: 你的模型ID, messages: [{role: user, content: 帮我检查这段 Redis SCAN 脚本有没有死循环风险}] }返回里有choices数组且内容正常说明 Base URL、Key、Model ID 三件套配对了。如果返回 401是 Key 问题如果报连接失败检查 Base URL 是不是写成了带/v1的地址。再验证 Redis 侧的遍历完整性。最直接的办法是造一批已知数据做对照。比如你先用脚本往 Redis 里写 10000 个k1:开头的 key 和 5000 个other:开头的 key然后用 SCAN 脚本扫k1*看结果是不是正好 10000 个去重后。如果少了说明循环提前退出了如果多了说明去重没做好或者匹配模式写宽了。# 造数据 for i in range(10000): r.set(fk1:{i}, v) for i in range(5000): r.set(fother:{i}, v) # 验证 result scan_by_prefix(k1*, count500) assert len(result) 10000, f期望 10000实际 {len(result)} print(遍历完整性验证通过)实测下来count设太小比如默认 10时10 亿 key 的库要跑几百万轮网络往返开销巨大脚本可能跑几个小时。把count调到 500 到 1000往返次数降到几十万甚至几万速度快很多。但count也不是越大越好设成 10000 时单次扫描时间变长可能触发客户端超时而且 Redis 主线程单次占用时间增加影响其他请求。折中在 500 左右比较稳。还有一个验证遍历是否完整的思路记录每轮返回的游标确认它最终回到了 0。如果脚本因为异常中断游标不会归零你下次可以从上次的游标继续但要注意这期间数据可能变了续扫的结果不保证和一次性扫完一致。关于重复SCAN 可能返回重复 key这是设计使然。所以你的业务逻辑必须幂等或者像上面脚本那样用 set 去重。如果你扫出来直接做删除重复删除同一个 key 第二次会返回 0不影响正确性但如果你做的是计数累加就必须去重否则数字会偏大。验证通过后还有一类问题专门等着你报错。下一节把常见错排一遍。5. 常见报错排查401、local proxy failed、reading choices、OAuth跑脚本和调 API 的过程中报错基本集中在几类。逐个对照。401 Unauthorized。这个最常见原因就三个Key 写错、Key 过期或被删、Key 和 Base URL 不匹配。先检查你复制 Key 的时候有没有带上多余空格再确认控制台里这个 Key 还在不在。如果你用的是环境变量打印出来看看有没有被截断。Base URL 必须是https://taotoken.net/api写成别的域名或者加了错误后缀都会导致鉴权失败。local proxy failed / connection refused。这类报错说明请求根本没发出去或者发到了错误的地址。检查你的网络能不能访问taotoken.net检查 Base URL 有没有拼写错误检查是不是本地配了什么代理把请求拦了。如果你在容器里跑确认容器的 DNS 和出网策略正常。这个错和 Redis 本身无关是调用链路的问题。reading choices 相关报错比如cannot read property choices of undefined或者解析响应时拿不到choices字段。这通常意味着返回的不是标准结构可能是错误响应被当成功响应解析了。先打印完整响应体看看多半里面是error字段而不是choices。常见诱因是 Model ID 写错服务端返回了模型不存在的错误或者请求体格式不对比如messages写成了字符串。对照接入文档里的请求示例逐字段核对。OAuth 相关报错。如果你用的是 Claude Code 这类带 OAuth 流程的工具报 OAuth 错误通常是认证配置没走通。检查ANTHROPIC_BASE_URL和ANTHROPIC_API_KEY是否都配了有些工具要求两者同时存在。如果工具提示需要登录确认你用的是 API Key 模式而不是交互式登录模式。配置改完后重启工具很多 OAuth 报错是旧配置缓存导致的。SCAN 脚本自身的坑。除了 API 报错脚本层面也有几个高频问题。一是死循环如果游标处理逻辑写错比如把返回的游标字符串当整数比较或者忘了更新 cursor 变量就会一直循环。二是漏 key如果你在遍历过程中删除了大量 key哈希表收缩可能导致部分 key 被跳过这是 SCAN 的已知行为解决办法是先扫后删。三是内存爆掉如果你把扫出来的 key 全塞进一个 list 而不去重10 亿 key 能把内存吃光用 set 或者边扫边处理。COUNT 设太大导致超时。有人为了减少往返把count设成 100000结果单次 SCAN 耗时几百毫秒客户端超时断开。Redis 的 SCAN 单次执行时间大致和count成正比生产环境建议不超过 1000具体压测后定。MATCH 模式写错导致扫不到。k1*匹配的是以k1开头的所有 key包括k1、k1abc、k1:123。如果你想匹配k1:开头必须写k1:*少个冒号结果完全不同。模式里的特殊字符要转义比如 key 里本身有*或?。排完这些错脚本基本就能稳定跑了。最后说下长期用的话怎么组织。6. 长期编码与 Agent 场景把 SCAN 脚本沉淀成可复用工具单次排查用完就扔的脚本和长期维护的工具写法不一样。如果你经常要做「按前缀清理」「按前缀统计」这类操作建议把 SCAN 逻辑封装成一个命令行工具参数化前缀、count、是否删除、批量大小这样每次不用重写。封装的时候有几个设计点值得注意。第一把去重和业务处理分开SCAN 层只负责稳定地产出 key业务层决定是打印、写文件还是删除。第二加进度输出海量数据下跑几分钟没动静会让人以为卡死了每处理 N 个 key 打印一次进度。第三加中断续跑能力把当前游标持久化异常退出后能从断点继续但要在文档里写清楚续跑不保证和一次性扫完完全一致。如果你用 Agent 来做这类运维任务比如让 Agent 自动生成清理脚本、自动分析 key 分布那 Coding Plan 会更合适地址是 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 。它面向的是长周期的编码和 Agent 调用比按次调用更适合这种持续性的工作流。实际用的时候我一般会这样组织把 Redis 连接配置、SCAN 封装、业务处理分成三个模块配置从环境变量读SCAN 封装成生成器函数业务处理按需传入回调。这样同一套 SCAN 逻辑能复用到清理、统计、迁移多个场景不用每次复制粘贴。def scan_iter(r, pattern, count500): cursor 0 while True: cursor, keys r.scan(cursorcursor, matchpattern, countcount) for k in keys: yield k if cursor 0: break # 复用统计 total sum(1 for _ in scan_iter(r, k1*)) # 复用清理 for k in scan_iter(r, temp:*): r.unlink(k)生成器写法比一次性返回 set 更省内存适合 key 量极大的场景。注意清理场景下unlink比del好它把删除操作放到后台线程不阻塞主线程。最后留一个实用提醒SCAN 的count和你的 Redis 实例规格、当前负载有关没有万能值。上线前在从库或者低峰期压测一下找到单次延迟和总耗时的平衡点。另外如果你的 Redis 是集群模式SCAN 只扫当前节点要遍历所有节点得对每个 master 分别执行这点在写工具的时候要考虑到否则会漏掉其他分片的 key。
RELATED

相关推荐

Natron Backdrop 节点完全指南:用分组容器组织节点图的实战与源码解析

Natron Backdrop 节点完全指南:用分组容器组织节点图的实战与源码解析

音视频视频处理图形学桌面应用 【免费下载链接】Natron Open-source video compositing software. Node-graph based. Similar in functionalities to Adobe After Effects and Nuke by The Foundry. 项目地址: https://gitcode.com/gh_mirrors/na/Natron 点击查看 …

📅 2026/10/15 17:39:00
小公司的合同管理,分三层就够了

小公司的合同管理,分三层就够了

公司用 Excel 和微信群管合同,多数不是因为不重视,而是因为不清楚哪些环节需要有人盯着;而恰恰是几个看起来不起眼的环节,会在履约期内留下隐患,产生扯皮、丢单、坏账的后果。合同大多分散在销售的笔记本、老板的邮箱、…

📅 2026/10/15 17:39:00
QGroundControl Log Setup 配置指南:ArduPilot 飞行控制器日志参数详解

QGroundControl Log Setup 配置指南:ArduPilot 飞行控制器日志参数详解

无人机智能硬件 【免费下载链接】qgroundcontrol Cross-platform ground control station for drones (Android, iOS, Mac OS, Linux, Windows) 项目地址: https://gitcode.com/gh_mirrors/qg/qgroundcontrol 点击查看 免费下载 本文基于仓库中的用户指南文档 docs…

📅 2026/10/15 17:39:00
MORE NEWS

更多资讯

📰

Oransim路线图前瞻:从v0.2到因果基础模型,闭环AI媒体投放与百万级智能体集群的完整规划

【免费下载链接】oransim Causal Digital Twin for Marketing at Scale Predict any marketing decision before you spend a dollar. 项目地址: https://gitcode.com/gh_mirrors/or/oransim 点击查看 免费下载 Oransim 是一个开源的营销因果数字孪生框架&#xf…

📰

OmniDrive是什么?一款让MT1959光驱通吃游戏光盘的开源固件破解工具完整解析

【免费下载链接】OmniDrive 项目地址: https://gitcode.com/gh_mirrors/omn/OmniDrive 点击查看 免费下载 OmniDrive 是一款面向 MediaTek MT1959 芯片光驱的开源固件修改工具,专为 Hitachi-LG Data Storage 光驱打造。刷入它之后,普通光驱就…

📰

ROS导航/odom轨迹可视化:从rosbag离线绘制到matplotlib实时显示

做机器人导航调试的时候,除了在 rviz 里盯着机器人实时跑,我经常需要把/odom发出来的轨迹单独拉出来画成一张图——比如比赛复盘、实验报告、论文插图,或者单纯想对比两版参数谁的路径更平滑。这个需求看着不起眼,真动手写的时候&…

📰

libssh2在Windows下的编译、链接与运行避坑指南

简介:libssh2 1.7.0的Windows开发包为使用Visual Studio 2015的C/C开发者提供了完整的SSH/SFTP集成支持。其中包含编译好的静态库与动态链接库,以及配套头文件,解决在Win10环境下开发时为库文件缺失或版本不匹配而烦恼的问题。压缩包共6个文件…

📰

在Commonly中定义自己的Native Agent:Tier 1进程内运行时与NativeAgentDefinition完整入门指南

【免费下载链接】commonly Open-source room for humans cross-vendor AI agents. Every agent gets its own name, memory, skills, and workstation. Any runtime, your infra — no per-agent fees. 项目地址: https://gitcode.com/gh_mirrors/co/commonly 点击…

📰

Zint+Zlib+Libpng预编译库集成指南:依赖链与避坑要点

简介:这套面向 Windows 开发者的预编译库包,内含 Zint、Zlib 与 Libpng 三大开源库的完整编译产物,专为 Visual Studio 2015 环境设计,提供 32 位与 64 位、Debug 和 Release 版本,可直接集成到项目中实现条形码/二维码…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬