为了账号安全,请及时绑定邮箱和手机立即绑定

玩转Redis—如何高效访问Redis中的海量数据

标签:
CSS3

1、前言

Redis以高性能著称,但性能再好,在面对海量数据时,若不正确的使用,也终将会有性能瓶颈,甚至造成服务宕机。

在实际项目中你是否会有以下疑问?

以上问题亦是Redis面试的高频问题。

2、思考

Q1:为什么Redis中的数据量很大时,某些数据操作会导致Redis卡顿,甚至宕机?

A1:Redis是单线程服务,所有指令都是顺序执行,当某一指令耗时很长时,就会阻塞后续的指令执行。当被积压的指令越来越多时,Redis服务占用CPU将不断升高,最终导致Redis实例崩溃甚至服务器宕机。

Q2:利用万能的keys命令查询任何想查的数据?

A2:自己电脑几万条数据玩玩就好了,线上使用keys命令,Excuse me?你想卷铺盖走人了吧。

++“某公司php工程师执行redis keys * 导致数据库宕机! 技术部发生2起本年度PO级特大事故,造成公司资金损失400万。”++ 这条新闻记忆犹新,警钟长鸣!

Q3:Redis中海量数据的正确操作方式

A3:利用SCAN系列命令(SCAN、SSCAN、HSCAN、ZSCAN)完成数据迭代。

Redis的【SCAN系列命令】你了解多少呢?

3、SCAN系列命令详解

SCAN系列命令,并不单纯指代SCAN命令,还包含SSCAN、HSCAN、ZSCAN,每种命令操作对象是有区别的,但用法及功能基本相同。

3.1、SCAN系列命令对比分析

玩转Redis—如何高效访问Redis中的海量数据

3.2、SCAN系列命令注意事项

3.3、SCAN系列命令详解

3.3.1、 增量迭代,可用于生产环境

3.3.2、不保证准确结果

3.3.3、基于游标迭代

3.3.4、迭代结束标记

3.3.5、迭代完整性

3.3.6、why有时迭代直接返回整个集合

3.3.7、参数count说明

3.3.8、参数match说明

4、SCAN系列命令示例

4.1、SCAN示例

详见《5.2、部分问题解答》

4.2、SSCAN示例

// SSCAN示例 @zxiaofan

127.0.0.1:6378> SADD sscantest sscantest:1 1 sscantest:2 2 sscantest:3 3 sscantest:4 4 sscantest:1a 1a sscantest:2a 2a sscantest:1ab 1ab sscantest:a1 a1 sscantest:aa1 aa1

(integer) 0

// MATCH ?:无匹配数据

127.0.0.1:6378> SSCAN sscantest 0 MATCH ? COUNT 1

1) “24”

2) (empty list or set)

127.0.0.1:6378> SSCAN sscantest 24 MATCH ? COUNT 1

1) “20”

2) (empty list or set)

127.0.0.1:6378> SSCAN sscantest 0 MATCH * COUNT 1

1) “24”

2) 1) “sscantest:3”

2) “sscantest:2a”

127.0.0.1:6378> SSCAN sscantest 24 MATCH * COUNT 1

1) “20”

2) 1) “a1”

4.3、HSCAN示例

// HSCAN示例 @zxiaofan

127.0.0.1:6378> HMSET hscantest hscantest:1 1 hscantest:2 2 hscantest:3 3 hscantest:4 4 hscantest:1a 1a hscantest:2a 2a hscantest:1ab 1ab hscantest:a1 a1 hscantest:aa1 aa1

OK

127.0.0.1:6378> HSCAN hscantest 0 MATCH hscantest*a COUNT 20

1) “0”

2) 1) “hscantest:1a”

2) “1a”

3) “hscantest:2a”

4) “2a”

127.0.0.1:6378> HSCAN hscantest 0 MATCH hscantest*a COUNT 2

1) “0”

2) 1) “hscantest:1a”

2) “1a”

3) “hscantest:2a”

4) “2a”

127.0.0.1:6378>

从HSCAN示例可以看出,即使count参数为2,也返回了所有匹配的结果。这就是先前提到的,数据量较小时,直接返回所有数据。

4.4、ZSCAN示例

// ZSCAN示例 @zxiaofan

// 【移除】并弹出count个分数最大的元素,count默认为1

127.0.0.1:6378> ZPOPMAX zscantest 20

1) “sscantest:1ab”

