Redis里那个scan方法,怎么用才不迷路,带你一步步摸索探索
- 问答
- 2026-01-17 05:07:02
- 2
说到Redis的SCAN命令,很多人第一次用的时候都会有点懵,明明用KEYS命令,输入个通配符就能一下子拿到所有匹配的key,为啥还要用这个返回结果看起来零零碎碎的SCAN呢?原因就在于“一下子”这三个字上,想象一下,如果你的Redis里存了几百万甚至上千万个key,你贸然使用KEYS *这样的命令,Redis会怎么做?它会停止所有工作,埋头苦干,一口气把所有key都找出来再返回给你,这个过程可能会持续好几秒甚至更久,在这期间,Redis就无法正常响应其他客户端的请求了,这就相当于一场“灾难”。(来源:Redis官方文档对KEYS命令的警告)
而SCAN命令的设计初衷,就是为了解决这个问题,它采用了一种叫做“游标分步迭代”的方式,把一次性的巨大操作,分解成很多个小的、不影响Redis正常服务的小操作,你可以把它想象成在图书馆里找一套大部头的百科全书,KEYS命令是要求管理员一口气把几十本全都搬到你面前,而SCAN则是你自己拿着一个书单,一次只拿一两本,看完还回去再拿下一两本,这样既不会把管理员累垮,也不会阻塞其他借书的人。
这个“不迷路”的用法,关键就在于理解SCAN命令的几个核心要素,你不用记那些复杂的专业术语,我们就用大白话来聊。
第一,你得有个“书签”——游标(Cursor)。
每次你调用SCAN命令,都要告诉它一个数字,这个数字就是游标,最开始的第一次,你传一个0进去,就像跟Redis说:“嗨,我从头开始找。” Redis在返回结果给你的时候,会同时告诉你下一个游标是多少,它可能返回(integer) 17,这就好比是书看到第17页了,下次你从第17页接着往下看就行,直到某一次,Redis返回给你的下一个游标又是0了,这就意味着整套“百科全书”你已经全部翻完了,迭代结束。
第二,一次拿多少?——COUNT参数。
SCAN命令还有一个很重要的参数叫COUNT,你可以把它理解为“我这次想先拿多少本看看”,比如你设置COUNT 100,就是告诉Redis,这次迭代我希望你返回大概100个key,注意,这里说的是“大概”!这不是一个硬性规定,Redis可能会返回比100多一点的key,也可能会返回比100少一点的key,这很正常,设置COUNT的目的是为了在你觉得一次返回太慢和一次返回太多之间做个平衡,如果key总量很大,你可以把COUNT值设大一点,比如1000,这样总的迭代次数会变少,但每次耗时可能稍长一点,这个需要根据实际情况调整。
第三,我只想看特定类型的书——MATCH模式。
这和KEYS命令的通配符是一样的,比如你只想找所有以user:session:开头的key,你就可以在SCAN命令后面加上MATCH user:session:*,但是这里有一个非常重要的点:MATCH过滤是在数据从数据库中取出来之后才进行的,这是什么意思呢?比如说,你设置了COUNT 100,但Redis可能实际上扫描了120个key,然后在这120个key里,只有10个符合user:session:*的模式,那么这次它就只返回这10个key给你,有可能你设置了一次拿100个,但返回的数组却是空的,就是因为那一批扫描出来的key里没有匹配模式的,这不是bug,而是SCAN的工作机制。
一个完整的“不迷路”的使用流程是这样的(以命令行为例):
- 开始探险: 你发出指令
SCAN 0 MATCH your_pattern COUNT 100,这里的0是起点。 - 接收第一批宝藏: Redis会返回一个包含两个元素的数组,第一个元素是下一个游标值(比如
53),第二个元素是一个列表,里面是本次迭代找到的、符合模式的key。 - 继续前进: 你用刚才拿到的游标值
53,发出下一个指令SCAN 53 MATCH your_pattern COUNT 100。 - 重复过程: 重复第2步和第3步。
- 抵达终点: 当某一次Redis返回给你的下一个游标值是
0时,恭喜你,你已经遍历了整个key空间,所有符合条件的key都应该已经在你手中了。
在实际写代码的时候(比如用Python的redis-py库),你会用一个while循环来做这个事情,大概长这样:
cursor = 0
all_keys = []
while True:
cursor, keys = redis_client.scan(cursor=cursor, match='your_pattern*', count=100)
all_keys.extend(keys)
if cursor == 0: # 如果游标回归0,说明迭代结束
break
再提醒几个路上可能遇到的“坑”:
- 期间数据可能会变: 因为SCAN迭代的过程可能持续一段时间,在这期间,其他客户端可能会新增或删除key,SCAN不保证能完全反映出“某一精确时刻”的数据库快照,它可能会返回一些已经被删除的key(但概率低),也可能会漏掉一些在迭代过程中新增加的key,对于要求绝对精确的场景要小心。
- 不是从0开始就叫安全: 即使你从游标0开始,在整个迭代过程中,只要没返回0,如果数据库的键空间发生了重组(比如扩容),也可能会导致一些key被重复遍历或遗漏,但这种情况在正常情况下比较罕见。
把SCAN命令理解成一次悠闲的、分步完成的图书馆查阅之旅,而不是一次性的疯狂搬运,你就不会迷路了,核心就是盯住返回的游标,不为单次返回的空结果而困惑,直到游标归零,任务完成,这样既能高效地获取大量key,又避免了阻塞Redis的风险,是生产环境中的标准做法。

本文由凤伟才于2026-01-17发表在笙亿网络策划,如有疑问,请联系我们。
本文链接:https://haoid.cn/wenda/82215.html
