为什么使用scan?
因为在Redis的命令执行是单线程模型的,使用keys
指令时,若数据量很大,Redis会对全量数据进行匹配,导致会有几秒钟的阻塞事件,而Scan是通过游标对hash-slot
分步进行的,阻塞时间短,适合进行线上生产环境使用。
scan特点
- 复杂度虽然也是 O(n),但是它是通过游标分步进行的,不会阻塞线程;
- 提供 limit 参数,可以控制每次返回结果的最大条数,limit 只是一个 hint,返回的结果可多可少;
- 同 keys 一样,它也提供模式匹配功能;
- 服务器不需要为游标保存状态,游标的唯一状态就是 scan 返回给客户端的游标整数;
- 返回的结果可能会有重复,需要客户端去重复,这点非常重要;
- 遍历的过程中如果有数据修改,改动后的数据能不能遍历到是不确定的;
- 单次返回的结果是空的并不意味着遍历结束,而要看返回的游标值是否为零;
scan遍历方式(高位加法)
普通加法和高位进位加法的区别
高位进位法从左边加,进位往右边移动,同普通加法正好相反。但是最终它们都会遍历所有的槽位并且没有重复。
WHY?
可以大大避免重复检索同一hash-slot
。
数据重复与丢失问题
数据重复
遍历的过程中,发送了hash-slot
的收缩,导致两个hash-slot
合并成一个,不得不重新检索当前槽位,造成数据的重复。
数据丢失
scan
对全量keys进行分段遍历的过程中,有数据插入到已经遍历过的插槽中,该数据不会被检索出。