Redis源码解析:keys不让用,scan小心坑

请添加图片描述

为什么不让用keys

在这里插入图片描述
我们都知道Redis其实就是一个大map,而使用keys的时候会遍历这个map中所有key并返回符合条件的key

// 返回所有的key
keys *

// 返回以test为前缀的key
keys test*

这个命令有很明显的缺点,一次性返回所有符合条件的key,会造成Redis服务卡顿。因为Redis是单线程的程序,顺序执行命令,其他命令必须等到当前keys指令执行完毕才能继续

所以一般情况下keys*命令是禁止使用的

使用scan要小心

为了解决keys的问题,Redis在后续的版本中提供了scan命令及其相关的命令

SCAN遍历数据库中的键
SSCAN遍历set中的键
HSCAN遍历hash中的键
ZSCAN遍历zset中的键盘(包括元素成员和元素分值)。

scan相关的命令使用格式如下

SCAN cursor [MATCH pattern] [COUNT count]
127.0.0.1:6379> scan 0 match testKey* count 2
1) "1"
2) 1) "testKey4"
   2) "testKey1"
   3) "testKey2"
   4) "testKey3"
127.0.0.1:6379> scan 1 match testKey* count 2
1) "13"
2) 1) "testKey5"
   2) "testKey"
127.0.0.1:6379> scan 13 match testKey* count 2
1) "15"
2) 1) "testKey6"
127.0.0.1:6379> scan 15 match testKey* count 2
1) "0"
2) (empty list or set)

当我们用scan遍历的时候,先指定游标为0,然后查询结果中会返回下次遍历需要传入的游标。直到最后返回的游标为0,才能判断已经遍历完毕。

注意返回结果为空时,并不表明遍历结束,只有当返回的游标为0时才能表明遍历结束

另外还有一个注意的点是,count参数只能大概用来控制返回的结果,返回的数量并不严格按照count,有可能比count多,也有可能比count少,上面的demo就是一个很明显的例子,为什么会这样呢?我们后续来分析

scan系的命令最终都调用了同一个方法,所以他们的实现逻辑是一样的,只不过遍历的对象有所差别。
在这里插入图片描述

当数据的encoding为ziplist,intset时,会直接返回所有的数据(因为ziplist,intset存储的元素比较少)

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
SCAN命令中的count参数为什么只能大概控制返回的数量?

// db.c/scanGenericCommand
do {
    cursor = dictScan(ht, cursor, scanCallback, NULL, privdata);
} while (cursor &&
      maxiterations-- &&
      listLength(keys) < (unsigned long)count);

先根据cursor遍历数组,遍历的过程中并不会实时校验count值,只有遍历完一次cursor才会校验,如果数量已经大于等于count值了则不再遍历,否则接着遍历。

有待验证

因此遍历完的key总是大于count的,但是后续还会有根据pattern筛选的过程,因此count参数只能一个大概控制返回数量的作用

参考博客

命令实现
[1]https://www.jianshu.com/p/be15dc89a3e8
scan详解
[2]http://redisdoc.com/database/scan.html#scan
原理解析与踩坑
[3]https://www.lixueduan.com/post/redis/redis-scan/
踩坑记录
[4]https://blog.51cto.com/u_15127597/4726910
scan实现原理
[5]https://blog.csdn.net/weixin_43705457/article/details/105255962

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Java识堂

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值