记一次redis内存翻倍问题排查

 

问题

巡查redis时发现短时间内存翻倍。

记一次redis内存翻倍问题排查

思路

  • 下载翻倍前后的rdb备份文件
  • 使用rdb-tool 生成rdb对应的csv report
  • 将csv处理后导入sqlite
  • 使用sqlite查询哪些key发生了变化
  • 根据key去业务代码中找相关代码查看

rdb-tool介绍

在获取到备份文件后,需要使用redis-rdb-tools生成内存快照。redis-rdb-tools是一个基于Python的RDB文件解析工具,主要有以下三个功能:

  • 生成内存快照;
  • 将RDB文件中的数据转换为JSON格式;
  • 对比两个RDB文件,发现差异。

 

csv结构介绍

记一次redis内存翻倍问题排查

 

具体步骤

  1. 下载rdb文件。如图所示点击下载,选择复制外网地址。使用wget命令下载

eg. wget "https://kyDNGPM4fYnS8%3D"  (记得给下载链接加双引号)

分别下载第二个和第三个rdb文件

  1. 安装 rdb-tool工具

 

git clone https://github.com/sripathikrishnan/redis-rdb-tools
cd redis-rdb-tools
sudo python setup.py install
  1. 执行生成csv report 命令

eg. rdb -c memory msg.rdb > msg.csv

rdb -c memory msg2.rdb > msg2.csv

  1. 将csv导入db
sqlite3 memory.db
sqlite> create table memory(database int,type varchar(128),key varchar(128),size_in_bytes int,encoding varchar(128),num_elements int,len_largest_element varchar(128));
sqlite>.mode csv 
sqlite>.import memory.csv memory

 

  1. 查询对比

记一次redis内存翻倍问题排查

记一次redis内存翻倍问题排查

记一次redis内存翻倍问题排查

  • 图一可以看到 user_inbox key占用内存由599Mb->3654Mb
  • 图二发现大量相同大小的 key。疑似同一消息多次发送给不同用户
  • 图三 证实确实是因为这个1564b大小的消息增多。
  1. 代码分析

管理后台有一个给全体玩家发送法官消息的功能,当时也确实是群推了一条消息。

如果玩家没有上线,那么这个消息就会存到消息盒子里。直到用户上线查看消息,客户端给服务器发confirm确认才会执行清除消息的逻辑。

 

 

常用查询report SQL

  • 查询内存中的key总数:
sqlite>select count(*) from memory;
  • 查询内存占用总量:
sqlite>select sum(size_in_bytes) from memory;
  • 查询内存占用量最高的10个key:
sqlite>select * from memory order by size_in_bytes desc limit 10;
  • 查询元素数量1000以上的list:
sqlite>select * from memory where type='list' and num_elements > 1000;
  • 相同类型key聚合查询(key 的长度自行调整)
select substr(key,0,28) kp,sum(size_in_bytes)/(1024*1024),count(*) from memory2 group by kp order by sum(size_in_bytes) desc;

 

参考资料

  1. 阿里云redis内存分析方法  https://help.aliyun.com/document_detail/141763.html?spm=5176.12818093.0.0.488716d0dQNQAK
  2. redis-rdb-cli 官方doc   https://github.com/sripathikrishnan/redis-rdb-tools