使用缓存通常的操作时先访问缓存数据,如果缓存中不存在的话,就会回源到数据库中然后将数据写入到缓存中。如果存在就直接返回数据,从整个过程来看,缓存层就处于数据库的前置环节,分担了数据库在高并发容易出现故障的风险,所以在使用过程中需要对缓存层很谨慎的进行分析。在访问缓存数据时,有常见的三大场景:缓存穿透、缓存击穿以及缓存雪崩
1.1、缓存穿透
现象:每次请求直接穿过缓存层,直接会员到数据库中,给数据库带来了巨大的压力,严重甚至会导致宕机,出现严重的生产事故
原因:访问数据会先访问缓存,如果数据不存在缓存中才会查询数据库,但是如果查询数据也查询不出来数据,也就是说当前访问数据永远不会写入缓存中,这样就导致了访问一定不存在的数据,就相当于缓存层形同虚设,每次请求都会到DB,造成数据库压力过大
解决方案:
- 1、如果DB 查询不到数据,保存空对象到缓存层,设置较短的失效时间
- 2、针对业务场景对参数进行有效性效验,防止非法请求击垮DB
- 3、采用布隆过滤器,这种过滤器可以过滤掉大部分不存在的数据,防止这些数据请求到DB。(这种方法我也不太了解,只知道概念,没用过)
1.2、 缓存击穿
现象:当某一 key 失效时,造成大量请求到 DB 层,击垮存储层
原因:为了保证缓存数据的有效性,通常会设置一个失效时间,如果是热点 key ,高并发时会有海量请求直接越过缓存层到数据库,这样就会给数据库赵成很大的负担,严重可能会导致宕机
解决方案:
- 1、使用互斥锁,当缓存数据失效时,保证一个请求能够访问导数据,并更新缓存,其他线程等待并重试。
- 2、缓存数据“永不过期”,如果缓存数据不设置失效时间的话,就不会存在热点 key 过期造成的大量请求到数据库。但是,缓存数据旧变成“静态数据”,因此当缓存数据快要过期时采用异步线程的方式提前进行更新缓存数据
1.3、缓存雪崩
现象:多个key失效,造成大量请求到 DB层,导致 DB 层负担过重甚至宕机
原因:缓存雪崩是指在设置缓存的时候设置了同样的过期时间,导致缓存统一时间失效,失效后全部请求就转发到了数据库,造成数据库一瞬间压力过大而导致数据库崩溃。
解决方案:
- 多每个 key 的失效时间的基础上设置一个随机时间,把失效时间给分布在多个时间节点上,这样就减少了key 在大规模集体失效的可能性。
- 使用互斥锁,保证每一相同的请求只允许单个线程进行 DB 查询
总结:
一般出现这几种问题都是系统设计的问题,如果设计得合理的话几乎不会出现这些问题。
缓存穿透强调是获取本不存在的缓存数据,请求必然会越过缓存层直接到达缓存层,很明显这是利用业务规则的漏洞会系统发起攻击,解决方案的核心原则是过滤这些非法业务请求,与是否是热点数据、缓存失效时间等因素没有关系。
缓存击穿强调的是热点 key 的失效,导致某一时刻大量请求会直接到 DB 层,解决方案的核心原则是规避数据库的并发操作。
缓存雪崩强调的多个 key 的解决失效,与 key 是否是热点数据并不是必然的因素,解决方案的核心原则则是让 key 之间的失效时间分布更加均匀,避免集体失效的情况

