导读:本期聚焦于零壳创作的《Redis Keys命令怎么用?一文讲清语法、风险与替代方案》,敬请观看详情。为什么生产环境要慎用Redis的Keys命令?这个看似简单的模糊查询指令,在键数量达到百万级时可能让整个Redis实例阻塞数秒甚至更久。本文从Keys命令的基本语法与通配符用法讲起,详细分析它的时间复杂度、阻塞原理,以及误用引发的线上事故场景,并给出SCAN迭代遍历、分批删除等安全替代方案。同时汇总了Keys命令的常见问题,比如为什么Keys会卡住、生产环境如何安全查找键、SCAN和Keys的区别是什么,看完这篇你就能彻底掌握Redis键管理的正确姿势。

Redis的KEYS命令大概是初学者最先学会、也是最容易在生产环境闯祸的命令之一。它能按照给定的模式匹配数据库中的键,用起来非常方便,但官方文档明确警告:不要在生产环境使用。这篇文章会把KEYS命令的语法、原理、风险以及替代方案讲透,帮助你在实际项目中做出正确选择。

Redis Keys命令怎么用?一文讲清语法、风险与替代方案

一、Keys命令的基本语法与通配符用法

KEYS命令的语法非常简单,只接受一个参数pattern,用于匹配键名。返回值是所有匹配到的键名组成的数组。它支持三种通配符:?匹配任意单个字符,*匹配任意数量字符(包括零个),[abc]匹配方括号中的任意一个字符。例如KEYS user:*可以找出所有以user:开头的键,KEYS user:??:1001可以匹配user:zhang:1001这类固定长度的结构。

# 连接redis后执行
redis> KEYS *
1) "user:1001"
2) "order:2001"
3) "session:abc"

redis> KEYS user:*
1) "user:1001"
2) "user:1002"

redis> KEYS user:10[12][0-9]
1) "user:1001"
2) "user:1002"

还可以用\转义通配符本身,比如想匹配字面上的星号字符,可以写成KEYS user:\*。此外[a-c]这种范围写法也是支持的,表示a、b、c三个字符中的任意一个。需要注意的是,这些匹配是大小写敏感的,userUser会被视为完全不同的前缀。

从功能上看,KEYS似乎是个查找利器,但它的实现方式决定了它的性能特征:Redis是单线程处理命令的(忽略持久化线程等辅助线程),KEYS执行时需要遍历整个键空间,逐一与模式做匹配,并且把所有匹配结果一次性收集完才返回。这意味着不管匹配到多少个键,它都要把整个数据库扫一遍。

二、为什么生产环境要禁用Keys命令

KEYS的时间复杂度是O(N),N是数据库中的键总数。注意这里的N不是匹配结果的数量,而是全库键的数量。假设你的Redis里存了两百万个键,执行一次KEYS user:*,即使只匹配到十个键,Redis也必须遍历这两百万个键才能返回结果。

更严重的问题在于阻塞。Redis的主线程在执行KEYS期间无法处理其他任何命令,如果键数量庞大,这个命令可能耗时几百毫秒到几秒钟。在这段时间内,所有业务请求都会被排队等待,上游应用可能出现大量超时,进而引发连接堆积、缓存雪崩等连锁反应。很多线上事故的剧本都是相似的:运维想清理一批缓存,随手敲了个KEYS xxx*,结果整个服务瞬间不可用。

还有一个容易被忽视的问题是返回值体积。如果匹配到几十万个键,KEYS会一次性把这些键名全部序列化返回,这个响应可能达到几十MB甚至更大,传输过程中占用大量网络带宽和客户端内存。如果用Jedis这类同步客户端接收,还可能直接触发内存溢出。

正因为如此,很多公司的Redis使用规范里直接把KEYS列为禁用命令,云厂商如阿里云、腾讯云的Proxy架构Redis甚至会直接拦截这个命令。如果确实需要模糊查找能力,正确的设计方式是在写入键时同步维护一个Set作为索引,比如把所有user:1001格式的键名存进user:index这个集合里,查找时用SMEMBERS即可,复杂度可控且不阻塞。

