Bigkeys

redis 的 client 自带查询工具:

> redis-cli -h 127.0.0.1 -p 6379 --bigkeys
# Scanning the entire keyspace to find biggest keys as well as
# average sizes per key type.  You can use -i 0.1 to sleep 0.1 sec
# per 100 SCAN commands (not usually needed).

[00.00%] Biggest hash   found so far 'kkkkk' with 1 fields
[00.00%] Biggest zset   found so far 'kkkkk2' with 1 members
[00.00%] Biggest string found so far 'kkkkk3' with 32 bytes
[00.00%] Biggest zset   found so far 'kkkkk4' with 6 members
[00.00%] Biggest string found so far 'kkkk5' with 36 bytes
....
[91.84%] Sampled 15000000 keys so far

-------- summary -------                       

Sampled 15605882 keys in the keyspace!
Total key length in bytes is 901211637 (avg len 57.75)

Biggest string found 'kkkkk1' has 71 bytes
Biggest    set found 'kkkkk2' has 102 members
Biggest   hash found 'kkkkk3' has 2180 fields
Biggest   zset found 'kkkkk4' has 100 members

9123995 strings with 297944906 bytes (58.47% of keys, avg size 32.66)
0 lists with 0 items (00.00% of keys, avg size 0.00)
246278 sets with 486939 members (01.58% of keys, avg size 1.98)
3020198 hashs with 4100860 fields (19.35% of keys, avg size 1.36)
3215411 zsets with 7321740 members (20.60% of keys, avg size 2.28)

不过这个除了 String 类型的 key 外,只能看出来一个数据结构下有多少数据,看不出来到底占多少内存,看着数值大的并不一定有问题,也不一定占用空间很大,所以这个工具只能用来做大致分析。

具体方式可以参看:redis-cli, the Redis command line interface – Redis

有意思的地方在于,--bigkeys 是通过 SCAN 命令运行的,对性能影响不大,并且可以通过 -i 0.1 等来减慢它的速度,更加减小影响。

redis-cli 有很多有用的参数,值得一看。比如分析问题的时候还可以用 --stat每秒输出一组关键统计信息:

> redis-cli -h 127.0.0.1 -p 6379 --stat                                  
------- data ------ --------------------- load -------------------- - child -                                                                
keys       mem      clients blocked requests            connections                                                            
13237148   4.45G    2       0       74967596566 (+0)    13652059                                                                
13237182   4.45G    2       0       74967598307 (+1741) 13652059    SAVE                                      
13237230   4.45G    2       0       74967600072 (+1765) 13652059    SAVE                                 
13237210   4.45G    2       0       74967601651 (+1579) 13652059    SAVE                                                   
13237189   4.45G    2       0       74967603472 (+1821) 13652059    SAVE                                                        
13237261   4.45G    2       0       74967605204 (+1732) 13652059    SAVE      

debug object

在这里有提这个东西:https://redis.io/commands/debug-object。

> redis-cli -h 127.0.0.1 -p 6379
127.0.0.1:6379> debug OBJECT some-key1
Value at:0x7f0795641ff0 refcount:1 encoding:raw serializedlength:33 lru:5539512 lru_seconds_idle:31594

返回结果中,serializedlength 是对应 key 序列化到磁盘后占用磁盘空间的大小。这个命令的问题在于,redis 不推荐使用这个命令,再有这里得到的大小是序列化到磁盘上的大小,和在内存中的大小并不一致。只能在怀疑有 key 过大时候执行一下看看。最好还需要注意因为牵扯到数据序列化,如果被查看的 key 是个比较大的数据结构,序列化过程可能比较慢,如果查看的 key 特别多可能会影响性能。

以 redis 4.0.11 为例,看上去计算地方在这里:redis/debug.c at 4.0.11 · antirez/redis · GitHub。可以参考。

Redis RDB tools

工具在这里:https://github.com/sripathikrishnan/redis-rdb-tools

工具用来分析 Redis 的 RDB 文件,生成内存报告,把所有 key 转换为 JSON,转存别的 DB 等。

1 先用 redis-cli 工具连上 Redis 执行 bgsave

一般来说在 Slave 上做这个操作要安全一些。并且如果 Redis 的 config 文件中配置了 save,那 Redis 会定期执行 bgsave 这种情况下一般就不用手工执行 bgsave 了,可以直接去 config 文件中配置的 dir 目录下找 dbfilename 配置的后缀为 .rdb 的文件。该文件为 redis 的持久化文件。redis rdb tools 就是用来分析这个文件的。

2 下载 .rdb 文件到本地,或者到装有 redis rdb tools 的机器上;

3 执行 rdb -c memory xxx.rdb -f output_memory.csv 解析下载的 rdb 文件并生成 csv 格式的 memory report;

生成出来的 .csv 文件 header 为:database,type,key,size_in_bytes,encoding, num_elements,len_largest_element,expiry。含义就如其字面意思,唯一 num_elements 和 len_largest_element 可能不好理解。num_elements 是如果是集合类型,则其表示是内部数量,比如 zset 就是里面有多少个 value 等,如果是 String 则是 String 长度。len_largest_element 是 value 内最大成员所占字节数。比如 zset 就是找到占内存最大的那个 member 的大小,如果是 String 的话则是 String 的大小。

rdb tools 比较厉害的地方在于,它虽然分析的是 RDB 文件,是数据在磁盘的格式,但会自动估算数据在内存中时占用内存大小,总体上得到的数值是比较接近数据在 Redis 实际值的。Redis 内存占用上比 rdb tools 分析出来的还多一部分是 client buffer,pubsub 占用的内存等。rdb tools 有个 FAQ 值得一看:FAQs · sripathikrishnan/redis-rdb-tools Wiki · GitHub

4 分析导出的 memory report;

有了导出的这个 .csv 后通过基本的 awk, grep 就能完成分析,一般来说几百万上千万的 key 分析起来也不会太慢。

还可以用 sqlite

> 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), expiry datetime);
sqlite> .mode csv memory
sqlite> .import output_memory.csv memory

一般 csv 默认的 seperator 就是 ,,如果有问题可以通过 .seperator , 来修改。

后续就可以使用 SQL 开始查询了。expiry 是过期时间,可以用比如 expiry < '2020-03-05T14:32:36' 这种比大小的方式来查询。

常用 SQL:

查询有多少 key

select count(*) from memory;

查询所有 key 的总大小

select sum(size_in_bytes) from memory;

查询占空间最大的 10 个 key

select key,size_in_bytes from memory order by size_in_bytes desc limit 10;

5 探索 redis rdb tools

事实上 rdb tools 自己就能直接分析 rdb 文件给出比如占空间最大的 key 是哪些,如 rdb -c memory -l 10 xxx.rdb 但是执行起来特别慢,如果要反复查询分析的话还是用 sqlite 比较方便。

再有 rdb tools 导出 memory report 的时候可以带着 --bytes 参数,即只导出大小查过某个值的 key,从而能减少导出的数据量,加快查询速度。

参考

Redis内存分析方法 - 我是一条最咸的咸鱼 - 博客园