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)就是下一次迭代游标,第二部分即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 |
命令耗时超过多少才会保存到
slowlog
中,可以通过命令config set slowlog-log-slower-than 2000
配置并且不需要重启redis
。注意:单位是微秒,2000微秒即2毫秒。
rename-command
为了防止把问题带到生产环境,我们可以通过配置文件重命名一些危险命令,例如keys
等一些高危命令。操作非常简单,只需要在conf配置文件增加如下所示配置即可:
rename-command flushdb flushddbb |
bigkeys
随着项目越做越大,缓存使用越来越不规范。我们如何检查生产环境上一些有问题的数据。bigkeys
就派上用场了,用法如下:
redis-cli -p 6380 --bigkeys |
执行结果如下:
... ... |
最后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 |
执行结果中很清楚的看到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_hits
和keyspace_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 100
,config set maxclients 1024
这样修改的话,如果以后由于某些原因redis
实例故障需要重启,那通过config
热修改的参数就会被配置文件中的参数覆盖,所以我们需要通过一个命令将config
热修改的参数刷到redis
配置文件中持久化,通过执行如下命令即可:
config rewrite |
执行该命令后,我们能在config
文件中看到类似这种信息:
如果conf中本来就有这个参数,通过执行config set,那么redis直接原地修改配置文件 |
set
官方文档介绍的用法如下:
SET key value [EX seconds] [PX milliseconds] [NX|XX] |
你可能用的比较多的就是set key value
,或者SETEX key seconds value
,所以很多同学用redis
实现分布式锁分为两步:首先执行SETNX key value
,然后执行EXPIRE key seconds
。很明显,这种实现有很严重的问题,因为两步执行不具备原子性,如果执行第一个命令后出现某些未知异常导致无法执行EXPIRE key seconds
,那么分布式锁就会一直无法得到释放。
通过SET
命令实现分布式锁的正式姿势应该是SET key value EX seconds NX
(EX和PX任选,取决于对过期时间精度要求)。另外,value也有要求,最好是一个类似UUID
这种具备唯一性的字符串。当然如果问你redis
是否还有其他实现分布式锁的方案。你能说出redlock
,那对方一定眼前一亮,心里对你竖起大拇指,但嘴上不会说。
参考
- 阿飞的博客,公众号