目录

Redis Scan 命令使用讨论

keys 命令与 scan 命令的区别

相同点和不同点:

操作 相同点 不同点
scan 时间复杂度O(n) 迭代扫描,消耗内存少
keys 时间复杂度O(n) 消耗内存大

Q&A

keys性能低,keys操作会锁整个库

还多少人看了网上的博客或者笔记,得出 keys 性能低,会锁整个库。那一定是你对底层不了解,或者网络文章的作者对底层一知半解。

我先把结论抛给你,然后再慢慢给你解释。

执行 Redis 的任何操作命令都会锁库,准确的说是锁整个服务器上的所有的 DB。

原因很简单,Redis 的 IO 操作是单线程的,执行任何一个操作命令都会其他操作命令无法得到执行。想要执行也要等前一个命令执行完成。

Redis 数据操作之所以 IO 单线程,是因为他认为多线程不过是为了提高效率,但是由于 Redis 操作的是内存,速度很快,反而引入了多线程,多线程的上下文切换,环境变量的保存与恢复反而降低了其效率。

其实现实应用中使用单线程的应用还是有很多的,例如 Nginx,NodeJS。

  • 那为何大家实际使用中,没有感受到其他操作命令锁库,而是感觉到了 keys 锁库呢?

Redis 底层使用的哈希表结构,其查找时间复杂度是 O(1)。然而 keys 是使用正则遍历整个库中的所有 keys ,其时间复杂度是 O(n)。随着库里 key 的增多,keys 的执行时间变长,所以让大家明显感觉到其锁库。其实大家都锁库。

项目使用了 key 做队列,使用 scan 获取队列,如何优化

首先说下你使用 key 做队列的缺点,队列中的元素位置是随机的,scan 获取出来的元素也是随机的,所以在消费任务的时候,不符合队列的 FIFO 准则。

其次如果你每次 scan 获取的元素数量有限,而 DB 中的 key 过多,就大大地增加了网络 IO 的次数。==我们知道 Redis 的性能瓶颈在网络 IO==,如果这样倒不如使用 keys 来的痛快。

如果这样说大家可能糊涂了,明明为了解决 keys 的低性能,引入的 scan,你这里又说 keys 比 scan 来的痛快,那么二者该如何取舍呢?

操作 使用场景 使用原因
keys DB 中 key 多,但是目标 key 少的情况 避免 scan 过多的网络 IO 请求,却命中率不高
scan DB 中目标 key 多,非目标 key 少的情况 避免 keys 返回的目标数据量过大,造成内存溢出。

二者的使用是为了达到一个均衡的效率。以上讨论仅限于在 keys 和 scan 二者中间的取舍。毕竟其他数据结构优于他们。