得物二面:Redis 如何高效安全的遍历所有 Key?(修订版)

张开发
2026/6/7 18:45:00 15 分钟阅读
得物二面:Redis 如何高效安全的遍历所有 Key?(修订版)
在线 Java 面试刷题已更新239题https://www.quanxiaoha.com/java-interview面试考察点基础掌握度面试官不仅仅是想知道SCAN命令怎么用更是想知道你是否清楚KEYS *为什么在生产环境被禁用以及SCAN基于游标的增量遍历是如何做到不阻塞 Redis 的。原理理解深度考察你是否了解SCAN的底层实现字典高位翻转算法、为什么可能返回重复元素、为什么可能漏掉新增的 Key以及COUNT参数的真正含义。生产实践经验能否给出完整的遍历方案如批量删除匹配的 Key、大 Key 扫描并知道如何处理SCAN的各种边界情况。核心答案方式命令阻塞性生产可用适用场景全量遍历KEYS pattern❌严重阻塞⚠️ 禁止仅调试 / 数据量极小增量遍历SCAN cursor [MATCH] [COUNT]✅ 不阻塞✅推荐生产环境遍历类型扫描SSCAN/HSCAN/ZSCAN✅ 不阻塞✅ 推荐遍历集合 / 哈希 / 有序集合一句话结论生产环境 **严禁使用KEYS**必须用SCAN系列命令基于游标增量遍历每次只返回少量结果不阻塞 Redis 主线程。深度解析一、为什么KEYS命令不能用于生产img上图展示了KEYS命令的危害单线程阻塞Redis 用单线程处理命令KEYS必须遍历完所有 Key 才能返回期间其他所有客户端的请求都被阻塞。内存暴涨如果有 1000 万个 Key返回结果可能占用数百 MB 内存。级联故障阻塞导致上游服务超时超时导致重试重试又加重 Redis 负载最终可能引发雪崩。结论KEYS只适合在数据量极小的开发 / 测试环境使用生产环境严禁使用。二、SCAN命令的工作原理img上图展示了SCAN的游标遍历机制游标从 0 开始第一次调用SCAN 0表示开始遍历。返回新游标每次调用返回一个新游标和一批 Key。下次调用使用新游标继续遍历。游标为 0 结束当返回的游标为 0 时表示遍历完成。不阻塞每次调用只处理一小批 Key由COUNT控制处理完就返回不阻塞其他客户端。三、SCAN的三个重要特性面试必问特性一可能返回重复的 Keyimg上图解释了SCAN可能返回重复 Key 的原因SCAN的游标算法不是简单的 桶编号 1而是高位翻转将桶编号的二进制位反转后加 1。这种设计是为了在 rehash 时仍然能正确遍历。当遍历过程中发生了 rehash哈希表扩容或缩容某些 Key 可能从旧位置迁移到了新位置导致被访问两次返回重复。解决方案客户端需要自行去重通常用HashSet记录已经见过的 Key。特性二可能漏掉新增的 Key遍历期间新增的 Key 有可能不会被返回。因为游标算法是按照固定的跳跃顺序遍历桶如果新 Key 被放入了已经遍历过的桶中就会被跳过。这是SCAN的设计取舍保证不阻塞牺牲一定的完整性。特性三COUNT不是精确返回数量COUNT只是建议值告诉 Redis 大约每次扫描多少个元素。实际返回的 Key 数量可能远少于COUNT比如COUNT 100可能只返回 10 个 Key因为大部分元素可能不匹配MATCH过滤条件。也可能多于COUNT在 rehash 场景下。四、SCAN系列命令全家桶命令遍历对象示例SCAN遍历整个数据库的所有 KeySCAN 0 MATCH user:* COUNT 100SSCAN遍历 Set 的所有元素SSCAN myset 0 COUNT 100HSCAN遍历 Hash 的所有 field-valueHSCAN myhash 0 MATCH field:* COUNT 100ZSCAN遍历 Sorted Set 的所有 member-scoreZSCAN myzset 0 COUNT 100五、生产实战批量删除匹配的 Key这是SCAN最常见的生产场景 —— 比如需要删除所有temp:*前缀的 Key/** * 安全批量删除匹配的 Key * 使用 SCAN 增量遍历 Pipeline 批量删除 */ public long safeDeleteKeys(String pattern) { long deletedCount 0; SetString batch new HashSet(); String cursor 0; do { // 1. SCAN 增量扫描 ScanResultString scanResult jedis.scan( cursor, new ScanParams().match(pattern).count(100) ); cursor scanResult.getCursor(); ListString keys scanResult.getResult(); if (!keys.isEmpty()) { batch.addAll(keys); // 2. 积累到一定数量后批量删除减少网络开销 if (batch.size() 500) { deletedCount batch.size(); Pipeline pipeline jedis.pipelined(); for (String key : batch) { pipeline.del(key); } pipeline.sync(); batch.clear(); } } } while (!0.equals(cursor)); // 游标为 0 表示遍历结束 // 3. 删除剩余的 Key if (!batch.isEmpty()) { deletedCount batch.size(); Pipeline pipeline jedis.pipelined(); for (String key : batch) { pipeline.del(key); } pipeline.sync(); } return deletedCount; } // 使用示例删除所有 temp: 开头的 Key long count safeDeleteKeys(temp:*); System.out.println(删除了 count 个 Key);关键点**用SCAN代替KEYS**增量遍历不阻塞 Redis。用 Pipeline 批量删除减少网络 RTT不用每删一个 Key 就发一次请求。客户端去重用HashSet收集 Key避免 SCAN 返回重复时重复删除。分批提交积累 500 个 Key 后批量删除避免一次性删除太多导致短暂阻塞。面试高频追问追问一SCAN的COUNT设多少合适默认值是 10生产环境一般设100~1000。设太小会增加遍历次数和网络开销设太大会增加单次处理时间。对于百万级 Key 的数据库COUNT 100通常每轮只需几毫秒不会影响 Redis 性能。如果 Key 特别多千万级可以适当增大到 500~1000。追问二Redis Cluster 中SCAN怎么用Redis Cluster 有 16384 个 slot每个节点只负责一部分 slot。需要在 **每个主节点上分别执行SCAN**可以用CLUSTER NODES获取所有主节点地址汇总结果。或者使用redis-cli --scan --pattern xxx:*命令它会自动遍历所有节点。追问三KEYS真的一点用都没有吗在以下场景可以有限度使用数据量极小的本地开发 / 测试环境确认数据库只有几十个 Key 的维护脚本。但任何可能连接生产环境的代码都不应该使用KEYS。常见面试变体变体一生产环境如何安全地批量删除 Key变体二RedisSCAN命令了解吗和KEYS的区别变体三SCAN遍历过程中有新增 Key 会怎样变体四如何在线上扫描 Redis 中的大 Key记忆口诀KEYS一次全扫阻塞全场 —— 核武器生产禁用。SCAN游标分批不阻塞 —— 机关枪点射模式。三大特性可能重复客户端去重、可能遗漏设计取舍、COUNT 不精确只是建议值。核心模式SCAN Pipeline 客户端去重 生产安全的批量操作。总结生产环境遍历 Redis 的所有 Key **必须使用SCAN**严禁使用KEYS。SCAN基于游标增量遍历每次只处理少量 Key不阻塞 Redis 主线程。需要注意SCAN的三个特性可能返回重复 Key需客户端去重、可能遗漏新增 Key、COUNT只是建议值。实际使用时配合 Pipeline 批量操作可以高效安全地完成批量删除、批量扫描等运维任务欢迎加入小哈的星球你将获得:专属的项目实战多个项目 / 1v1 提问 /Java 学习路线 /学习打卡 / 每月赠书 / 社群讨论新项目《Spring AI 项目实战》正在更新中..., 基于 Spring AI Spring Boot 3.x JDK 21;《从零手撸仿小红书微服务架构》 已完结基于 Spring Cloud Alibaba Spring Boot 3.x JDK 17..., 点击查看项目介绍演示地址http://116.62.199.48:7070/《从零手撸前后端分离博客项目全栈开发》2期已完结,演示链接http://116.62.199.48/;专栏阅读地址https://www.quanxiaoha.com/column截止目前累计输出 100w 字讲解图 4013 张还在持续爆肝中..后续还会上新更多项目目标是将 Java 领域典型的项目都整一波如秒杀系统, 在线商城, IM 即时通讯Spring Cloud Alibaba 等等戳我加入学习解锁全部项目已有4500小伙伴加入1. 我的私密学习小圈子从0到1手撸企业实战项目~ 2. Redis 只会用缓存16种妙用让同事直呼牛X 3. 滴滴二面怎么解决 Redis 缓存和数据库的一致性问题 4. 中国最难入职的八家 IT 公司最近面试BAT整理一份面试资料《Java面试BATJ通关手册》覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构等等。 获取方式点“在看”关注公众号并回复 Java 领取更多内容陆续奉上。PS因公众号平台更改了推送规则如果不想错过内容记得读完点一下“在看”加个“星标”这样每次新文章推送才会第一时间出现在你的订阅列表里。 点“在看”支持小哈呀谢谢啦

更多文章