学习一下Redis的SCAN命令

最近在学习Redis的常用命令,String类型的命令学完没发现啥问题,今天学到Hash这种类型的数据结构,其中有一个HSCAN命令,字面理解就是对HASH的扫描,熟悉面向对象的编程的小伙伴应该不难理解,HASH这种数据结构类似于JAVA/C#里面的Class,适合存储一个对象,对象中包含若干个字段,那么这个HSCAN就是用来迭代对象中的所有的字段的。

我们看官方文档对他的描述。

简单翻一下:

  • 2.8.0版本后可用
  • 一次调用的时间复杂度是O(1)
  • 当返回的游标值是0时表明迭代完成,完成此过程的时间复杂度是O(N),其中N为Hash集合中元素的个数。
  • 关于HSCAN的详细文档可看SCAN的文档(这说明这玩意和SCAN的用法基本差不多)

看完发现需要先学SCAN命令,,,,,有点刚入门写代码的感觉,区百度一个概念同时会引申出N个概念😒,好吧先去看SCAN命令

以下是正题:


 

原版文档自己看,我按自己理解简单翻译下(六级都没过🤣,欢迎大佬指正)

简单介绍

  SCAN命令以及与其类似的SSCAN、HSCAN、ZSCAN命令被用来迭代集合中的元素。

  • SCAN命令迭代当前选中的数据库(16个数据库中的某一个)中的key的集合
  • SSCAN命令迭代集合这种数据类型中的元素
  • HSCAN命令迭代哈希这种数据类型中的所有的字段及其对应的值
  • ZSCAN命令迭代有序集合这种数据类型中的所有的元素及其对应的Score(排序用的分数)

 

   以上这些命令允许渐进式的迭代结合,每次调用只返回集合中的一部分,是非阻塞的。因此在生产环境中,对于元素或者键比较多的集合的访问,使用此类命令比使用KEYS/SMEMBERS这种阻塞式的命令效率要高很多,KEYS或者SMEMBERS命令有时候能阻塞服务器几秒钟(没有实战验证过,不得而知,官方文档这么说的)。这么看来好像KEYS、SMEMBERS这种命令一无是处,其实不然,虽然它是阻塞式,但是正因为是阻塞式的,因此他可以返回命令调用时刻集合中的所有元素(一个不落),而SCAN这类命令则不能,因为在迭代的过程中结合是有可能被修改的。(只用记住KEYS、SMEMBERS是阻塞的,一次返回所有的元素,SCAN是非阻塞的,一次返回部分元素(具体每次返回多少个元素,什么时候迭代完成下面会讲),需要迭代多次才能遍历集合中的所有元素

  SCAN、SCAN、HSCAN、ZSCAN四个命令用法很像,注意一点:SCAN、HSCAN、ZSCAN三个命令的迭代对象分别是Set、Hash、Sorted Set,命令的第一个参数是要迭代对象对应的键名称,而SCAN的迭代对象是当前数据库本省的所有的键值对的集合,因此不需要传递key这个参数。

基本用法(以SCAN为例,其他三个类似)

SCAN基于游标(cursor)实现迭代器,这意味着每次迭代命令调用后服务器将返回一个更新后的游标值,这个游标值在下次调用的时候需要当作命令的参数传给服务器(这说明SCAN命令中有一个参数是cursor)。第一次调用时cursor设为0,此后的每次调用的cursor的值都是上一次调用时服务端的返回值。直到服务端返回的cursor为0时表明集合迭代完成(这一块写个while循环就搞定了)(从一而终,以0开始以0结束)。

SCAN命令的确定与不确定

确定:从迭代开始到迭代结束这期间一直在存在于集合中的元素,可以确定他肯定会被返回,同样迭代期间一直未曾出现在集合中的元素可以确定肯定不会被返回。

不确定:

同一个元素无法保证只能被返回一次,有可能会被返回多次,数据的去重操作要由应用程序来处理,如果业务场景允许数据重复更完美;

在迭代过程中被添加进集合的元素不能确定是否会被返回;同理在迭代过程中被删除的元素也无法确定是否会被返回。

SCAN命令每次迭代返回的元素的个数

 每次命令调用可以传递COUNT <count>参数,但是无法保证每次返回的元素的个数与count相同

  • count的默认值为10.
  • 集合元素比较多,如果没有使用MATCH <pattern>参数作为过滤条件,那么返回的元素个数通常会与count相同,或者比count稍微大一点。
  • 当集合是有整数值构成的小集合、或者编码为ziplist(由不同值构成的一个小哈希或者一个小的有序集合)时,该命令通常会忽略COUNT参数,全量返回。(这一块有点抽象,具体怎么界定小集合,小值其实是有配置文件配置的,接下来会讲)
如何界定小集合,小值
# Hashes are encoded using a memory efficient data structure when they have a
# small number of entries, and the biggest entry does not exceed a given
# threshold. These thresholds can be configured using the following directives.
hash-max-ziplist-entries 512
hash-max-ziplist-value 64

 

这是从redis.conf中截取的一段配置,这两个配置的意思是如果HASH中字段的个数大于512个我们称该集合为大集合;如果集合中某个字段的长度大于64个字节,那么称该值为大值。如果某个结合满足:字段数大于512,或者字段中有某个(哪怕只有一个)字段是大值字段,那么这个时候HSCAN中的COUNT才会起作用。否则将采用ziplist编码以优化内存,count参数会被忽略。因此这就可以解释为啥初学者会发现COUNT参数压根不起作用,无论COUNT传什么值都是全量返回所有的元素,原因就在于集合是小集合,并且集合中所有字段都是小值,使得redis采用了ziplist压缩算法以优化内存。

posted @ 2021-03-09 20:48  chuanjie  阅读(437)  评论(0)    收藏  举报