目的
博主最近在工作上需要清理一个数年项目的 Redis,内存告警 90%,但是不能单靠看代码和直觉来清理,需要有个直观的参考指标。
并且线上的数据删除需要谨慎,删除的 key 众多,如果删出了问题势必需要快速回滚保证业务正常运行,所以还编写了一个安全删除的脚本,方便线上操作。
导出
在做全量的分析之前,首先需要拿到全量的 .rdb
文件。
如果是运行在 Linux 服务器中的 redis-server
,可以直接使用 dump.rdb
,存的东西太大的话就直接在从库主机上做分析即可,不用全量下载到本地。
如果是云服务商的话,就需要按照其官方文档的引导,获取到 .rdb
,博主目前所在公司使用了 aws 的全套服务,针对 redis 实例导出 rdb 文件搜集了如下资料。
已经获取到 .rdb
文件的可以跳过这一段了,由于里边操作较为复杂为节省同样使用 aws 同学的时间,大概整理一下操作过程
- 首先,创建一个与 redis实例 同区的存储桶
- 然后给存储桶配置权限,进入桶的访问控制列表 > 其他AWS账户的访问权限,添加账户输入
540804c33a284a299d2547575ce1010f2312ef3da9b3a053c8bc45bf233e4353
,权限勾选- 列出对象
- 写入对象
- 读取存储桶权限
- 然后,在
ElastiCache控制面板
>备份
> 选中备份 > 复制 - 写一个标志符,目标s3的位置选刚才建好的桶,点击复制,直到导出完成
- s3中发现对应的 rdb 文件:memory-clear-1-0001.rdb,下载即可
手动备份的官方文档:https://docs.aws.amazon.com/zh_cn/AmazonElastiCache/latest/red-ug/backups-manual.html
导出备份的官方文档:https://docs.aws.amazon.com/zh_cn/AmazonElastiCache/latest/red-ug/backups-exporting.html
分析
拿到 .rdb
文件后,下一步就是分析这个 rdb 文件中各个 key 占用的内存了,网络上也提供到了相关的工具。
安装工具并分析
pip install rdbtools
pip install python-lzf # 加快转储速度
进入到 rdb 所在目录,生产内存报告
rdb -c memory dump.rdb > dump.csv
下一步的分析,可以借助 excel 也可以借助 Mysql 等数据库工具导入 csv 后进行
CSV的内部结构大概是这样的:
database | type | key | size_in_bytes | encoding | num_elements | len_largest_element | expiry |
---|---|---|---|---|---|---|---|
0 | hash | Funcoloring_update_picture_formal:com.cm.fun.color:Android:2.1.1:v3:large_preview | 459060 | hashtable | 1 | 432708 | |
0 | hash | ad_stats:20200624:apps:com.ios.qyb.incolour | 201 | ziplist | 4 | 19 | 2020-07-09T00:00:04.621000 |
0 | hash | ad_stats:20200617:com.cm.fun.color:upltv:inter_open | 206 | ziplist | 4 | 19 | 2020-07-02T00:00:33.171000 |
0 | hash | ad_stats:20200620:com.ios.qyb.incolour:MAX:reward_hint | 206 | ziplist | 3 | 19 | 2020-07-05T00:01:31.333000 |
关键列
第一列 database
表示数据库id,在excel中可以借助筛选功能,得到每个数据库中占用的具体key数量和内存大小。
第二列 type
顾名思义,数据类型
第三列 key
不多讲
第四列 size_in_bytes
就是占用字节数
其他…
如何定位问题 key
我一般的操作是,借助 excel 把 size_in_bytes
/ 1024 / 1024,得到 Mb
单位的内存占用量,再使用排序功能得到占用最多的列
我这边遇到的情况是大约 20% 的 key 占用了超过 80% 的空间,所以一般不用看太多就可以定位到问题。
除了找那些占用巨大的key,还需要重点查看 没有过期时间的key,讲道理一般场景下的 redis 不适合单独持久化数据,容易导致数据来源混乱不好维护。
找到 key 之后,根据 key 的规则去找相关的代码,根据逻辑将需要删除的 key 找出来,没有设置过期时间的改代码设置下过期时间。
恢复数据
如果你下载到了本地想要恢复线上的数据做测试或方便的查看内容,那么你可能需要通过 .rdb
文件恢复数据
如果安装了 docker,可以把下载的 rdb 重命名为 dump.rdb
,映射到 /data
中,在 rdb 文件目录下可以使用如下指令,运行成功后
$ docker run --name test-redis -it -v `pwd`/dump.rdb:/data/dump.rdb --rm redis
1:C 01 Jul 2020 07:44:21.073 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
1:C 01 Jul 2020 07:44:21.073 # Redis version=6.0.1, bits=64, commit=00000000, modified=0, pid=1, just started
1:C 01 Jul 2020 07:44:21.073 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
然后进入容器使用 redis-cli
即可
$ docker exec -it test-redis /bin/bash
root@0910da87ae73:/data#
root@0910da87ae73:/data# redis-cli
127.0.0.1:6379>
127.0.0.1:6379> select 2
OK
127.0.0.1:6379[2]> KEYS *
1) "***:****:***"
如果本地搭好了环境,替换下 dump.rdb
即可,注意修改配置,否则可能加载失败
appendonly no
dbfilename dump.rdb # your rdb file name
dir /var/lib/redis # your rdb path
安全删除脚本
为方便回滚,编写了一个小脚本用于安全删除生产环境上的多个 key,执行删除的时候先把 key 按行放到 keys.txt
中,执行如下指令可以在删除的同时备份到 delete-backup.json
,如果出了问题直接回滚就好。
脚本仅支持五大基本类型,hyperloglog
类型的数据占用不会太大,也没想法子去兼容,list
类型出于可重复性回滚数据的考虑,每次都会先删除记录再回滚,如果线上在 push 列表,有一定的丢数据风险,考虑停机再次导出并合并有关的 list 数据。
用法
python convert.py delete keys.txt # safe delte and generate delete-backup.json
python convert.py revert delete-backup.json # rollback by delete-backup.json
代码