Redis 大 key 问题一文通

1. 背景

最近对接了一个卧龙同事的接口,因为接口比较慢,所以打算对第三方接口加个缓存。但是会有大 key 的问题。设计过程中调研了一些解决方案,这里总结下。 关键字:Redis;大Key问题;

2. 大 key 会带来什么问题

我们都知道,redis 是单线程架构,日常的读写操作都是由一个线程完成。一旦某一个线程执行了大 key 的读写,就会影响之后所有命令的执行,进而影响 redis 实例甚至整个 redis 集群的稳定。

3. 什么才叫大 key

那么什么才叫大 key?普遍认同的规范是:

  1. value > 10kb,即认定为大 key
  2. 像list,set,hash 等容器类型的 redis key,元素数量 > 5000,即认定为大 key

现在我们知道了大 key 会来带什么问题,也知道了什么样的 key 才算大key。接下来我们看看都有哪些解决方案。

4. 解决方案一:压缩

适用于字符串类型的 redis key。采用压缩算法,将 key 压缩至可接受的范围内。压缩也是有讲究的,首先要选择无损的压缩算法,然后在压缩速率和压缩率之间也要权衡。比较常用的压缩算法/工具如下:

  • google snappy:无损压缩,追求压缩速度而不是压缩率(Compression rate)
  • message pack:无损压缩,仅适用于 json 字符串的压缩,可以得到一个更小的 JSON,官网是:msgpack.org/

5. 解决方案二:value 切片

适用于 list,set,hash 等容器类型的 redis key。规范要求容器的元素数量 < 5000,我们可以在写 redis 的时候做个逻辑,如果超过了 5000 的容器就做切片。

举个例子,现在有一个 list 类型的缓存 ,他包含 12000 个元素。是很典型的大key。 我们以 5000 为阈值,把 list 切分成三份:user_list_slice_1、user_list_slice_2、user_list_slice_3,另外还需要一个存储切片具体情况的key,所以还需要一个 user_list_ctl。 业务程序后续访问这个缓存的时候,先请求 user_list_ctl,解析出缓存的切分情况,再去请求具体的切片即可。

6. 解决方案三:抛弃大 key(discard)

大多数场景,我们是把 redis 当缓存用,缓存失效了就走数据库查出数据。我们可以设定一个阈值,如果缓存对象特别大的话,我们就抛弃这个key,不缓存,直接走数据库。这样不会影响 redis 正常的运作。

当然,这是个取巧的方案,灵感是来自线程池的拒绝策略(DiscardPolicy)。采用这个方案得确认直接抛弃不会影响业务,还需要确保不走缓存后的性能业务上能够接受。

7. 俯瞰一下,从架构的角度解决这个问题

千叮咛万嘱咐,大 key 问题造成的线上事故仍然没有断过,这个怎么解决? 我觉得有如下几个思路

  • 完善监控机制,有大 key 出现就及时告警
  • 封禁/限流能力,能够及时封禁大 key 的访问,降低业务影响(保命用)
  • 在服务和 redis 集群之间建设 proxy 层,在 proxy 做大 key 的处理(压缩或者切片处理),让业务开发无需感知大key。

8. 总结

总结一下,解决 redis 的大 key,我们常规有三种解决方案。一是压缩,而是切片,三是直接抛弃不缓存。

都看到这了,给个赞吧

都看到这了,给个赞吧

都看到这了,给个赞吧

相关推荐
dualven_in_csdn1 小时前
搞了两天的win7批处理脚本问题
java·linux·前端
你的人类朋友2 小时前
✍️【Node.js程序员】的数据库【索引优化】指南
前端·javascript·后端
C++chaofan3 小时前
74. 搜索二维矩阵
java·算法·leetcode·矩阵
诺浅4 小时前
AWS S3 SDK FOR JAVA 基本使用及如何兼容七牛云
java·spring boot·aws
卜及中4 小时前
【Redis/1-前置知识】分布式系统概论:架构、数据库与微服务
数据库·redis·架构
迢迢星万里灬4 小时前
Java求职者面试:微服务技术与源码原理深度解析
java·spring cloud·微服务·dubbo·netty·分布式系统
KIDAKN5 小时前
java--怎么定义枚举类
java·开发语言
何中应5 小时前
第一个人工智能(AI)问答Demo
java·人工智能·语言模型
东阳马生架构5 小时前
商品中心—3.商品可采可补可售的技术文档
java