时间:2019-12-22来源:系统城作者:电脑系统城
1. 概述
SCAN 命令以及比较相近的 SSCAN、HSCAN 和 ZSCAN 命令都用于增量迭代数据集元素:
由于这些命令都可以增量迭代,每次调用都只会返回少量元素,所以这些命令可以用于生产环境中,不用担心像使用 KEYS、SMEMBERS 命令带来的问题。在键或元素的大数据集上调用这些命令可能会长时间(甚至几秒钟)阻塞服务器。像 SMEMBERS 这样的阻塞命令能够在给定的时间内提供数据集中所有的元素,但 SCAN 系列命令仅对返回的元素提供有限的保证,因为数据集在我们增量迭代时可能会发生改变。
SCAN,SSCAN,HSCAN 以及 ZSCAN 命令工作原理都非常类似,因此这篇文章会涵盖这四个命令。区别在于 SSCAN,HSCAN 以及 ZSCAN 命令,第一个参数是保存 Set,Hash或 Sorted Set 值的键的名称。SCAN命令不需要任何键名参数,因为它会迭代当前数据库中所有的键,因此迭代的对象是数据库本身。
2. 基本用法
SCAN 是基于游标的迭代器。这意味着在每次调用该命令时,服务器都会返回一个更新后的新游标,用户需要在下一次调用中将这个新游标作为 SCAN 命令的游标参数。当 SCAN 命令的游标参数被设置为 0 时, 服务器将开始一次新的迭代,而当服务器向用户返回的新游标为 0 时会终止迭代。以下是 SCAN 迭代的示例:
在上面的示例中,第一次调用使用 0 作为游标来开始一次新的迭代。第二次调用时使用上一次调用返回的游标,即命令回复的第一个元素值,即17。从上面的示例可以看到,SCAN 命令返回值是两个值的数组:第一个值是下一次调用中将要使用的新游标,第二个值是包含返回元素的数组。
由于在第二次调用中返回的游标为 0,因此服务器向调用者发送信号,告知迭代已完成,并且遍历完数据集。从游标值 0 开始迭代,然后调用 SCAN 直到返回的游标再次为 0,表示一个完整迭代。
3. 保证
SCAN 命令,以及其他增量迭代命令,在整个完整迭代过程中可以为用户提供一系列的保证:
但是,由于 SCAN 只有很少的关联状态(仅有游标),因此具有以下缺点:
4. 每次执行返回数量
SCAN 系列的函数不能保证每次调用返回的元素数量会在给定范围内。每次调用可能会返回 0 个元素,但只要返回的游标不为 0,客户端就认为迭代没有结束(即使返回了 0 个元素也不能表示迭代的结束)。返回的元素数量会符合一定的规则:
但是,用户可以使用 COUNT 参数来调整每次调用返回的元素的数量级。
5. COUNT参数
虽然 SCAN 不能保证每次迭代返回的元素数量,但是可以使用 COUNT 参数根据经验进行调整。基本上,COUNT 参数的作用就是让用户告知迭代命令,在每次迭代中应该从数据集里返回多少元素。虽然 COUNT 参数只是迭代命令实现上的一种提示(hint),但是在大多数情况下,这种提示是能满足我们的预期:
没有必要每次迭代都要使用相同的 COUNT 值。用户可以在每次迭代中按自己的需要随意改变 COUNT 值,只要记得将上次迭代返回的游标用到下次迭代里面就可以了。
6. MATCH参数
我们也可以通过匹配一个 Glob 风格的模式来迭代元素,类似于 KEYS 命令。我们只需要在 SCAN 命令后面追加 MATCH <pattern> 参数即可实现。
以下是一个使用 MATCH 参数进行迭代的示例:
我们需要注意的是 MATCH 过滤器是在从数据集中检索出元素之后,在将数据返回给客户端之前应用的。这意味着,如果模式匹配到数据集中很少的元素,则 SCAN 命令在很多次迭代中可能不返回元素。一个例子如下所示:
如上述所述,大多数调用没有返回元素,而最后一次调用使用 COUNT 为1000,强制命令对该迭代进行更多扫描,从而使得命令返回的元素也变多了。
7. TYPE参数
从 6.0 版开始,我们可以使用此参数要求 SCAN 命令仅返回与给定类型匹配的对象,从而允许我们遍历数据库以查找特定类型的键。SCAN 可以使用 TYPE 参数,但 HSCAN 或 ZSCAN 等不可用。
type 参数与 TYPE 命令返回的字符串名称相同。需要我们注意的是某些 Redis 类型(例如GeoHashes、HyperLogLogs、Bitmap 以及 Bitfields 等)其内部是使用其他 Redis 类型(例如 String 或 Zset)来实现的,因此 SCAN 命令无法将其与相同类型的其他键区分开。例如,ZSET 和 GEOHASH:
重要的是,TYPE 过滤器是在从数据库中检索元素之后应用的,因此该参数不会降低服务器完成完整迭代所需的负载,对于稀有类型,我们可能不会收到任何元素。
8. 多次并行迭代
不同客户端可能在同一时间迭代同一数据集,客户端每次执行迭代都需要传入一个游标,并在迭代结束之后获得一个新的游标,而这个游标就包含了迭代的所有状态,因此,服务器无须为迭代记录任何状态。
9. 在中间终止迭代
由于服务器端不会记录状态,迭代的所有状态都保存在游标中,因此调用方可以自由地中途终止迭代,不用向服务器发送通知。An infinite number of iterations can be started and never terminated without any issue.
10. 使用错误的游标调用SCAN
使用错误的,负数的,超出范围的游标或其他无效的游标来调用 SCAN,会导致未定义的行为,但绝不会导致崩溃。未定义的是指 SCAN 将不再确保返回元素的保证。
唯一有效的游标是:
开始迭代时的游标值为0。
上一次调用 SCAN 返回的游标,以便继续迭代。
11. 终止保证
只有在保证迭代的数据集大小始终保持在给定的最大上限内时(大小恒定),才能保证 SCAN 算法能终止;否则,对一直增长的数据集进行迭代可能会导致 SCAN 永远不会终止迭代(死循环)。
这很容易直观地看出:如果数据集不断增长,为了访问所有可能出现的元素,将需要做越来越多的工作,而能否结束一个迭代取决于对 SCAN 的调用次数、COUNT 参数值以及数据集的增长速度。
12. 返回值
SCAN,SSCAN,HSCAN 以及 ZSCAN 命令都返回一个包含两个元素的回复,第一个元素表示游标的无符号64位整数,第二个元素是迭代出的元素数组:
SCAN 元素数组是键的列表。
SSCAN 元素数组是 Set 成员的列表。
HSCAN 元素数组包含两个元素,即字段和值,对应 Hash 的每个返回元素。
ZSCAN 元素数组包含两个元素,即一个成员及其关联的分数,对应 Sorted Set 中的每个返回元素。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对我们的支持。
2023-11-01
React中immutable的使用2023-11-01
命令行清除Redis缓存的实现2023-11-01
Redis缓存空间优化实践详解引言大厂很多项目都是部署到多台服务器上,这些服务器在各个地区都存在,当我们访问服务时虽然执行的是同一个服务,但是可能是不同服务器运行的;在我学习项目时遇到这样一个登录情...
2023-11-01
1.多次修改一个redis的String过期键,如何保证他仍然能保留第一次设置时的删除时间 2.修改hash、set、Zset、list的值,会使过期时间重置吗?...
2023-11-01