背景

线上阿里云 redis 内存使用持续飙升,短时间内爆了好几次,一开始清空了些存了一百多万key的库,但内存缓慢释放了一定程度还是没什么用,仍然在警戒线附近,只好扩容,扩容又有几秒瞬断,引发了很多问题,因为我们所有的业务组都在使用同一个redis 服务器而且约定 redis 使用都是存的有时效性的,通过阿里云管理后台可以看到每天早上 redis 开始直线上升,等12个小时时间到期,又呈断崖式下跌,迫切需要分析下线上 redis 的内存具体使用情况,以诊断问题,看是哪个业务组使用导致的,能否从代码层面去优化并从根源上解决掉问题。这里直接使用 redis-rdb-tools 来进行静态分析,整个分析的过程非常简单但很实用,值得拥有!!!

使用

创建备份

为了不影响线上实例的使用,自建 Redis 的一般会采用 bgsave 生成 rdb 文件,云数据库 Redis 版本可以在控制台上进行数据备份和下载操作,下载后的数据为 rdb 格式文件。步骤详见下图:
rdb

介绍

redis-rdb-tools 是一个 python 的解析 rdb 文件的工具,在分析内存的时候,我们主要用它生成内存快照。主要有以下三个功能:

  • 生成内存快照
  • 转储成 json 格式
  • 使用标准的 diff 工具比较两个 dump 文件

redis-rdb-tools 安装

redis-rdb-tools 有两种安装方式,任选其一即可。
使用 PYPI 安装

pip install rdbtools

从源码安装

git clone https://github.com/sripathikrishnan/redis-rdb-tools
cd redis-rdb-tools
sudo python setup.py install

使用 redis-rdb-tools 生成内存快照

语法

Usage: rdb [options] /path/to/dump.rdb
Example : rdb --command json -k "user.*" /var/redis/6379/dump.rdb
Options:
  -h, --help  #显示此帮助消息并退出;         
  -c FILE, --command=FILE #指定rdb文件;                
  -f FILE, --file=FILE #指定导出文件;
  -n DBS, --db=DBS    #解析指定数据库,如果不指定默认包含所有;
  -k KEYS, --key=KEYS  #指定需要导出的KEY,可以使用正则表达式;
  -o NOT_KEYS, --not-key=NOT_KEYS #指定不需要导出的KEY,可以使用正则表达式;
  -t TYPES, --type=TYPES #指定解析的数据类型,可能的值有:string,hash,set,sortedset,list;可以提供多个类型,如果没有指定,所有数据类型都返回;
  -b BYTES, --bytes=BYTES #限制输出KEY大大小;
  -l LARGEST, --largest=LARGEST #根据大小限制的top key;
  -e ESCAPE, --escape=ESCAPE #指定输出编码,默认RAW;

生成内存快照的命令为:rdb -c memory dump.rdb > memory.csv,然后报错了!!!

[root@localhost mnt]# rdb -c memory hins6119739_data_20190109234325.rdb > memory.csv
WARNING: python-lzf package NOT detected. Parsing dump file will be very slow unless you install it. To install, run the following command:

pip install python-lzf

按照提示去安装 python-lzf,结果又报错了...

[root@localhost mnt]# pip install python-lzf
Collecting python-lzf==0.2.4
  Using cached             
  https://files.pythonhosted.org/p
Installing collected packages: python-lzf
  Running setup.py install for python-lzf ... error
    Complete output from command /usr/bin/python2 -u -c "import setuptools,         tokenize;__file__='/tmp/pip-install-2h02L5/python-lzf/setup.py';f=getattr(tokenize, 'open', open)    (__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" install --    record /tmp/pip-record-IPT2FC/install-record.txt --single-version-externally-managed --compile:
    running install
    running build
    running build_ext
    building 'lzf' extension
    creating build
    creating build/temp.linux-x86_64-2.7
    gcc -pthread -fno-strict-aliasing -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -D_GNU_SOURCE -fPIC -fwrapv -DNDEBUG -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -D_GNU_SOURCE -fPIC -fwrapv -fPIC -I. -I/usr/include/python2.7 -c lzf_module.c -o build/temp.linux-x86_64-2.7/lzf_module.o -Wall
lzf_module.c:3:20: fatal error: Python.h: No such file or directory
     #include "Python.h"
                    ^
    compilation terminated.
    error: command 'gcc' failed with exit status 1

    ----------------------------------------
Command "/usr/bin/python2 -u -c "import setuptools, tokenize;__file__='/tmp/pip-install-2h02L5/python-    lzf/setup.py';f=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n',     '\n');f.close();exec(compile(code, __file__, 'exec'))" install --record /tmp/pip-record-IPT2FC/install-    record.txt --single-version-externally-managed --compile" failed with error code 1 in /tmp/pip-install-    2h02L5/python-lzf/

莫慌!运行 yum install python-devel 即可,此时再安装 python-lzf 并生成内存快照就好了。会生成一个 CSV 格式的内存报告。包含的列有:

  • database :key在redis的db
  • type :key类型
  • key :key值
  • size_in_bytes :key的内存大小(byte)
  • encoding :value的存储编码形式
  • num_elements :key中的value的个数
  • len_largest_element :key中的value的长度
  • expiry :key过期时间

分析内存快照

直接将 CSV 的数据导入到 MySQL,当然怎么顺手怎么来,导入 SQLLite,Postgres等都行,视个人而异,这样就可以利用sql语句很方便的对Redis的内存数据进行各种分析了,导入方法自行百度。

数据导入以后,接下来想怎么分析就怎么分析了,举几个简单的例子:
查询key的个数

select count(*) from memory;

查询总的内存占用

select sum(size_in_bytes) from memory;

查询内存占用最高的10个key

select * from memory order by size_in_bytes desc limit 10;

查询value个数1000个以上的list

select * from memory where type='list' and num_elements > 1000;

总结

sql
可以看到内存占用最高的 Top100 全是应用市场业务组的,一个key最大34MB以上的 string 类型的 value,这一百个加起来就用了1.95G,虽然不像别的库key存了五十万,一百万,只存了900多个,但却占了95%的内存使用。

通过使用 redis-rdb-tools + mysql的方式,可以方便的对 redis 实例的内存情况进行静态的分析。整个过程也比较简单,获取到 rdb 之后即可。能够帮助排除业务中潜在的风险点,找到业务性能瓶颈。

最后修改:2020 年 06 月 09 日 12 : 51 PM
如果觉得我的文章对你有用,请随意赞赏