三、安全替代方案:SCAN迭代遍历

从Redis 2.8.0开始,官方提供了SCAN命令作为KEYS的安全替代。它同样支持通配符模式匹配,但采用增量式迭代:每次调用只扫描键空间的一小部分并返回一个游标,客户端拿着游标再次调用,直到游标返回0表示遍历完成。

# SCAN cursor [MATCH pattern] [COUNT count] [TYPE type]
redis> SCAN 0 MATCH user:* COUNT 100
1) "45"              # 下一次迭代使用的游标
2) 1) "user:1001"
   2) "user:1088"

redis> SCAN 45 MATCH user:* COUNT 100
1) "0"               # 游标为0表示遍历结束
2) 1) "user:2003"

SCAN的核心优势在于每次只做少量工作就交还CPU,让Redis有机会处理其他命令,整个过程不会造成明显阻塞。COUNT参数只是每次扫描的期望数量提示,并非精确值,默认为10,生产环境通常调到几百以平衡效率和平滑度。在代码中用一个循环即可完成完整遍历,以Java的Jedis为例:

ScanParams params = new ScanParams();
params.match("user:*");
params.count(500);
String cursor = ScanParams.SCAN_POINTER_START;
List<String> allKeys = new ArrayList<>();
do {
    ScanResult<String> result = jedis.scan(cursor, params);
    allKeys.addAll(result.getResult());
    cursor = result.getCursor();
} while (!"0".equals(cursor));

使用SCAN时有两个注意点。第一,它保证遍历开始到结束期间一直存在的键至少被返回一次,但可能在同一次遍历中重复返回某个键,所以业务代码要做去重或幂等处理。第二,遍历过程中新增或删除的键是否被返回是不确定的,如果需要强一致性快照,SCAN无法满足,只能考虑在从库上执行或使用其他设计。

另外,SCAN还有几个面向特定数据结构的兄弟命令:SSCAN遍历集合、HSCAN遍历哈希、ZSCAN遍历有序集合。这些命令的存在也是为了解决大集合上执行SMEMBERSHGETALLZRANGE全量读取时的阻塞问题,使用思路与SCAN完全一致。

四、常见问题解答

问题1:Keys执行很慢或者卡住了怎么办?如果在执行中无法中断,只能等待其完成,Redis没有提供终止正在执行的命令的手段。这也是建议配置lazyfree-lazy-expire和合理命令超时监控的原因。事后应立刻把客户端的这类调用改为SCAN方案。

问题2:如何安全地批量删除匹配的键?先通过SCAN迭代拿到键名,再分批调用UNLINK删除。UNLINKDEL的区别在于它只从键空间摘除键,实际的内存回收交给后台线程异步完成,删除大键时不会长时间阻塞主线程。

redis> SCAN 0 MATCH session:* COUNT 200
1) "127"
2) 1) "session:abc"
   2) "session:def"

redis> UNLINK session:abc session:def
(integer) 2

问题3:KEYS和SCAN的结果一样吗?功能上都做模式匹配,但KEYS返回全量精确结果,SCAN是分批可能重复的结果,需客户端聚合去重。性能上一个阻塞一个不阻塞,生产环境一律选SCAN

问题4:为什么有时KEYS明明很快?键数量少的时候遍历耗时极短,测试环境感觉不到问题,但键规模上去后风险是指数级放大的,这也是很多事故发生在业务量增长之后的原因。

总结一下:KEYS命令适合在开发调试或本地环境快速查看键,生产环境一律用SCAN替代遍历,用UNLINK替代DEL删除批量键。更根本的解法是在数据设计阶段就维护好索引结构,避免对模糊查找的依赖,从源头消除这类性能隐患。

Redis Keys命令SCAN遍历Redis键管理修改时间:2026-09-05 19:52:53

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/20260905/51107.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。