1. 为什么我们需要在集群里“大海捞针”?
大家好,我是老张,在缓存这块摸爬滚打十来年了。今天咱们聊一个很多朋友在Redis集群里都会遇到的“老大难”问题:怎么快速、安全地找出所有符合特定模式的Key?比如,你想知道某个门店下所有商品的缓存,或者想清理一批带有特定前缀的测试数据。
你可能第一时间会想到那个简单粗暴的 KEYS 命令。我承认,在单机测试环境里,KEYS “user:1001:*” 敲下去,瞬间返回结果,确实爽快。但我要告诉你,在生产环境的Redis集群里用 KEYS,尤其是在数据量大的时候,这操作跟“自杀”差不多。为什么?因为 KEYS 命令是阻塞式的。它会遍历整个数据库的所有Key,直到找出所有匹配项才会返回。在这期间,Redis服务器无法处理其他任何请求,性能会断崖式下跌,搞不好就直接把服务给打挂了。
那不用 KEYS 用什么呢?Redis官方早就给出了答案:SCAN 命令。SCAN 的核心优势就是非阻塞和游标迭代。它不会一次性把所有匹配的Key都捞出来,而是每次只返回一小部分,并给你一个“游标”(cursor),你拿着这个游标再去请求下一次,直到游标返回0,表示遍历完成。这个过程是分步的,对服务器性能影响极小,完全可以在生产环境放心使用。
但是,当你兴冲冲地把单机Redis上跑通的 SCAN 脚本,搬到Redis集群环境时,很可能就傻眼了——怎么只返回了一部分数据?原因很简单:标准的 SCAN 命令只能针对单个Redis节点进行操作。一个Redis集群是由多个主从节点组成的,你的数据被分散存储在不同的节点上。如果你只连上其中一个节点执行 SCAN,那自然只能查到该节点上的数据,结果当然不完整。
所以,我们今天要解决的核心问题,就是在Redis集群环境下,如何高效、正确地使用 SCAN 命令,实现跨所有节点的模糊匹配Key查询。这就像你要在一个分布在不同楼层的图书馆里找一批特定主题的书,你不能只在一层楼找,得派人去每一层楼的书架前都用相同的方法找一遍,最后把结果汇总起来。
2. 吃透SCAN命令:从语法到实战陷阱
在开始集群遍历之前,我们必须先把 SCAN 这个工具本身玩明白。很多朋友用不好,不是因为集群复杂,而是对 SCAN 的基本特性和细节理解不到位。
2.1 命令语法与参数拆解
SCAN 命令的基本语法长这样:
SCAN cursor [MATCH pattern] [COUNT count]
看起来很简单,但每个部分都有讲究。
cursor(游标):这是迭代的灵魂。第一次调用时,游标必须设为0。之后,每次命令返回的第一个元素,就是下一次迭代应该使用的游标。当返回的游标为0时,表示整个遍历结束。这个游标是一个基于内部状态的数字,你不需要理解它的具体含义,只需原样传递即可。MATCH pattern(匹配模式):这就是我们的“模糊匹配”条件。它支持简单的通配符:*:匹配任意数量的任意字符。比如user:*匹配所有以user:开头的Key。?:匹配一个任意字符。比如user:?匹配user:1、user:a,但不匹配user:10。[abc]:匹配括号内的任意一个字符。比如user:[123]匹配user:1、user:2、user:3。 这里有个关键点:MATCH过滤是在数据从数据库中取出来之后,在返回给客户端之前进行的。也就是说,COUNT参数决定了一次从底层存储里取多少Key,然后在这批Key里再用pattern进行过滤。所以,即使你设置了MATCH,一次迭代返回的数量也可能少于COUNT,甚至为0。
COUNT count(数量提示):这是最容易让人误解的参数。COUNT仅仅是一个 “提示”(hint),而不是一个保证。你告诉Redis:“我希望你每次大概返回这么多元素。” Redis会尽力满足,但出于其内部字典桶(hash bucket)遍历的实现机制


2352

被折叠的 条评论
为什么被折叠?



