Redis 中的 Big Key 问题是什么?如何解决?
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文档:
当然,这些标准并不是绝对的,具体的情况还是需要根据应用场景和实际情况来进行调整,这个需要你和面试官说明清楚。
使用 bigkeys 命令查询 bigkeys
这个是 Redis 内置的指令,直接在 Redis 的客户端 redis-cli 中就可以调用使用,该命令可以获取 Redis 的整体信息,并且显示每种类型数据中最大的 Key。
如下所示,在命令行终端输入 redis-cli --bigkeys 便可以查看到(docker 版本的话可能会出现查找失败的情况)。
这种方法有优点,就是其是 Redis 内置的,其统计非常方便。
它的原理就是在 Redis 内部执行 scan 命令,遍历整个实例所有的 key,针对 key 的类型执行 strlen、hlen、scard 等命令获取字符串长度或集合的元素个数。
所以在线上执行这个命令的需要,需要关注性能问题,可以通过 -i 命令控制扫描的休息间隔,时间单位是秒。
还有一点,元素多不一定代表占用的内存多,需要实际评估下。
Comments