2) “6”

3) “sscantest:2a”

4) “5”

5) “sscantest:1a”

6) “4”

7) “sscantest:3”

8) “3”

9) “zscantest:1”

10) “2”

11) “sscantest:2”

12) “2”

13) “test1”

14) “1”

15) “sscantest:1”

16) “1”

127.0.0.1:6378> ZPOPMAX zscantest 20

(empty list or set)

127.0.0.1:6378> ZADD zscantest 1 zscantest:1 2 zscantest:2 3 zscantest:3 4 zscantest:1a 5 zscantest:2a 6 zscantest:1ab 7 zscantest:a1 8 zscantest:aa1

(integer) 8

// NX:不存在才添加;CH:返回被改变(含新增)的元素个数

127.0.0.1:6378> ZADD zscantest NX CH 1 test1 2 zscantest:1

(integer) 1

127.0.0.1:6378> ZSCAN zscantest 0 MATCH *a COUNT 5

1) “0”

2) 1) “zscantest:1a”

2) “4”

3) “zscantest:2a”

4) “5”

127.0.0.1:6378> 5、总结

5.1、看看面试时你能答上几个自考问题

5.2、部分问题解答

5.2.1、SCAN返回数据为空就是迭代结束了吗

// SCAN返回数据为空就是迭代结束了吗? @zxiaofan

127.0.0.1:6378> keys k?

1) “k1”

2) “k2”

127.0.0.1:6378> SCAN 0 MATCH k?

1) “88”

2) (empty list or set)

127.0.0.1:6378> SCAN 88 MATCH k?

1) “34”

2) 1) “k1”

127.0.0.1:6378> SCAN 34 MATCH k?

1) “122”

2) (empty list or set)

127.0.0.1:6378> SCAN 122 MATCH k?

1) “14”

2) (empty list or set)

127.0.0.1:6378> SCAN 14 MATCH k?

1) “33”

2) (empty list or set)

127.0.0.1:6378> SCAN 33 MATCH k?

1) “53”

2) (empty list or set)

127.0.0.1:6378> SCAN 53 MATCH k?

1) “93”

2) (empty list or set)

127.0.0.1:6378> SCAN 93 MATCH k?

1) “107”

2) 1) “k2”

127.0.0.1:6378> SCAN 107 MATCH k?

1) “79”

2) (empty list or set)

127.0.0.1:6378> SCAN 79 MATCH k?

1) “0”

2) (empty list or set)

127.0.0.1:6378>

看上述示例,匹配“k?”的数据实际有2条“k1”、“k2”,在整个迭代过程中,多次返回数据为空,但是迭代未曾结束(因为“k1”、“k2”没有全部迭代返回)。

所以,只有当游标返回为0时,才能说明迭代结束了。

5.2.2、如果首次迭代cursor参数不是0,能实现完整迭代吗?

// 如果首次迭代cursor参数不是0,能实现完整迭代吗? @zxiaofan

127.0.0.1:6378> keys k?

1) “k1”

2) “k2”

127.0.0.1:6378> SCAN 66 MATCH k?

1) “122”

2) (empty list or set)

127.0.0.1:6378> SCAN 122 MATCH k?

1) “14”

2) (empty list or set)

127.0.0.1:6378> SCAN 14 MATCH k?

1) “33”

2) (empty list or set)

127.0.0.1:6378> SCAN 33 MATCH k?

1) “53”

2) (empty list or set)

127.0.0.1:6378> SCAN 53 MATCH k?

1) “93”

2) (empty list or set)

127.0.0.1:6378> SCAN 93 MATCH k?

1) “107”

2) 1) “k2”

127.0.0.1:6378> SCAN 107 MATCH k?

1) “79”

2) (empty list or set)

127.0.0.1:6378> SCAN 79 MATCH k?

1) “0”

2) (empty list or set)

127.0.0.1:6378>

看上述示例,匹配“k?”的数据实际有2条“k1”、“k2”,当第一次SCAN使用cursor为66,我们可以发现经过多次迭代,游标返回为0时,“k1”一直未曾被迭代返回。

所以,如果首次迭代cursor参数不是0,不能实现完整迭代。

完整迭代必须是游标从0开始,游标到0结束。

6、后记

本文针对Redis的SCAN系列命令做了详细的对比分析以及实际使用示例,并整理了面试中的高频问题。建议阅读本文的同学实际动手练习下,效果更好。

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消