Redis 大 key 问题一文通

2023年 8月 9日 32.5k 0

1. 背景

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

2. 大 key 会带来什么问题

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

3. 什么才叫大 key

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

  • value > 10kb,即认定为大 key
  • 像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。
    image.png
    我们以 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 正常的运作。

    image.png

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

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

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

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

    8. 总结

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

    都看到这了,给个赞吧

    都看到这了,给个赞吧

    都看到这了,给个赞吧

    相关文章

    JavaScript2024新功能:Object.groupBy、正则表达式v标志
    PHP trim 函数对多字节字符的使用和限制
    新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
    使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
    为React 19做准备:WordPress 6.6用户指南
    如何删除WordPress中的所有评论

    发布评论