Redis中的数据结构对服务的性能有着举足轻重的影响,如果大key较多,容易形成性能瓶颈,甚至降低业务稳定性。定期分析内存并根据分析结果优化内存,可以保持服务的稳定和高效。为了不影响线上Redis服务的运行,您可以使用BGSAVE命令生成RDB文件,再结合redis-rdb-tools和SQLite进行静态分析。

前提条件

  • 已创建Linux系统的ECS实例。
  • ECS中已安装了SQLite。
说明
  • 如果云数据库Redis版实例的版本为4.0或以上,您可以使用Redis控制台的缓存分析功能直接进行缓存分析并查看大key,详情请参见缓存分析
  • 云数据库Redis版控制台的缓存分析功能不支持2.8版本的实例,如需分析2.8版本实例的内存数据,请使用本文介绍的方法。

创建备份文件

redis-rdb-tools简介

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

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

安装redis-rdb-tools

您可以在以下两种方式中任选其一安装redis-rdb-tools。

  • 在ECS中使用PYPI安装:
    pip install rdbtools
  • 在ECS中使用源码安装:
    git clone https://github.com/sripathikrishnan/redis-rdb-tools
    cd redis-rdb-tools
    sudo python setup.py install

使用redis-rdb-tools生成快照

在ECS中使用如下命令生成CSV格式的快照:

rdb -c memory dump.rdb > memory.csv

生成的快照包含如下几列的数据:

  • 数据库ID;
  • 数据类型;
  • key;
  • 内存使用量(Byte),包含key、value和其它值的容量;
    说明 内存使用量是理论上的近似值,一般略低于实际值。
  • 编码。

生成的CSV文件示例如下:

$head memory.csv
database,type,key,size_in_bytes,encoding,num_elements,len_largest_element
0,string,"orderAt:377671748",96,string,8,8,
0,string,"orderAt:413052773",96,string,8,8,
0,sortedset,"Artical:Comments:7386",81740,skiplist,479,41,
0,sortedset,"pay:id:18029",2443,ziplist,84,16,
0,string,"orderAt:452389458",96,string,8,8

将CSV文件导入SQLite数据库

SQLite是一款轻型的关系型数据库。将CSV文件中的数据导入到SQLite数据库中之后,即可使用SQL语句分析Redis的内存数据。

说明
  • SQLite版本必须是3.16.0以上。
  • 导入前请通过批量编辑或其它方式删除CSV文件中每行末尾的逗号(,)。

使用如下命令导入数据:

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 memory
sqlite>.import memory.csv memory

使用redis-rdb-tools分析内存快照

将数据导入SQLite数据库后,可根据需要使用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;