Redis 使用monitor造成的内存飙升_客户端

 

 

美团在Redis上踩过的坑-Redis内存占用飙升


一、现象:


    redis-cluster某个分片内存飙升,明显比其他分片高很多,而且持续增长。并且主从的内存使用量并不一致。

Redis 使用monitor造成的内存飙升_redis_02

 

二、分析可能原因:


 1.  redis-cluster的bug (这个应该不存在)

 2. 客户端的hash(key)有问题,造成分配不均。(redis使用的是crc16, 不会出现这么不均的情况)

 3. 存在个别大的key-value: 例如一个包含了几百万数据set数据结构(这个有可能)

 4. 主从复制出现了问题。

 5. 其他原因

 

三、调查原因:


 1. 经查询,上述1-4都不存在

 2. 观察info信息,有一点引起了怀疑: client_longes_output_list有些异常。

Redis 使用monitor造成的内存飙升_客户端_03

3. 于是理解想到服务端和客户端交互时,分别为每个客户端设置了输入缓冲区和输出缓冲区,这部分如果很大的话也会占用Redis服务器的内存。

Redis 使用monitor造成的内存飙升_客户端_04

从上面的client_longest_output_list看,应该是输出缓冲区占用内存较大,也就是有大量的数据从Redis服务器向某些客户端输出。于是使用client list命令(类似于mysql processlist) redis-cli -h host -p port client list | grep -v "omem=0",来查询输出缓冲区不为0的客户端连接,于是查询到祸首monitor,于是豁然开朗.

Redis 使用monitor造成的内存飙升_客户端_05

monitor的模型是这样的,它会将所有在Redis服务器执行的命令进行输出,通常来讲Redis服务器的QPS是很高的,也就是如果执行了monitor命令,Redis服务器在Monitor这个客户端的输出缓冲区又会有大量“存货”,也就占用了大量Redis内存。

Redis 使用monitor造成的内存飙升_服务器_06

 

四、紧急处理和解决方法


进行主从切换(主从内存使用量不一致),也就是redis-cluster的fail-over操作,继续观察新的Master是否有异常,通过观察未出现异常。查找到真正的原因后,也就是monitor,关闭掉monitor命令的进程后,内存很快就降下来了。

 

五、 预防办法:


1. 为什么会有monitor这个命令发生,我想原因有两个:

(1). 工程师想看看究竟有哪些命令在执行,就用了monitor

(2). 工程师对于redis学习的目的,因为进行了redis的托管,工程师只要会用redis就可以了,但是作为技术人员都有学习的好奇心和欲望。

2. 预防方法:

(1) 对工程师培训,讲一讲redis使用过程中的坑和禁忌

(2) 对redis云进行介绍,甚至可以让有兴趣的同学参与进来

(3) 针对client做限制,但是官方也不建议这么做,官方的默认配置中对于输出缓冲区没有限制。

client-output-buffer-limit normal 0 0 0  

(4) 密码:redis的密码功能较弱,同时多了一次IO

(5) 修改客户端源代码,禁止掉一些危险的命令(shutdown, flushall, monitor, keys *),当然还是可以通过redis-cli来完成

(6) 添加command-rename配置,将一些危险的命令(flushall, monitor, keys * , flushdb)做rename,如果有需要的话,找到redis的运维人员处理

 

六、模拟实验:


以一个monitor为例,使用redis-benchmark分别测试monitor开启前后的性能

redis-benchmark -c 10 -n 100000 -q

开启前结果

PING_INLINE: 92506.94 requests per second
PING_BULK: 97943.19 requests per second
SET: 94786.73 requests per second
GET: 99403.58 requests per second
INCR: 89766.61 requests per second
......

开启后结果

PING_INLINE: 76569.68 requests per second
PING_BULK: 67294.75 requests per second
SET: 44404.97 requests per second
GET: 60132.29 requests per second
INCR: 49382.71 requests per second
......

结果对比

开启后的性能明显低了很多,例如:

SET -53%

GET -39%

INCR -44%