最近发现项目中用的 redis
内存消耗很大(可是印象中却觉得没有这么多的key的内存消耗才对呀?),使用 info
命令能够看到全部key占用的一些内存大小以及key的数量等等,以下图所示(只截图了memory和keyspace部分):python
能够发现, info
命令只能看到总的内存大小以及key的数量等。这些对于分析到底哪些或哪类key占用的内存较大是远远不够的!mysql
工欲善其事必先利其器!git
在各类google搜索以后,发现有一个工具貌似是能够的: redis-rdb-tools 。github
因而分头行动,redis
根据该工具 , 能够将 rdb 快照文件转换为 csv 格式文件:sql
拿到csv文件后有两种作法,docker
pandas
库分块读取csv文件,能够作一些统计、过滤等操做(几乎有与等价于sql的api操做方式。(这里由于是操做的内部的业务数据,有些数据细节不便公开,仅贴出相关重要命令以及一些踩坑后的经验方法等)shell
# 1. 先运行一个python docker容器(注意将rdb文件挂载进去) docker run -it -v YOUR_PATH/xxx.rdb:/data/xxx.rdb python bash # 2. 安装rdb tools pip install rdbtools python-lzf # 3. 执行rdb 转为csv命令 (此过程根据rdb文件大小时间不定) rdb -c memory /data/xxx.rdb -f memory.csv
上述命令中有些路径和名称注意替换为你本身真实的值。数据库
话说这里也是个坑来着,在往 postgres
数据库导入csv数据时,报了一个大概意思是 “实际的列个数和期待的列个数不匹配”错误。 可能rdb tools在转换的时候某些行的值有点问题,或者其余bug致使。 这里鉴于有异常的数据条数很少,不用太过于深究,直接用 pandas
简单清洗一下便可。api
相关python代码以下:
import pandas as pd import numpy as np reader = pd.read_csv('/xxxx/memory.csv', iterator=True,error_bad_lines=False) loop = True chunkSize =10000000 chunks=[] total_bytes=0 while loop: try: chunk = reader.get_chunk(chunkSize) chunks.append(chunk) except StopIteration: loop = False print("Iteration is stopped.") df = pd.concat(chunks, ignore_index=True) df.to_csv('/xxx/memory2.csv', sep=',', encoding='utf-8')
大概解释下,这里先读取csv文件,指定选项 error_bad_lines=False
,则pandas会自动忽略有问题的行。接着用分块的方式读完全部内容,最后合并而后写到新文件。
此步骤其实理论上非必须的,上文说到其实能够直接用 pandas
操做csv几乎能够完成跟sql相似的分析效果。 但比较仍是直接用sql比较方便,仍是导到数据库来的实惠。
# 1. 运行postgres docker容器(记得把上面步骤中转换获得的csv文件挂载进去) docker run --name postgres -v /xxx/memory2.csv:/memory.csv -d postgres:9.6 # 2. 进入postgres容器内部 psql shell docker exec -it postgres psql -U postgres # 3. 建立临时表 (建议是全部字段是用text,不然导入可能会遇到转型错误,第一个字段index是pandas带进来的,能够导出csv时处理下) postgres=# create table keys_dump( index integer, database text, type text, key text, size_in_bytes text, encoding text, num_elements text, len_largest_element text, expiry text ); # 4. 执行导入csv文件命令 postgres=# COPY keys_dump FROM '/memory.csv' WITH csv;
如今问题会比较简单了,这里由于key中涉及到一些实际业务值,下面只是简单列举一下好比统计 string
类型的key占用的总内存大小:
select sum(size_in_bytes::int) from keys_dump where type='text';
诸如此类的sql,根据你的实际场景,好比按key中某关键词进行like查询:
select sum(size_in_bytes::int) from keys_dump where type='text' and key like 'xxxx%';
或者来个统计单key大小前10条:
select * from keys_dump order by size_in_bytes::int desc limit 10;
以上sql语句,我本身都试过,在单表3亿多的行数中执行,总时间大概10几到二十几秒左右,总体速度仍是让人能接受的,毕竟只是作下离线分析。
欢迎工做一到五年的Java工程师朋友们加入Java架构开发: 855835163 群内提供免费的Java架构学习资料(里面有高可用、高并发、高性能及分布式、Jvm性能调优、Spring源码,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多个知识点的架构资料)合理利用本身每一分每一秒的时间来学习提高本身,不要再用"没有时间“来掩饰本身思想上的懒惰!趁年轻,使劲拼,给将来的本身一个交代!