Redis缓存三兄弟


Date: 2023/9/29

本文目的是记录三种 redis 缓存出错的场景

  • 缓存击穿
  • 缓存穿透
  • 缓存雪崩

一 . 缓存穿透

定义:

如果用户请求一个数据库中永远不存在的数据,比如查询 id 为 0 或负数时,服务端会先查 redis,发现没有,就会去转发到数据库查询,数据库中一定不会查询到该数据(id 自增),但是也会对数据库造成压力,如果有人知道了请求路径,就可以通过大量请求这样的 id,可能会导致数据库崩溃。

解决方法:

如果 redis 中不存在,转发到数据库中查询,如果查询不到,就把需要查询的 id (id <= 0)作为 key,value 设为 NULL,存到 redis 中,这样再次有一样的请求,就会直接返回 redis 中对应的空值;

当然,这里的 key 需要设置一个过期时间,否则会造成内存压力过大。

二 . 缓存击穿

定义:

当一个 redis 中某个 key 刚好失效的瞬间,大量请求该数据的请求就会被转发到数据库进行查询,只要数据量够大,也会导致数据库压力大甚至崩溃。

还有一种想法是:这个 key 长时间处于高并发状态,这时如果 key 突然失效,就会导致上述结果。

解决方法

  1. 互斥锁
    给线程添加互斥锁,当前线程 1 如果查询 redis 缓存查询不到就会获取互斥锁,此时其他线程 2 的查询就会被堵塞,随后该线程 1 就进行查询数据库和缓存更新,更新完成后释放锁,线程 2 也可以查询到数据了。

    能保持 redis 和 mysql 的强一致性,但是性能差(阻塞其他线程)

  1. 逻辑过期

    高可用,性能优,但是不能保证数据强一致性


如图,线程 1 在查询时发现缓存过期后会先获取锁,然后新建一个子线程进行数据库查询缓存更新 等子线程完成后就释放锁,在得到锁的过程中其他线程如果要查询该缓存,发现过期后,也想进行更新,但是发现被锁了,就直接返回过期的缓存数据。只有当锁释放后,其他线程才能获得最新数据。

由此可见,不会阻塞其他线程的查询,所以效率高,但会导致查询的数据不一定是最新的,即非时效性。

缓存雪崩

定义:

当一段时间内 (同一时刻)有大量 key 同时失效,就会导致大量数据查询请求抓发到数据库进行查询,可能会导致数据库崩溃。

解决方法 :

  1. 给每个 key 设置不同的过期时间,防止大量 key 同时失效。

    如:给每个 key 的过期时间 TTL 加上一个随机值

  2. 搭建 Redis 集群,提高服务可用性 (涉及到[[集群模式]] 和[[哨兵]])

  • #todo 写 Redis 集群和哨兵
  1. 给缓存业务添加限流策略

    Spring cloud gateway 或 nginx 等

  2. 添加多级缓存

    一级缓存用 Caffeine 或 Guava


文章作者: KTpro
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 KTpro !
评论
  目录