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,我们常规有三种解决方案。一是压缩,而是切片,三是直接抛弃不缓存。

都看到这了,给个赞吧

都看到这了,给个赞吧

都看到这了,给个赞吧

相关推荐
卑微的小鬼3 分钟前
Go 语言结合 Redis 实现固定窗口、滑动窗口、令牌桶和漏桶限流算法的示例代码
开发语言·redis·golang
handsomestWei16 分钟前
java实现多图合成mp4和视频附件下载
java·开发语言·音视频·wutool·图片合成视频·视频附件下载
全栈若城27 分钟前
03 Python字符串与基础操作详解
java·开发语言·python
伯牙碎琴38 分钟前
二、Spring Framework基础:IoC(控制反转)和DI(依赖注入)
java·spring·log4j
菲力蒲LY40 分钟前
输入搜索、分组展示选项、下拉选取,全局跳转页,el-select 实现 —— 后端数据处理代码,抛砖引玉展思路
java·前端·mybatis
南宫生1 小时前
力扣每日一题【算法学习day.130】
java·学习·算法·leetcode
!!!5251 小时前
Java实现斗地主-做牌以及对牌排序
java·算法
我要最优解1 小时前
关于在mac中配置Java系统环境变量
java·flutter·macos
二十七剑1 小时前
jvm调试和查看工具
java·linux·jvm
过客猫20221 小时前
使用 deepseek实现 go语言,读取文本文件的功能,要求支持 ascii,utf-8 等多种格式自适应
开发语言·后端·golang