【Redis】Redis中大key怎么处理?

什么是 Redis 大 key?

大 key 并不是指 key 的值很大,而是 key 对应的 value 很大。

一般而言,下面的情况被称为大 key:

● 一个String类型的Key,它的值为5MB(数据过大);
● 一个List类型的Key,它的列表数量为20000个(列表数量过多);
● 一个ZSet类型的Key,它的成员数量为10000个(成员数量过多);
● 一个Hash格式的Key,它的成员数量虽然只有1000个但这些成员的value总大小为100MB(成员体积过大)

​ 有时候会因为业务人员使用不当,在 Redis 实例中形成了很大的对象,比如一个很大的 hash 或一个很大的zset,都是可能出现的。这样的对象给 Redis 的集群数据迁移带来了很大的问题,因为在集群环境下,如果某个 key 太大,会导致数据迁移卡顿。另外在内存分配上,如果一个 key 太大,那么当它需要扩容时,会一次性申请更大的一块内存,这也会导致卡顿。如果这个大 key 被删除,内存会被一次性回收,卡顿现象也会再次产生。

在平时的业务开发中,要尽量避免大 key 的产生.

​ 如果你观察到 Redis 的内存大起大落,这极有可能是因为大 key 导致的,这时候你就需要定位出具体是哪个 key,进一步定位出具体的业务来源,然后再改进相关业务代码设计。

为什么会出现大key?

  1. Redis数据结构使用不恰当:将Redis用在并不适合其能力的场景,造成Key的value过大,如使用String类型的Key存放大体积二进制文件型数据。
  2. 未及时清理垃圾数据:没有对无效数据进行定期清理,造成如HASH类型Key中的成员持续不断的增加。即一直往value塞数据,却没有删除机制,value只会越来越大。
  3. 对业务预估不准确:业务上线前规划设计考虑不足没有对Key中的成员进行合理的拆分,造成个别Key中的成员数量过多。
  4. 明星、网红的粉丝列表、某条热点新闻的评论列表:假设我们使用List数据结构保存某个明星/网红的粉丝,或者保存热点新闻的评论列表,因为粉丝数量巨大,热点新闻因为点击率、评论数会很多,这样List集合中存放的元素就会很多,可能导致value过大,进而产生大Key问题。

Redis中大key存在的问题

  • 内存占用:大key占用大量的内存资源,导致Redis的内存压力增加
  • 网络传输延迟:大key的读写操作可能会增加网络的传输延迟,影响性能
  • 持久化备份:大key的持久化备份需要更多的磁盘空间和时间

Redis中如何定位大key?

​ 为了避免给线上Redis 带来卡顿,就要用到 scan 指令,对于扫描出来的每一个key,使用type指令获得 key的类型,然后使用相应数据结构的size或者len方法来得到它的大小,对于每一种类型,将大小排名的前若干名作为扫描结果展示出来。
​ 上面这样的过程需要编写脚本,比较烦琐,不过 Redis 官方已经在redis-cli 指令中提供了这样的扫描功能,我们可以直接拿来使用。

redis-cli -h 127.0.0.1 -p6379 -a "password" -- bigkeys

如果你担心这个指令会大幅拾升 Redis的ops导致线上报警,还可以增加一个休眠参数。

redis-cli -h 127.0.0.1 -p6379 -a "password" -- bigkeys -i 0.1

上面这个指令每隔100条 scan 指令就会休眠0.1s,ops 就不会剧烈拾升,但是扫描的时间会变长。

使用的时候注意事项:

  • 最好选择在从节点上执行该命令。因为主节点上执行时,会阻塞主节点;
  • 如果没有从节点,那么可以选择在 Redis 实例业务压力的低峰阶段进行扫描查询,以免影响到实例的正常运行;或者可以使用 -i 参数控制扫描间隔,避免长时间扫描降低 Redis 实例的性能。

该方式的不足之处:

  • 这个方法只能返回每种类型中最大的那个 bigkey,无法得到大小排在前 N 位的 bigkey;
  • 对于集合类型来说,这个方法只统计集合元素个数的多少,而不是实际占用的内存量。但是,一个集合中的元素个数多,并不一定占用的内存就多。因为,有可能每个元素占用的内存很小,这样的话,即使元素个数有很多,总内存开销也不大;

如何删除大 key?

删除操作的本质是要释放键值对占用的内存空间,不要小瞧内存的释放过程。

释放内存只是第一步,为了更加高效地管理内存空间,在应用程序释放内存时,操作系统需要把释放掉的内存块插入一个空闲内存块的链表,以便后续进行管理和再分配。这个过程本身需要一定时间,而且会阻塞当前释放内存的应用程序。

所以,如果一下子释放了大量内存,空闲内存块链表操作时间就会增加,相应地就会造成 Redis 主线程的阻塞,如果主线程发生了阻塞,其他所有请求可能都会超时,超时越来越多,会造成 Redis 连接耗尽,产生各种异常。

因此,删除大 key这一个动作,我们要小心。具体要怎么做呢?这里给出两种方法:

  • 分批次删除
  • 异步删除(Redis 4.0版本以上)

如何解决Redis中大key存在的问题

  1. 把大key分成多个小key来存储:比如把一个大的Hash结构分割成多个小的Hash结构,每个小的Hash结构代表一部分数据,这样可以减小单个key的大小,去降低内存的压力。
  2. 搭建Redis Cluster集群,把key分配到不同的hash slot槽所在的分片上:这样可以降低单个Redis节点的存储压力
  3. 如果已经存在了大key,可以做数据的拆分和迁移:按照业务需求和规则把大key拆分成多个小key,并分布到不同的Redis实例上,在迁移完成之后,清除掉不需要使用的大key。
  4. 可以考虑使用压缩算法进行压缩,去减少存储空间的占用:在存储数据之前对数据进行压缩,在读取的时候进行解压缩,以节省存储空间和减少网络传输的数据量。
  5. 从业务层面进行分析,了解大key产生的原因,并根据需求和访问模式进行相应的优化:比如使用更合适的数据结构,优化业务逻辑的设计方法等等。

你可能感兴趣的:(Redis,缓存,redis,数据库,缓存)