1 什么是 Bigke
下面这两种情况,在很多互联网公司都被认为是 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 参数查找
代码语言:javascript复制redis-cli -p 6301 --bigkeys
图中可以看到 string 类型中最大的 key 为 aaa(实际可以看到每种数据结果的最大一个 key,只是我这个实例只有 string 类型的)。
在使用 --bigkeys 时,建议在从实例执行,因为其是通过 scan 完成的,如果在主实例运行,可能会影响业务查询。
3.2 debug object
使用 --bigkeys 只能获取到每种数据结构的 top1,但是有时我们需要获取到更多的 Bigkey,这时可以使用 scan debug object 扫描出所有的 Bigkey。
使用方法如下:
代码语言:javascript复制debug object key_name
比如:
其中 serializedlength 表示 key 的大小,单位为字节。
要注意的是,serializedlength 不代表真实的字节大小,它返回对象使用 RDB 编码序列化后的长度,值会偏小,当然也能通过这个数据排查出 Bigkey。
如果 key 类型为字符串,可以通过 strlen 来查看字节数:
分别计算每个 key 的 serializedlength,然后找到对应 Bigkey 进行相应的处理。
如果使用的 Redis 是 4.0 以上的版本,也可以使用 scan memory usage 进行判断,具体用法如下:
首先构造一个测试的 hash
代码语言:javascript复制hmset martin age 20 score 90 address shanghai
然后执行以下命令确定 key 的字节数
代码语言:javascript复制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 分析
代码语言:javascript复制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 搜索工具,其大致判断逻辑是:
- 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 上。