keys

我把这个命令放在第一位,是因为笔者曾经做过的项目,以及一些朋友的项目,都因为使用 keys 这个命令,导致出现性能毛刺。这个命令的时间复杂度是O(N),而且redis又是单线程执行,在执行keys时即使是时间复杂度只有O(1)例如SET或者GET这种简单命令也会堵塞,从而导致这个时间点性能抖动,甚至可能出现timeout。

强烈建议生产环境屏蔽keys命令(后面会介绍如何屏蔽)。

scan

既然keys命令不允许使用,那么有什么代替方案呢?有!那就是 scan 命令。如果把keys命令比作类似 select * from users where username like '%afei%' 这种SQL,那么scan应该是 select * from users where id>? limit 10 这种命令。

官方文档用法如下:

SCAN cursor [MATCH pattern] [COUNT count]

初始执行scan命令例如 scan 0。SCAN命令是一个基于游标的迭代器。这意味着命令每次被调用都需要使用上一次这个调用返回的游标作为该次调用的游标参数,以此来延续之前的迭代过程。当SCAN命令的游标参数被设置为0时,服务器将开始一次新的迭代,而 当redis服务器向用户返回值为0的游标时,表示迭代已结束,这是唯一迭代结束的判定方式,而不能通过返回结果集是否为空判断迭代结束。

使用方式:

127.0.0.1:6380> scan 0
1)
"22"
2)
 1)
"23"
    2)
"20"
    3)
"14"
    4)
"2"
    5)
"19"
    6)
"9"
    7)
"3"
    8)
"21"
    9)
"12"
   10)
"25"
   11)
"7"

返回结果分为两个部分:第一部分即1)就是下一次迭代游标,第二部分即2)就是本次迭代结果集。

slowlog

上面提到不能使用keys命令,如果就有开发这么做了呢,我们如何得知?与其他任意存储系统例如mysql,mongodb可以查看慢日志一样,redis也可以,即通过命令 slowlog。用法如下:

SLOWLOG subcommand [argument]

subcommand主要有:

  • get,用法:slowlog get [argument],获取argument参数指定数量的慢日志。

  • len,用法:slowlog len,总慢日志数量。

  • reset,用法:slowlog reset,清空慢日志。

执行结果如下:

127.0.0.1:6380> slowlog get 5
1)
1)
(integer)
2
   2)
(integer)
1532656201
   3)
(integer)
2033
   4)
1)
"flushddbb"
2)
1)
(integer)
1  ----  慢日志编码,一般不用care
   2)
(integer)
1532646897  ----  导致慢日志的命令执行的时间点,如果api有timeout,可以通过对比这个时间,判断可能是慢日志命令执行导致的
   3)
(integer)
26424  ----  导致慢日志执行的redis命令,通过4)可知,执行config rewrite导致慢日志,总耗时26ms+
   4)
1)
"config"
      2)
"rewrite"

命令耗时超过多少才会保存到slowlog中,可以通过命令 config set slowlog-log-slower-than 2000 配置并且不需要重启redis。注意:单位是微妙,2000微妙即2毫秒。

rename-command

为了防止把问题带到生产环境,我们可以通过配置文件重命名一些危险命令,例如 keys 等一些高危命令。操作非常简单,只需要在conf配置文件增加如下所示配置即可:

rename-command flushdb flushddbb
rename-command flushall flushallall
rename-command keys keysys

bigkeys

随着项目越做越大,缓存使用越来越不规范。我们如何检查生产环境上一些有问题的数据。 bigkeys 就派上用场了,用法如下:

redis-cli -p 6380 --bigkeys

执行结果如下:

... ...
-------- summary -------

Sampled 526 keys in the keyspace!
Total key length in bytes is 1524 (avg len 2.90)

Biggest string found 'test' has 10005 bytes
Biggest   list found 'commentlist' has 13 items

524 strings with 15181 bytes (99.62% of keys, avg size 28.97)
2 lists with 19 items (00.38% of keys, avg size 9.50)
0 sets with 0 members (00.00% of keys, avg size 0.00)
0 hashs with 0 fields (00.00% of keys, avg size 0.00)
0 zsets with 0 members (00.00% of keys, avg size 0.00)

最后5行可知,没有set,hash,zset几种数据结构的数据。string类型有524个,list类型有两个;通过 Biggest ... ... 可知,最大string结构的key是 test,最大list结构的key是 commentlist

需要注意的是,这个 bigkeys得到的最大,不一定是最大。说明原因前,首先说明 bigkeys 的原理,非常简单,通过scan命令遍历,各种不同数据结构的key,分别通过不同的命令得到最大的key:

  • 如果是string结构,通过 strlen 判断;

  • 如果是list结构,通过 llen 判断;

  • 如果是hash结构,通过 hlen 判断;

  • 如果是set结构,通过 scard 判断;

  • 如果是sorted set结构,通过 zcard 判断。

正因为这样的判断方式,虽然string结构肯定可以正确的筛选出最占用缓存,也可以说最大的key。但是list不一定,例如,现在有两个list类型的key,分别是:numberlist–[0,1,2],stringlist–[“123456789123456789”],由于通过llen判断,所以numberlist要大于stringlist。而事实上stringlist更占用内存。其他三种数据结构hash,set,sorted set都会存在这个问题。使用bigkeys一定要注意这一点。

monitor

假设生产环境没有屏蔽keys等一些高危命令,并且slowlog中还不断有新的keys导致慢日志。那我们如何揪出这些命令是由谁执行的呢?这就是 monitor 的用处,用法如下:

redis-cli -p 6380 monitor

如果当前redis环境OPS比较高,那么建议结合linux管道命令优化,只输出keys命令的执行情况:

[afei@redis ~]# redis-cli -p 6380 monitor | grep keys
1532645266.656525 [0 10.0.0.1:43544] "keyss" "*"
1532645287.257657 [0 10.0.0.1:43544] "keyss" "44*"

执行结果中很清楚的看到keys命名执行来源。通过输出的IP和端口信息,就能在目标服务器上找到执行这条命令的进程,揪出元凶,勒令整改。

info

如果说哪个命令能最全面反映当前redis运行情况,那么非info莫属。用法如下:

INFO [section]

section可选值有:

  • Server:运行的redis实例一些信息,包括:redis版本,操作系统信息,端口,GCC版本,配置文件路径等;

  • Clients:redis客户端信息,包括:已连接客户端数量,阻塞客户端数量等;

  • Memory:使用内存,峰值内存,内存碎片率,内存分配方式。这几个参数都非常重要;

  • Persistence:AOF和RDB持久化信息;

  • Stats:一些统计信息,最重要三个参数:OPS( instantaneous_ops_per_sec), keyspace_hitskeyspace_misses 两个参数反应缓存命中率;

  • Replication:redis集群信息;

  • CPU:CPU相关信息;

  • Keyspace:redis中各个DB里key的信息;

config

config是一个非常有价值的命令,主要体现在对redis的运维。因为生产环境一般是不允许随意重启的,不能因为需要调优一些参数就修改conf配置文件并重启。redis作者早就想到了这一点,通过config命令能热修改一些配置,不需要重启redis实例,可以通过如下命令查看哪些参数可以热修改:

config get *

热修改就比较容易了,执行如下命令即可:

config set

例如: config set slowlog-max-len 100config set maxclients 1024

这样修改的话,如果以后由于某些原因redis实例故障需要重启,那通过config热修改的参数就会被配置文件中的参数覆盖,所以我们需要通过一个命令将config热修改的参数刷到redis配置文件中持