【重难点】【Redis 03】缓存雪崩、缓存穿透、缓存击穿、Redis 的内存过期策略、并发读写和双写
一、缓存雪崩
缓存雪崩指的是在同一时刻 Redis 中大量的键值对都到了设置的失效时间,并且同时有大量的请求涌入,这个时候由于 Redis 中没有相应的键值对来完成这些请求,这些请求就会发给数据库,而数据库无法抗住这么大量的请求就直接崩溃了,即使重新启动数据库,还是会有大量新的请求,导致数据库又再次崩溃
如何处理?
- 批量向 Redis 存储据的时候,给每个键值对的失效时间都加一个随机值
- 为热点数据设置永不过期
二、缓存穿透
缓存穿透指的是同一时刻有大量的请求查询缓存和数据库中都没有的数据,比如 id 值为 -1 的数据。这种大量的请求会绕过数据库,直接请求数据库,由于数据库也没有这些数据,也就无法写入缓存,这样就会造成数据库压力过大,甚至崩溃
如何处理?
- 增加请求参数校验
- 如果缓存和数据库都没有这个键,可以暂时将值设置为 null
- 限制单个 IP 每秒的最大访问次数
- 使用布隆过滤器,可以高效地判断出数据库中是否有这个数据
布隆过滤器的原理
布隆过滤器实际上就是一个二进制数组,通过多个哈希函数计算数据库中数据的哈希值,并映射到数组中,也就是把对应索引位的 0 改为 1,表示数据存在。比如数据库中有 “hello” 这个数据,我们计算出它的哈希值映射为 3、5、7,那么查询的时候,必须 3、5、7 这三个索引对应的值都是 1 才能证明这个数据存在
多个哈希函数是为了防止哈希冲突
三、缓存击穿
缓存击穿指的是某一个键扛着大量的请求,在这个键失效的瞬间,大量的请求击穿缓存直接查询数据库,造成数据库压力过大,严重时会导致数据库崩溃
如何处理?
- 设置热点数据永不过期
- 设置互斥锁,缓存失效时,查询数据库并重新存入缓存,期间利用互斥锁阻塞后续的大量请求
四、Redis 的内存过期策略
- 定期删除,每隔一段时间抽取部分设置了过期时间的键检查是否过期
- 惰性删除,当查询到键的时候才检查是否过期,过期了则不返回
- 当内存不足时,使用最近最少使用算法淘汰键
五、并发读写和双写
如何处理并发读写带来的顺序不一致问题?
某个时刻,多个系统实例都去操作同一个键,比如下单、支付、减库存。这种情况可以基于 Zookeeper 实现分布式锁,每个系统实例都通过 Zookeeper 获取分布式锁,确保同一时间,只能有一个系统实例在操作同一个键,并且 Zookeeper 也可以确保各系统实例获取锁的顺序
如何处理缓存与数据库的双写问题?
- 读的时候,先读缓存,缓存没有再读数据库,并把数据放入缓存中,然后返回响应
- 更新的时候,先更新数据库,再删除缓存