文章目录
- 前言
- 什么是渐进式遍历
- SCAN
- 数据库管理
前言
前面我们学习了针对 redis 五种基本数据类型和五种特殊数据类型的常用命令,其中通用命令 keys pattern
我们都知道是用来查询当前 redis 服务器中有哪些 key 的,而如果此时 redis 服务器中存在很多的 key 的话,使用 keys 命令就需要花费较多的时间,而又因为 redis 是单线程执行的模式,如果一个命令执行所需要的时间较长的话,就会造成 redis 服务器的阻塞。那么这就代表着我们应该尽量避免使用例如 keys *
这样的命令,但是如果我们真的需要知道当前 redis 服务器中有哪些 key 的时候该怎么办呢?
本篇文章,我们将学习一种遍历方式,叫做渐进式遍历,使用渐进式遍历一次命令执行只会遍历部分数据,而不会像 keys 命令一样一次遍历完所有的数据。
什么是渐进式遍历
Redis 中的渐进式遍历(Progressive Iteration)是一种处理大数据集遍历的技术,它允许客户端逐步地、分批次地获取数据,而不是一次性地获取整个数据集。这种遍历方式对于非常大的数据集特别有用,因为它可以减少内存使用和网络传输的开销,同时避免阻塞服务器。
渐进式遍历的核心思想是将遍历操作分解为多个小的步骤,每个步骤只处理数据集的一部分。客户端可以逐步地请求更多的数据,直到整个数据集都被遍历完。
渐进式遍历其实是一组命令,这一组命令的使用方法是一样的,其中的代表命令就是 SCAN
SCAN
SCAN 命令以渐进式的方式进行键的遍历。SCAN cursor [MATCH pattern] [COUNT count] [TYPE type]
这里的 cursor 是游标,用来告诉我们下一次使用 SCAN 渐进式遍历的时候从哪个位置开始遍历。这里的游标不是类似下标这样的概念,不一定下一次渐进式遍历的开始位置的游标就要大于上一次遍历的开始游标。
type 则是指定每次渐进式遍历的数据类型,这里的数据类型指的是 value 的数据类型。
每次使用 scan 渐进式遍历的返回值有两部分:第一部分是下次渐进式遍历游标开始的位置,第二部分就是遍历的数据。第一次渐进式遍历游标从 0 开始,当遍历完成所有的数据之后返回的游标值是 0。后面的 count 是说这次渐进式遍历遍历多少数据,默认是10,但是这里的 count 只是建议,实际的返回数据可能大于我们给定的 count 值也可能小于,这里是不确定的。
127.0.0.1:6379> MSET key1 111 key2 222 key3 333 key4 444 key5 555 key6 666 key7 777 key8 888 key9 999 key10 000
OK
127.0.0.1:6379> keys *1) "key7"2) "key3"3) "key4"4) "key5"5) "key6"6) "key10"7) "key8"8) "key9"9) "key2"
10) "key1"
127.0.0.1:6379> SCAN 0 count 3
1) "12"
2) 1) "key5"2) "key6"3) "key7"
127.0.0.1:6379> SCAN 12 count 3
1) "3"
2) 1) "key2"2) "key3"3) "key1"
127.0.0.1:6379> SCAN 3 count 3
1) "7"
2) 1) "key10"2) "key8"3) "key9"
127.0.0.1:6379> SCAN 7 count 3
1) "0"
2) 1) "key4"127.0.0.1:6379> SCAN 0 count 4
1) "2"
2) 1) "key5"2) "key6"3) "key7"4) "key2"
127.0.0.1:6379> SCAN 2 count 4
1) "7"
2) 1) "key3"2) "key1"3) "key10"4) "key8"5) "key9"
127.0.0.1:6379> SCAN 7 count 4
1) "0"
2) 1) "key4"
为什么我们每次渐进式遍历之后,redis 会给我们返回一个下一次渐进式遍历的游标值呢?这是因为在渐进式遍历的过程中,不会在 redis 服务器中存储任何的状态信息,所以也就不会在服务器这边保存你这一次渐进式遍历遍历到哪里了,而是会告诉你我这次遍历到哪里了,你下一次渐进式遍历应该从哪个位置开始,这个位置是需要我们自己来传给 redis 服务器的。也正是因为 redis 这样的机制,我们的渐进式遍历是随时可以终止的,是不会对 redis 服务器产生任何影响的。
-
灵活性与可控性:由于 SCAN 命令不保存状态信息,它允许客户端完全控制遍历的过程。客户端可以根据需要随时开始、暂停或继续遍历,而不需要担心服务器保存的状态信息可能会导致的潜在问题。这种灵活性使得 SCAN 命令更加适应于各种复杂的应用场景。
-
资源消耗低:不保存状态信息意味着服务器不需要为遍历操作分配额外的存储空间来维护状态。这有助于减少服务器的内存消耗,尤其是在处理大规模数据集时。同时,由于没有状态信息需要管理,遍历操作的开销也相对较低,这有助于提高整体的性能。
-
可中断性:由于遍历状态不由服务器保存,客户端可以在任何时候中断遍历操作,而不需要担心状态信息的丢失或不一致。这使得 SCAN 命令在处理长时间运行的任务或需要响应其他操作的场景时更加可靠。
-
容错性:由于状态信息不依赖于服务器的持久化存储,即使服务器在遍历过程中发生故障或重启,也不会影响遍历的进度或结果。客户端可以简单地重新开始遍历,而无需担心从故障中恢复状态信息的复杂性。
虽然渐进式遍历可以有效的解决 keys * 这样的类型命令对 redis 服务器产生阻塞的问题,但是渐进式遍历也存在问题:当在渐进式遍历的过程中,如果键发生了修改、增加、删除等的时候,可能就会导致我们渐进式遍历的结果出现重复或者遗漏,这点是需要我们注意的。
在渐进式遍历的过程中不应该对键的值和数量做出修改,就像 c++ 的迭代器,Java 的 for each 循环一样,如果在这个过程中遍历的容器或者集合中的元素发生修改可能就会出现问题。
数据库管理
在前面的 MySQL 中我们可以发现,在 MySQL 中可以有很多的数据库,一个数据库中可以有很多的表,而在 redis 中我们好像上来就是 set 和 get,我们也没有指定哪个数据库啊,那么也是否意味着 redis 中不存在数据库这样的概念呢?
其实不是的,redis 中也存在库这样的概念,只不过 redis 为我们提供了 16 个默认的数据库,编号从 0-15,这些数据库之间的数据是相互隔离的,不会相互影响,并且这些数据库是不允许我们对其进行删除操作的,不仅如此,redis 也不允许我们创建出新的数据库。redis 默认使用的数据库就是编号为 0 的数据库,所以也就不需要我们显式的指定使用哪个数据库。
如果我们想要更换其他的数据库,可以使用 SELECT dbindex
来切换其他数据库。
127.0.0.1:6379> keys *1) "key7"2) "key3"3) "key4"4) "key5"5) "key6"6) "key10"7) "key8"8) "key9"9) "key2"
10) "key1"
127.0.0.1:6379> select 5
OK
127.0.0.1:6379[5]> keys *
(empty array)
FLUSHDB [ASYNC | SYC]
命令可以异步或者同步的删除当前数据库中的所有键。
127.0.0.1:6379[5]> select 0
OK
127.0.0.1:6379> FLUSHDB
OK
127.0.0.1:6379> keys *
(empty array)
FLUSHALL
命令是删除所有数据库中的键。
DBSIZE
命令可以获取到当前数据库中 key 的数量。
127.0.0.1:6379> MSET key1 111 key2 222 key3 333 key4 444 key5 555
OK
127.0.0.1:6379> DBSIZE
(integer) 5
127.0.0.1:6379> SELECT 6
OK
127.0.0.1:6379[6]> DBSIZE
(integer) 0