> 文档中心 > Redis的全量遍历和渐进式遍历

Redis的全量遍历和渐进式遍历

Redis提供了两种key遍历的方法,一种是keys,一种是scan,这里对它们进行讲解并分析。

1、全量遍历

keys pattern

在本专栏【认识redis】中,讲解的全局命令中有keys 的简单使用,实际上keys命令是支持pattern匹配的,如下:

#获取redis中所有键,使用keys * 命令127.0.0.1:6379> keys * 1) "user" 2) "user.name" 3) "list1" 4) "c" 5) "test" 6) "b" 7) "y" 8) "a" 9) "user.city"10) "hk"11) "list2"12) "k"13) "x"

上面的例子中使用的是*,这是为了匹配所有的key。

keys命令中的pattern参数使用的是glob风格的通配符,详细如下:

  • *代表匹配任意私服
  • ?代表匹配一个字符
  • [] 代表匹配部分字符,例如[a,c,e]代表匹配a,c,e,[1-10]代表匹配从1到10的任意数字。
  • \x 用来匹配转义字符,例如 需要用来匹配?、*等特殊字符时,需要进行转义

例子如下:

#匹配list开头的所有key127.0.0.1:6379> keys list*1) "list1"2) "list2"#匹配包含user的key127.0.0.1:6379> keys [user]*1) "user"2) "user.name"3) "user.city"

当需要遍历所有的键时,keys是一个十分有用的命令,但是考虑到Redis是单线程架构,如果Redis中包含大量的key时,执行keys命令,极有可能导致Redis阻塞,所有一般不建议在生产环境中使用该命令,如果业务确实需要对所有键进行遍历,可使用如下操作:

1、确认键的总数,如果总数比较少的话,可以使用该命令

2、如果键的数量比较多,可以使用渐进式遍历命令scan,能够有效避免阻塞。

2、渐进式遍历

Redis中提供了scan命令,有效解决了keys命令带来的阻塞问题。它执行时并不会遍历全部键,而是采用渐进式遍历的方式,不过想要真正实现keys的功能,需要执行多次scan命令才行。

Redis中存储键值对使用的是hashtable的数据结构,每次执行scan命令,可以看成是只扫描其中一部分键,知道将所有的键都遍历完才可以结束。scan命令如下:

scan cursor [match pattern] [count number]

命令参数为:

  • cursor:必须参数,游标,第一次遍历从0开始,每次遍历完都会返回当前的游标值,直到游标值为0,标识所有key都被遍历完成,遍历可以结束
  • match pattern : 和keys命令的匹配相似,都是用作键的匹配
  • count number: 表名每次匹配要遍历的键的个数,默认是10,可以适当调大。

示例如下:

# 第一次执行scan 0127.0.0.1:6379> scan 01) "11"2)  1) "user"    2) "a"    3) "test"    4) "user.name"    5) "hk"    6) "y"    7) "user.city"    8) "b"    9) "list1"   10) "c"   # 使用新的cursor = '11',执行scan 11127.0.0.1:6379> scan 111) "0"2) 1) "list2"   2) "k"   3) "x"

运行命令和结果解释:

1、第一次执行scan 0 ,返回结果包括两部分,第一部分 11 就是下次执行scan命令需要的cursor参数,第二部分是返回的10个键。

2、第二次执行scan 11 ,得到的结果是 “0”,说明所有的键都已经被遍历过了。

除了scan外,Redis中还提供了针对哈希、集合、有序集合等类型的扫描遍历的命令,解决hgetall、smembers、zrange可能产生的阻塞的问题,对应的命令分别是:hscan、sscan、zscan,它们的用法和scan相似。

使用scan命令的注意事项:

scan命令能有效的解决keys命令带来的阻塞问题,但是却带来新的问题。

在scan过程中,如果键发生了变化(增、删、改),那么有可能会出现新增的键没有遍历到或者遍历出了重复键的情况。这是在开发过程中需要注意到的地方。