记一次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结构介绍
具体步骤
- 下载rdb文件。如图所示点击下载,选择复制外网地址。使用wget命令下载
eg. wget "https://kyDNGPM4fYnS8%3D" (记得给下载链接加双引号)
分别下载第二个和第三个rdb文件
- 安装 rdb-tool工具
git clone https://github.com/sripathikrishnan/redis-rdb-tools cd redis-rdb-tools sudo python setup.py install
- 执行生成csv report 命令
eg. rdb -c memory msg.rdb > msg.csv
rdb -c memory msg2.rdb > msg2.csv
- 将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
- 查询对比
- 图一可以看到 user_inbox key占用内存由599Mb->3654Mb
- 图二发现大量相同大小的 key。疑似同一消息多次发送给不同用户
- 图三 证实确实是因为这个1564b大小的消息增多。
- 代码分析
管理后台有一个给全体玩家发送法官消息的功能,当时也确实是群推了一条消息。
如果玩家没有上线,那么这个消息就会存到消息盒子里。直到用户上线查看消息,客户端给服务器发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;
参考资料
- 阿里云redis内存分析方法 https://help.aliyun.com/document_detail/141763.html?spm=5176.12818093.0.0.488716d0dQNQAK
- redis-rdb-cli 官方doc https://github.com/sripathikrishnan/redis-rdb-tools