第一时间阅读精彩文章!
点击这段文字获取:5个可以写到简历的项目实战视频教程(含源码)
大家肯定用过Redis,也知道Redis的命令以及用法,但是假如在某些场景下,误用了一些命令,后果会非常严重,所以要坚决杜绝这样的事情发生,由于我自己之前误用过,所以事故报告它来了!
前言
我相信大家都猜到了这个导致服务器挂的命令是什么,没错,他就是
“
keys”
命令。
误用这个Redis命令的场景是:
由于业务需要,会定时更新一批缓存的数据,但是一个个获取key效率低下,所以就想到了批量获取的思路,然后就使用了keys命令,在本地或者测试环境下,由于缓存中key的数量并不是那么多,所以没有出现缓存挂或者服务器宕机的情况,但是随着历史数据的增加和业务的增长,缓存中的key越来越多,达到了几百万甚至上千万,所以使用keys命令的时候,查询出来的符合查询规则的数据量也非常大,导致服务器阻塞,随后宕机!
解析KEYS命令
先来看下官网的介绍
查找所有符合给定模式pattern(正则表达式)的 key 。
时间复杂度为O(N),N为数据库里面key的数量。
例如,Redis在一个有1百万个key的数据库里面执行一次查询需要的时间是40毫秒 。
警告:
KEYS
的速度非常快,但在一个大的数据库中使用它仍然可能造成性能问题,如果你需要从一个数据集中查找特定的
KEYS
, 你最好还是用 Redis 的集合结构
SETS
来代替。
支持的正则表达模式:
-
h?llo
匹配
hello
,
hallo
和
hxllo
-
h*llo
匹配
hllo
和
heeeello
-
h[ae]llo
匹配
hello
和
hallo,
但是不匹配
hillo
-
h[^e]llo
匹配
hallo
,
hbllo
, … 但是不匹配
hello
-
h[a-b]llo
匹配
hallo
和
hbllo
如果你想取消字符的特殊匹配(正则表达式,可以在它的前面加
\
。
返回值
array-reply: 所有符合条件的key
例子:
redis> MSET one 1 two 2 three 3 four 4
OK
redis> KEYS *o*
1) "four"
2) "one"
3) "two"
redis> KEYS t??
1) "two"
redis> KEYS *
1) "four"
2) "three"
3) "one"
4) "two"
redis>
可以看到官网在介绍keys的时候从优点和缺点都给出了信息,优点就是在数据量没那么大的时候,keys的效率确实非常高,但是缺点也很明显,那就是会影响服务器的性能,导致服务器阻塞,进而影响其他服务的使用
了解了keys命令之后,Garnett确实也不推荐搭建使用,所以这里我们就不深入去研究keys命令了,那么不推荐使用这个,有什么替代方案吗,当然有了,那就是SCAN命令
解析SCAN命令
先来看下官网的介绍
SCAN 命令及其相关的 SSCAN, HSCAN 和 ZSCAN 命令都用于增量迭代一个集合元素。
以上列出的四个命令都支持增量式迭代,它们每次执行都只会返回少量元素,所以这些命令可以用于生产环境,而不会出现像 KEYS 或者 SMEMBERS 命令带来的可能会阻塞服务器的问题。
不过,SMEMBERS 命令可以返回集合键当前包含的所有元素, 但是对于SCAN这类增量式迭代命令来说,有可能在增量迭代过程中,集合元素被修改,对返回值无法提供完全准确的保证。
官网再次提到了在使用KEYS时候的缺点,所以还是特别要重视的
SCAN命令的基本用法
SCAN命令是一个基于游标的迭代器
。这意味着命令每次被调用都需要使用上一次这个调用返回的游标作为该次调用的游标参数,以此来延续之前的迭代过程
当SCAN命令的游标参数被设置为 0 时, 服务器将开始一次新的迭代, 而当服务器向用户返回值为 0 的游标时, 表示迭代已结束。
以下是一个 SCAN 命令的迭代过程示例 :
redis 127.0.0.1:6379> scan 0
1) "17"
2) 1) "key:12"
2) "key:8"
3) "key:4"
4) "key:14"
5) "key:16"
6) "key:17"
7) "key:15"
8) "key:10"
9) "key:3"
10) "key:7"
11) "key:1"
redis 127.0.0.1:6379> scan 17
1) "0"
2) 1) "key:5"
2) "key:18"
3) "key:0"
4) "key:2"
5) "key:19"
6) "key:13"
7) "key:6"
8) "key:9"
9) "key:11"
在上面这个例子中, 第一次迭代使用 0 作为游标, 表示开始一次新的迭代。第二次迭代使用的是第一次迭代时返回的游标 17 ,作为新的迭代参数 。
显而易见,
SCAN命令的返回值
是一个包含两个元素的数组, 第一个数组元素是用于进行下一次迭代的新游标, 而第二个数组元素则是一个数组, 这个数组中包含了所有被迭代的元素。