Redis Scan命令的基本使用方法
1.概述
SCAN命令以及比较相近的SSCAN、HSCAN和ZSCAN命令都用于增量迭代数据集元素:
- SCAN命令用于迭代当前数据库中的数据库键。
- SSCAN命令用于迭代集合(Set)中的元素。
- HSCAN命令用于迭代哈希(Hash)中的字段以及对应的值。
- ZSCAN命令用于迭代有序集合(SortedSet)中的元素以及对应的得分。
由于这些命令都可以增量迭代,每次调用都只会返回少量元素,所以这些命令可以用于生产环境中,不用担心像使用KEYS、SMEMBERS命令带来的问题。在键或元素的大数据集上调用这些命令可能会长时间(甚至几秒钟)阻塞服务器。像SMEMBERS这样的阻塞命令能够在给定的时间内提供数据集中所有的元素,但SCAN系列命令仅对返回的元素提供有限的保证,因为数据集在我们增量迭代时可能会发生改变。
SCAN,SSCAN,HSCAN以及ZSCAN命令工作原理都非常类似,因此这篇文章会涵盖这四个命令。区别在于SSCAN,HSCAN以及ZSCAN命令,第一个参数是保存Set,Hash或SortedSet值的键的名称。SCAN命令不需要任何键名参数,因为它会迭代当前数据库中所有的键,因此迭代的对象是数据库本身。
2.基本用法
SCAN是基于游标的迭代器。这意味着在每次调用该命令时,服务器都会返回一个更新后的新游标,用户需要在下一次调用中将这个新游标作为SCAN命令的游标参数。当SCAN命令的游标参数被设置为0时,服务器将开始一次新的迭代,而当服务器向用户返回的新游标为0时会终止迭代。以下是SCAN迭代的示例:
redis127.0.0.1:6379>scan0 1)"17" 2)1)"key:12" 2)"key:8" 3)"key:4" 4)"key:14" 5)"key:16" 6)"key:17" 7)"key:15" 8)"key:10" 9)"key:3" 10)"key:7" 11)"key:1" redis127.0.0.1:6379>scan17 1)"0" 2)1)"key:5" 2)"key:18" 3)"key:0" 4)"key:2" 5)"key:19" 6)"key:13" 7)"key:6" 8)"key:9" 9)"key:11"
在上面的示例中,第一次调用使用0作为游标来开始一次新的迭代。第二次调用时使用上一次调用返回的游标,即命令回复的第一个元素值,即17。从上面的示例可以看到,SCAN命令返回值是两个值的数组:第一个值是下一次调用中将要使用的新游标,第二个值是包含返回元素的数组。
由于在第二次调用中返回的游标为0,因此服务器向调用者发送信号,告知迭代已完成,并且遍历完数据集。从游标值0开始迭代,然后调用SCAN直到返回的游标再次为0,表示一个完整迭代。
3.保证
SCAN命令,以及其他增量迭代命令,在整个完整迭代过程中可以为用户提供一系列的保证:
- 在完整迭代开始直到完整迭代结束期间内的所有元素都会被遍历返回;这意味着,如果某个给定元素在开始迭代时位于数据集内,并且在终止迭代时仍然存在,那么SCAN会在某次迭代时返回给用户。
- 在完整迭代开始直到完整迭代结束期间内不存在的元素永远都不会被返回;因此,如果某个元素在迭代开始之前就被删除,并且在后续的迭代过程中从未添加回数据集中,那么SCAN永远都不会返回该元素。
但是,由于SCAN只有很少的关联状态(仅有游标),因此具有以下缺点:
- 同一个元素可能会被返回多次。重复元素的问题需要我们自己的应用程序处理,例如,可以考虑将迭代返回的元素用于幂等操作(可以重复执行多次操作)上。
- 如果一个元素是在迭代过程中被添加到数据集的,又或者是在迭代过程中从数据集中被删除的,那么这个元素可能会被返回,也可能不会。
4.每次执行返回数量
SCAN系列的函数不能保证每次调用返回的元素数量会在给定范围内。每次调用可能会返回0个元素,但只要返回的游标不为0,客户端就认为迭代没有结束(即使返回了0个元素也不能表示迭代的结束)。返回的元素数量会符合一定的规则:
- 在迭代大型数据集时,SCAN最多可能会返回几十个元素。
- 在迭代小的数据集并且内部为编码数据结构时(小的Set、Hashe以及SortedSet),单次调用就可以返回数据集的所有元素。
但是,用户可以使用COUNT参数来调整每次调用返回的元素的数量级。
5.COUNT参数
虽然SCAN不能保证每次迭代返回的元素数量,但是可以使用COUNT参数根据经验进行调整。基本上,COUNT参数的作用就是让用户告知迭代命令,在每次迭代中应该从数据集里返回多少元素。虽然COUNT参数只是迭代命令实现上的一种提示(hint),但是在大多数情况下,这种提示是能满足我们的预期:
- COUNT默认值为10。
- 在迭代一个足够大、由哈希表实现的数据库、Set、Hash或者SortedSet时,如果用户没有使用MATCH参数,那么每次调用返回COUNT个元素,或者比COUNT稍多的元素。
- 在迭代一个编码为IntSet(一个只由整数值构成的小数据集)或Hash的Set以及编码为ZipList(由不同值构成的小的Hash或者Set)的SortedSet时,通常会无视COUNT参数指定的值,并在第一次调用时就将数据集包含的所有元素都返回给用户。
没有必要每次迭代都要使用相同的COUNT值。用户可以在每次迭代中按自己的需要随意改变COUNT值,只要记得将上次迭代返回的游标用到下次迭代里面就可以了。
6.MATCH参数
我们也可以通过匹配一个Glob风格的模式来迭代元素,类似于KEYS命令。我们只需要在SCAN命令后面追加MATCH
以下是一个使用MATCH参数进行迭代的示例:
redis127.0.0.1:6379>saddmyset123foofoobarfeelsgood (integer)6 redis127.0.0.1:6379>sscanmyset0matchf* 1)"0" 2)1)"foo" 2)"feelsgood" 3)"foobar" redis127.0.0.1:6379>
我们需要注意的是MATCH过滤器是在从数据集中检索出元素之后,在将数据返回给客户端之前应用的。这意味着,如果模式匹配到数据集中很少的元素,则SCAN命令在很多次迭代中可能不返回元素。一个例子如下所示:
redis127.0.0.1:6379>scan0MATCH*11* 1)"288" 2)1)"key:911" redis127.0.0.1:6379>scan288MATCH*11* 1)"224" 2)(emptylistorset) redis127.0.0.1:6379>scan224MATCH*11* 1)"80" 2)(emptylistorset) redis127.0.0.1:6379>scan80MATCH*11* 1)"176" 2)(emptylistorset) redis127.0.0.1:6379>scan176MATCH*11*COUNT1000 1)"0" 2)1)"key:611" 2)"key:711" 3)"key:118" 4)"key:117" 5)"key:311" 6)"key:112" 7)"key:111" 8)"key:110" 9)"key:113" 10)"key:211" 11)"key:411" 12)"key:115" 13)"key:116" 14)"key:114" 15)"key:119" 16)"key:811" 17)"key:511" 18)"key:11" redis127.0.0.1:6379>
如上述所述,大多数调用没有返回元素,而最后一次调用使用COUNT为1000,强制命令对该迭代进行更多扫描,从而使得命令返回的元素也变多了。
7.TYPE参数
从6.0版开始,我们可以使用此参数要求SCAN命令仅返回与给定类型匹配的对象,从而允许我们遍历数据库以查找特定类型的键。SCAN可以使用TYPE参数,但HSCAN或ZSCAN等不可用。
type参数与TYPE命令返回的字符串名称相同。需要我们注意的是某些Redis类型(例如GeoHashes、HyperLogLogs、Bitmap以及Bitfields等)其内部是使用其他Redis类型(例如String或Zset)来实现的,因此SCAN命令无法将其与相同类型的其他键区分开。例如,ZSET和GEOHASH:
redis127.0.0.1:6379>GEOADDgeokey00value (integer)1 redis127.0.0.1:6379>ZADDzkey1000value (integer)1 redis127.0.0.1:6379>TYPEgeokey zset redis127.0.0.1:6379>TYPEzkey zset redis127.0.0.1:6379>SCAN0TYPEzset 1)"0" 2)1)"geokey" 2)"zkey"
重要的是,TYPE过滤器是在从数据库中检索元素之后应用的,因此该参数不会降低服务器完成完整迭代所需的负载,对于稀有类型,我们可能不会收到任何元素。
8.多次并行迭代
不同客户端可能在同一时间迭代同一数据集,客户端每次执行迭代都需要传入一个游标,并在迭代结束之后获得一个新的游标,而这个游标就包含了迭代的所有状态,因此,服务器无须为迭代记录任何状态。
9.在中间终止迭代
由于服务器端不会记录状态,迭代的所有状态都保存在游标中,因此调用方可以自由地中途终止迭代,不用向服务器发送通知。Aninfinitenumberofiterationscanbestartedandneverterminatedwithoutanyissue.
10.使用错误的游标调用SCAN
使用错误的,负数的,超出范围的游标或其他无效的游标来调用SCAN,会导致未定义的行为,但绝不会导致崩溃。未定义的是指SCAN将不再确保返回元素的保证。
唯一有效的游标是:
开始迭代时的游标值为0。
上一次调用SCAN返回的游标,以便继续迭代。
11.终止保证
只有在保证迭代的数据集大小始终保持在给定的最大上限内时(大小恒定),才能保证SCAN算法能终止;否则,对一直增长的数据集进行迭代可能会导致SCAN永远不会终止迭代(死循环)。
这很容易直观地看出:如果数据集不断增长,为了访问所有可能出现的元素,将需要做越来越多的工作,而能否结束一个迭代取决于对SCAN的调用次数、COUNT参数值以及数据集的增长速度。
12.返回值
SCAN,SSCAN,HSCAN以及ZSCAN命令都返回一个包含两个元素的回复,第一个元素表示游标的无符号64位整数,第二个元素是迭代出的元素数组:
SCAN元素数组是键的列表。
SSCAN元素数组是Set成员的列表。
HSCAN元素数组包含两个元素,即字段和值,对应Hash的每个返回元素。
ZSCAN元素数组包含两个元素,即一个成员及其关联的分数,对应SortedSet中的每个返回元素。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对毛票票的支持。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。