【死磕Redis系列】九、Scan

------------------------------------------------------------------------------------------------------慢慢来,一切都来得及


 

了解

问题:在平时线上 Redis 维护工作中,有时候需要从 Redis 实例成千上万的 key 中找出特定前缀的 key 列表来手动处理数据,可能是修改它的值,也可能是删除 key。这里就有一个问题,如何从海量的 key 中找出满足特定前缀的 key 列表来?

Redis 提供了一个简单暴力的指令 keys 用来列出所有满足特定正则字符串规则的 key。

这个指令使用非常简单,提供一个简单的正则字符串即可,但是有很明显的两个缺点

1、没有 offsetlimit 参数一次性吐出所有满足条件的 key万一实例中有几百 w 个key 满足条件当你看到满屏的字符串刷的没有尽头时你就知道难受了

2 keys 算法是遍 历算法 杂度是 O(n) 如果 实例中有千万级以上的 key 这个指令就会导致 Redis 务卡顿 所有 读写 Redis 的其它的指令都会被延后甚至会超 时报错 为Redis 是 单线程程序 顺序执行所有指令 其它指令必 须等到当前的 keys 指令 执行完了才可以继续
 
Redis 为了解决这个问题,它在 2.8 版本中加入了大海捞针的指令—— scan scan 相比 keys 具备有以下特点 :
1 杂度虽然也是 O(n) 但是它是通 过游标分步进行的 不会阻塞线程 ;
2 提供 limit 参数 可以控制每次返回 结果的最大条数 limit 只是一个 hint 返回的结果可多可少;
3 keys 它也提供模式匹配功能 ;
4 务器不需要为游标保存状态 标的唯一状态就是 scan 返回 给客户端的游标整数 ;
5 返回的 结果可能会有重复 需要客户端去重复 这点非常重要 ;
6 历的过程中如果有数据修改 动后的数据能不能遍历到是不确定的 ;
7 单次返回的结果是空的并不意味着遍历结束 而要看返回的游 标值是否为零 ;
 

使用

scan 参数提供了三个参数,第一个是 cursor 整数值 ,第二个是 key 的正则模式 ,第三个是 遍历的 limit hint 。第一次遍历时 cursor 值为 0 ,然后将返回结果中第一个整数值作为下一次遍历的 cursor 。一直遍历到返回的 cursor 值为 0 时结束。
 

scan 历顺序

scan 的遍历顺序非常特别。它不是从第一维数组的第 0 位一直遍历到末尾,而是采用了高位进位加法来遍历。之所以使用这样特殊的方式进行遍历,是考虑到字典的扩容和缩容时避免槽位的遍历重复和遗漏。
 
普通加法和高位进位加法的区别
 
高位进位法从左边加,进位往右边移动,同普通加法正好相反。但是最终它们都会遍历所有的槽位并且没有重复。
 
发布了22 篇原创文章 · 获赞 10 · 访问量 6125

猜你喜欢

转载自blog.csdn.net/qq_28681387/article/details/105497677