1 什么是 Bigkey
下面这两种情况,在很多互联网公司都被认为是 Bigkey:
字符串类型:一般认为超过 10 KB 就是 Bigkey
非字符串类型:哈希、列表、集合、有序集合,体现在元素个数过多,比如超过 5000 个。
2 Bigkey 的危害
Bigkey 存在很多危害,具体体现在以这些方面:
内存空间不均匀:比如在 Redis cluster 或者 codis 中,会造成节点的内存使用不均匀。
阻塞:因为 Redis 单线程特性,如果操作某个 Bigkey 耗时比较久,则后面的请求会被阻塞。
过期时可能阻塞:如果 Bigkey 设置了过期时间,当过期后,这个 key 会被删除,假如没有使用 Redis 4.0 的过期异步删除,就会存在阻塞 Redis 的可能性,并且慢查询中查不到(因为这个删除是内部循环事件)。
3 怎么发现 Bigkey
那么怎么知道某个实例中是否有 Bigkey 呢?这里介绍几个常见的用法:
3.1 自带的 Bigkeys 参数查找
redis-cli -p 6301 --bigkeys
图中可以看到 string 类型中最大的 key 为 aaa(实际可以看到每种数据结果的最大一个 key,只是我这个实例只有 string 类型的)。
在使用 --bigkeys 时,建议在从实例执行,因为其是通过 scan 完成的,如果在主实例运行,可能会影响业务查询。
3.2 debug object
使用 --bigkeys 只能获取到每种数据结构的 top1,但是有时我们需要获取到更多的 Bigkey,这时可以使用 scan+debug object 扫描出所有的 Bigkey。
使用方法如下:
debug object key_name
比如:
其中 serializedlength 表示 key 的大小,单位为字节。
要注意的是,serializedlength 不代表真实的字节大小,它返回对象使用 RDB 编码序列化后的长度,值会偏小,当然也能通过这个数据排查出 Bigkey。
如果 key 类型为字符串,可以通过 strlen 来查看字节数:
分别计算每个 key 的 serializedlength,然后找到对应 Bigkey 进行相应的处理。
如果使用的 Redis 是 4.0 以上的版本,也可以使用 scan +memory usage 进行判断,具体用法如下:
首先构造一个测试的 hash
hmset martin age 20 score 90 address shanghai
然后执行以下命令确定 key 的字节数
memory usage martin
3.3 通过 rdbtools 分析 rdb
获取生产 Redis 的 rdb 文件,通过 rdbtools 分析 rdb 生成 csv 文件,再导入 MySQL 或其他数据库中进行分析统计,根据 size_in_bytes 统计 Bigkey。
安装 redis-rdb-tools,参考 GitHub(https://github.com/sripathikrishnan/redis-rdb-tools)。
进行 RDB 分析
rdb -c memory dump.rdb >1.csv
分析结果形式如下:
如果需要弄 Bigkey 自动分析平台,可以把 RDB 文件传输到某台机器上,然后在这台机器上执行定时任务分析 RDB 获取 csv 文件,然后通过脚本把 csv 文件导入数据库,然后再通过前端页面展示出 Bigkey 结果。
3.4 通过脚本扫描
通过 Python 脚本,迭代 scan key,每次 scan 1000,对扫描出来的 key 进行类型判断,然后不同类型的 key 通过不同的方法筛选出 Bigkey
比如阿里云 Redis 大 key 搜索工具(https://yq.aliyun.com/articles/117042),其大致判断逻辑是:
string 类型:通过 strlen 命令判断存储的字符串长度,如果大于 10240,则认为是 Bigkey。
hash 类型:通过 hlen 命令判断域的数量,如果大于 10240,则认为是 Bigkey。
list 类型:通过 llen 命令判断 list 类型 key 的列表长度,如果大于 10240,则认为是 Bigkey。
set 类型:通过 scard 命令判断集合中元素的数量,如果大于 10240,则认为是 Bigkey。
zset 类型:通过 zcard 命令判断有序集合中元素的数量,如果大于 10240,则认为是 Bigkey。
3.5 其他第三方工具
例如:redis-rdb-cli
地址:https://github.com/leonchen83/redis-rdb-cli
4 优化 Bigkey
找到 Bigkey 后,怎么优化呢?
这里介绍几种常见的优化方式:
4.1 删除 Bigkey
有些 Bigkey 业务不需要使用了,因此可以考虑删除掉。但是要注意的是:如果直接 del,可能会阻塞 Redis 服务。大致有下面几种处理办法:
如果 key 类型为 string,则直接删除;
如果 key 类型为 hash、list、set、sorted set,使用 hscan 命令,每次获取部分(例如100个)field-value,再利用 hdel 删除每个 field;
Redis 在4.0 版本支持 lazy delete free 的模式,删除 Bigkey 不会阻塞 Redis。
4.2 控制大小
处理 Bigkey 的另外一种方法就是控制大小,比如 string 减少字符串长度,list、hash、set、zset 等减少成员数。
4.3 拆分 Bigkey
有时也可以考虑对 Bigkey 进行拆分,具体方法如下:
对于 string 类型的 Bigkey,可以考虑拆分成多个 key-value。
对于 hash 或者 list 类型,可以考虑拆分成多个 hash 或者 list。
4.4 更换数据库
其实有些场景下,使用 Redis 并不是最优的选择,比如长文本,如果放在 Redis 中,很可能就是一个 Bigkey,因此建议不要存入 Redis,用文档型数据库 MongoDB 代替或者直接缓存到 CDN 上。
欢迎加入 Redis 交流社群
群内不定期邀请一些身边的 Redis 大牛
交流分享,解答工作中遇到的的问题
分享工作经验、(微yzlkf09)面试技巧等!
也欢迎各位大牛投稿,内容可以是数据库、开发、运维、产品、运营等!
悦专栏 LIKECOLUMN
在这里,学好编程
做更优秀的 IT人!