Redis 中的 Big Key 问题是什么?如何解决?

Sherwin.Wei Lv7

Redis 中的 Big Key 问题是什么?如何解决?

回答重点

Redis 中的 “big Key” 是指一个内存空间占用比较大的键(Key),它有什么危害呢?

  • 内存分布不均。在集群模式下,不同 slot 分配到不同实例中,如果大 key 都映射到一个实例,则分布不均,查询效率也会受到影响。
  • 由于 Redis 单线程执行命令,操作大 Key 时耗时较长,从而导致 Redis 出现其它命令阻塞的问题。
  • 大 Key 对资源的占用巨大,在你进行网络 I/O 传输的时候,导致你获取过程中产生的网络流量较大,从而产生网络传输时间延长甚至网络传输发现阻塞的现象,例如一个 key 2MB,请求个 1000 次 2000 MB。
  • 客户端超时。因为操作大 Key 时耗时较长,可能导致客户端等待超时。

如何解决 big key问题?

可以从以下几个方向进行入手:

开发方面

  • 对要存储的数据进行压缩,压缩之后再进行存储
  • 大化小,即把大对象拆分成小对象,即将一个大 Key 拆分成若干个小 Key,降低单个 Key 的内存大小
  • 使用合适的数据结构进行存储,比如一些用 String 存储的场景,可以考虑使用 Hash、Set 等结构进行优化

业务层面

  • 可以根据实际情况,调整存储策略,只存一些必要的数据。比如用户的不常用信息(地址等)不存储,仅存储用户 ID、姓名、头像等。
  • 优化业务逻辑,从根源上避免大 Key 的产生。比如一些可以不展示的信息,直接移除等。

数据分布方面

  • 采用 Redis 集群方式进行 Redis 的部署,然后将大 Key 拆分散落到不同的服务器上面,加快响应速度

扩展知识

怎样算 big key ?

大 Key 可能出现在不同的场景中,不过其本质都是相同的,就是对应的值其所占内存非常大,例如:

1)大型字符串

1
set key "面试鸭xxxxxx······(此处省略无数个字符)"

2)大型哈希表

1
HMSET student:8927 name "yupi" nickname "面试鸭" 

这个时候就可能有同学会问了,到底占用多少内存才算得上是 big key 呢?

其实这个没有一个很绝对的说法,主要还是取决于具体的场景以及应用需求。参考阿里云redis文档:

image.png

当然,这些标准并不是绝对的,具体的情况还是需要根据应用场景和实际情况来进行调整,这个需要你和面试官说明清楚。

使用 bigkeys 命令查询 bigkeys

这个是 Redis 内置的指令,直接在 Redis 的客户端 redis-cli 中就可以调用使用,该命令可以获取 Redis 的整体信息,并且显示每种类型数据中最大的 Key。

如下所示,在命令行终端输入 redis-cli --bigkeys 便可以查看到(docker 版本的话可能会出现查找失败的情况)。

Snipaste_2024-05-09_15-03-43.jpg

这种方法有优点,就是其是 Redis 内置的,其统计非常方便。

它的原理就是在 Redis 内部执行 scan 命令,遍历整个实例所有的 key,针对 key 的类型执行 strlen、hlen、scard 等命令获取字符串长度或集合的元素个数。

所以在线上执行这个命令的需要,需要关注性能问题,可以通过 -i 命令控制扫描的休息间隔,时间单位是秒。

还有一点,元素多不一定代表占用的内存多,需要实际评估下。

Comments