Redis应用实践——scan指令

从某种程度上来说,scan是来取代keys指令的。传统的keys指令不仅没有limit这类的参数,而且是通过遍历查找,复杂度是O(n)。

scan的基本用法

  • scan 0 match key99** count 1000

上面的 0 为cursor游标参数,这条指令执行完,会返回一个游标, 返回的游标不为0则代表还没有遍历完成。

上面的 1000 为limit值,但是这个值并不是指定了返回结果集的数量,而是服务器本次遍历的字典槽位数量(约等于)。所以你会发现,设置了1000的limit,返回的结果可能只有10条左右。

scan的遍历顺序

在你使用scan指令做了实验后,你可能发现,返回的游标并不是一次比一次大的。因为scan指令确实使用的不是从0开始顺序遍历的方法。

这是因为redis考虑到了字典扩容或者缩容的情况,所以使用了高位加法的方法来决定遍历的顺序。(原理代论证,这里不是很清楚)这样扩容后,可以继续从当前的槽往后遍历,之前的全部是已遍历过的,之后的都没有遍历过。

渐进式rehash

在扩容的过程中,如果key比较大,那么对所有元素进行rehash将会消耗比较长的时间,而redis又是单线程的,所以采用了渐进式的策略,也就是同时维护两个数组,在查找元素时如果一个找不到就要区另一个里面找。scan命令也需要同时扫描新旧的槽位。

大key扫描

如果一个key过大,在迁移时就会造成卡顿,而且在需要扩容时,也会一次性申请两倍大小的空间。

所以在业务开发中,尽量避免大key的产生,如果监控发现redis的内存大起大落,那就很可能时大key导致的问题。

redis-cli给我们提供了扫描大key的功能redis-cli -h 127.0.0.1 -p 7001 --bigkeys