

《Redis深度历险》学习笔记:Scan
source link: https://acuario.xyz/posts/redis-deep-adventure-scan/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

《Redis深度历险》学习笔记:Scan
Scan 命令
- 使用
keys
命令来查找特定前缀的 key 列表有两个缺点:- 没有
offset
、limit
参数,该命令会一次性输出所有满足条件的结果。 keys
命令的时间复杂度为O(n)
,大键查询会阻塞进程,造成卡顿。
- 没有
- 通常使用
scan
命令来进行大键查询:scan
命令的时间复杂度为O(n)
,但通过游标分步进行,不阻塞进程,游标的唯一状态为返回的游标整数。- 提供
limit
参数,实际数量返回可多可少。 - 返回结果可能有重复,需要自行去重。
- 遍历查询时若有数据变动,是否会返回符合条件的数据一切随缘。
- 返回为空不一定表示无结果,要看游标是否为零。
- Scan 命令可以用于各种类型数据的操作,如
zscan
用于 zset 集合、hscan
用于 hash 字典、sscan
用于 set 集合。 - 在集群环境下,如果某个 key 太大,会数据导致迁移卡顿。
- 在内存分配上,如果一个 key 太大,它扩容时会申请更大内存,导致卡顿。
- 开发中,要尽量避免大 key 的产生。
- 假设 redis 中已经存在 10000 条名为 key%d 的数据,下面是一个 scan 的例子:
127.0.0.1:6379> scan 0 match key99* count 1000
1) "13976"
2) 1) "key9911"
2) "key9974"
......
12) "key9905" // 扫描了 1000 个槽位,返回 12 条数据,还有库存
127.0.0.1:6379> scan 13976 match key99* count 1000
1) "1996"
2) (empty list or set) // 扫描了 1000 个槽位,返回为空,还有库存
127.0.0.1:6379> scan 1996 match key99* count 1000
1) "12594"
2) 1) "key9939"
2) "key9941"
...... // 扫描了 1000 个槽位,返回 N+ 条数据,还有库存
127.0.0.1:6379> scan 11687 match key99* count 1000
1) "0"
2) 1) "key9969"
2) "key998"
......
11) "key9944" // 扫描了 1000 个槽位,返回 11 条数据,游标为 0,没有库存啦
- 可以使用
--bigkeys
参数定位大键:
1
2
redis-cli -h 127.0.0.1 -p 7001 –-bigkeys
redis-cli -h 127.0.0.1 -p 7001 –-bigkeys -i 0.1 // i 为休眠参数,每隔 100 条 scan 指令就会休眠 0.1s
字典结构
字典结构的特殊性决定了 Scan 的高效,游标返回的是槽位号码,每个槽位(slot)挂载的元素可多可少,所以有可能出现返回结果为空的情况:
scan 命令以高位进位加法进行检索,与普通加法相反,但也可以遍历所有结果:
字典扩容
数组长度为
2^n
次方,所以取模运算等价于位与操作,a mod 8 = a & (8-1) = a & 7
,7 称为字典的mask
值。扩容操作使得原槽位xxx
中的一半数据不变还是0xxx
,另一半放到了1xxx(xxx+mask)
中:这样的字典伸缩方式使得 scan 按高位加法遍历数组变得无比高效,因为伸缩操作此时对 scan 的遍历方法毫无影响!rehash 后的槽位在遍历时的顺序依然是相邻的!!
渐进式 rehash 会同时保留旧数组和新数组,在定时任务中以及后续对 hash 的指令操作中渐渐地将旧数组中挂接的元素迁移到新数组上,避免大键伸缩造成卡顿
scan 处于 rehash 中的字典,需要同时扫描新旧槽位,然后将结果融合后返回给客户端
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK