缓存穿透-击穿-雪崩

1. 背景

添加缓存的目的一般都是为了减轻数据库的读写压力,同时提升服务性能。这涉及到项目中实际的开发经验,即数据库的读写速度往往会是项目瓶颈。

操作系统中:cpu运行速度>缓存读写速度>硬盘读写速度,增加缓存、读写分离等方法都是用来优化数据库读写耗时。

2. 缓存穿透

2.1 需求

用户需要查询数据库中某一项信息,优先去缓存中查询
2.1.1 如果缓存中保存了信息,则在缓存中命中需要的信息,直接返回,不进行后续的查询数据库操作。

2.1.2 如果缓存中查询信息失败,则从数据库中查询数据,如果查询到了,则将数据放入缓存(会涉及设置失效时间,查询频率等操作),并返回信息。

2.1.3 如果数据库也查询失败,则直接返回查询失败提醒。

分析流程2.1.1、2.1.2、2.1.3,假设存在如下场景,有人恶意伪造大量数据库中不存在的id请求,大量涌入服务器,则此时流程2.1.1因为缓存没有数据会被跳过,流程2.1.2也因为没有缓存没有数据会被跳过,流程2.1.3会对每次请求都检索一遍数据库表。可以把这个时候缓存都被跳过的现象成为缓存穿透,因为能加速服务器性能的缓存都被跳过,每次都是在硬盘上读写遍历,这必然造成系统性能下降。

2.2 解决办法

2.2.1 参数校验

参数校验,拦截掉不必要发出请求的某些恶意id,例如被北京ip发送的id范围是在01XXX和03XXX之间,则拦截其他数字开头的id.

2.2.2 布隆过滤器

数据库数据量不是过大时,可将所有数据提前存储到内存,在这种场景下,使用布隆过滤器减少数据加载到缓存时候,内存使用量。布隆过滤器特点缓存查询得到的数据库不一定存在;但缓存查询不到数据库一定不存在

同时由于缓存中的数据需要及时和数据库进行同步更新。否则数据库新添加的信息,因为缓存中不存在,布隆过滤器会拦截掉这些新增的正常请求。这在一些业务场景是无法接受的,但在对这种情况可以接受的业务场景前提下,布隆过滤器虽然会有少量缓存不存在的请求发送给数据库,但更多的是会避免掉很多数据不存在的数据库访问。

2.2.3 缓存空值

受限于应用场景,布隆过滤器使用并不多,而是采用缓存空值方案。核心思想为,无论数据库中是否查询得到数据,都将数据放入缓存,数据存在时,请求id对应值为该真实数据;数据不存在时,请求id对应值为空值。

3. 缓存击穿

3.1 需求

假设在每年轰轰烈烈的春节火车票抢票中,某一列车次在春节一个月内对应的那个key在缓存中过期失效了,涉及一百万人,每个人都疯狂点抢票,这个时候缓存失效,数据库接受大量请求,可能造成死机或者物理机温度过高直接宕机。

3.2 调整key有效时间

  • 直接延长缓存时间,
  • 有接收到了对于key的查询,就重置key有效期
  • 某些长期热点展示数据设置永久有效,由运维人员根据时间业务等情况,手动调整数据从数据库上载或卸载到缓存。

3.3 请求加锁

同一时刻,只有一个请求拥有访问数据库的锁,即加锁实现限流。基于lock接口或sychronized关键字

4. 缓存雪崩

4.1 需求

缓存中的多个key同时失效(恰好过期时间都是在一个时刻)或者缓存服务器物理机宕机失效,都会造成缓存雪崩,同一时刻大量请求涌入数据库。

4.2 过期时间避免统一

多个key都在某一时刻同时过期,因此可以在设定的过期时间基础上,添加一定范围(例如3600秒)随机数时间,避免高并发时,出现key同时失效。

4.3 架构设计

物理机宕机,可在设计阶段设计主从缓存服务器,slaves缓存服务器及时同步master缓存服务器中的信息,一旦master挂了,salves们竞争上岗,其中某一个slave将承担master的缓存任务。(redis哨兵模式)


缓存穿透-击穿-雪崩
http://oowatermelon.github.io/OoWaterMelonS/2022/12/16/缓存穿透-击穿-雪崩/
作者
OoWaterMelonS Shao
发布于
2022年12月16日
许可协议