Redis 运维实战 第06期:Bigkey

2022-04-25 08:30:14 浏览数 (1)

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 上。

0 人点赞