Redis 缓存问题

Redis 缓存问题

缓存穿透

问题描述

缓存穿透指:

当请求传递到后端服务器时,会先查询Redis 缓存中是否存在该 key 值,不存在,则会请求db 去查询。

当发生程序被攻击时,出现大量空值的key 会去请求,以拖垮服务器查询,导致程序崩溃。

解决方法

  1. 缓存空值
  2. 布隆过滤器(key 校验)

缓存空值

将数据库中查询为空的key 也存储在缓存中,当再次查询时,则可以避免查询数据库。

缓存空值会出现两个问题:

  1. 空值缓存,会占用更多空间,需要设置较短的过期时间。(若是攻击,会很麻烦)
  2. 缓存和存储的数据会有一段时间不一致,有业务影响。

布隆过滤器

原理
  1. 利用 k 个哈希函数,对元素进行计算

  2. 根据哈希值,将位数据组对应的下标置为1

  3. 当需要查询时,重复过程 1,若查询对应位数据下标不全为1,则不存在,全为1,则存在

优点:

数据空间小,不用存储数据本身

缺点:

  • 元素可以添加到集合中,不能删除
  • 匹配结果是“绝对不在集合中”,并不能保证匹配成功的值已经在集合中
  • 当集合快满时,即接近预估最大容量时,误报的概率会变大
  • 数据占用空间放大

缓存击穿

问题描述

单个热点key 的缓存数据,****刚好过了有效时间,此时大量请求涌入,会导致数据查询流量大增,数据库可能崩溃。

解决方法

  1. 互斥锁
  2. 热点数据永不过期

互斥锁

当第一个数据库查询请求发起后,就将缓存中该数据上锁;

此时其他查询该缓存的请求,被阻塞等待;

当第一个请求完成,然后更新缓存,释放锁;

其他查询请求后续可以查询到。

注意:互斥锁可以避免某一个热点,但实际情况里往往是一批。

将缓存的过期时间,设置为随机值,会降低这一概率。

热点数据永不过期

从缓存层面,确实没有设置过期时间,也就是物理不过期

从功能层面,每一个value 都有对应逻辑时间,过期后,单独重新构建。

注意:在重新构建期间,可能会出现数据不一致的情况。

比较

  • 互斥锁
    • 存在死锁和阻塞风险
    • 较好的降低后端负载,一致性比较好
  • 永远不过期
    • 数据不一致情况
    • 代码复杂度会增大

缓存雪崩

问题描述

指缓存中大量的数据同时过期,导致大量请求在短时间内直接到达数据库,对数据库造成巨大压力。

解决方法

  1. 过期时间分散
  2. 缓存预热
  3. 限流降级

过期时间分撒

使用 expire 命令设置过期时间,引入随机过期时间机制

缓存预热

使用 CacheWarmer 等工具在系统启动前预热缓存

限流降级

使用限流算法控制访问数据库的请求速率,当缓存失效导致请求过多时,进行降级处理。

工具:HystrixSentinel

参考文章

硬核 | Redis 布隆(Bloom Filter)过滤器原理与实战 - 知乎 (zhihu.com)