怎样保证缓存一致性问题?

什么是缓存

百度百科定义

> **缓存(cache)**,原始意义是指访问速度比一般[随机存取存储器](https://baike.baidu.com/item/随机存取存储器)(RAM)快的一种高速存储器,通常它不像系统主存那样使用[DRAM](https://baike.baidu.com/item/DRAM)技术,而使用昂贵但较快速的[SRAM](https://baike.baidu.com/item/SRAM)技术。缓存的设置是所有现代计算机系统发挥高性能的重要因素之一。

从整个计算机的发展史可以看出,缓存在提高计算机性能作出巨大贡献例如:CPU缓存(一级缓存、二级缓存、三级缓存)、磁盘缓存、系统缓存、网络缓存、分布式缓存等等。缓存的终结目的也是提高性能、减少数据IO操作和数据溯源等,那么本篇文章主要的是在论述分布式缓存数据的一致性问题。

什么是缓存一致性

​ 这里的缓存一致性最主要的是在讨论在分布式缓存的架构下缓存的一致性问题,如图:

cache1

我们在读取数据库数据的时候首先读取分布式缓存是否存在数据,如果存在就直接返回,如果不存在数据就从数据库读取数据同时缓存数据到分布式缓存中,那么如果存在另外一个线程在更新数据库数据,那么我们应该怎样去更新缓存数据,才能保证数据库和缓存的数据的一致性呢?

解决方案

数据实时同步

​ 首先这种数据同步是增量、主动、强一致性,首先思路

  • 对数据库数据进行更新的时候(新增删除更新)淘汰缓存(缓存失效)

  • 读取数据的时候更新缓存,为了避免缓存击穿带来的雪崩问题我们需要做同步处理,控制只有一个线程去读取数据然后更新到缓存,其他线程被阻塞等待

  • 设置缓存失效时间,这是一个兜底操作假设在更新缓存失败这个缓存失效时间一到就会把缓存失效

    流程图

cache2

数据准实时性

​ 首先这种数据同步是增量、被动、准一致性,首先思路

  • 对数据进行更新操作时在保持数据库后发送一个更新缓存的MQ消息(如果要保证数据不丢失,建议可以建立本地一个消息表在发生MQ失败后可以重试)
  • 缓存更新服务消费MQ更新数据消息后读取数据库数据进行相关业务处理(比如需要读取数据库数据进行汇总计算操作等)
  • 缓存更新服务更新业务处理结果数据到分布式缓存中

cache3

任务调度更新

​ 这种通过分布式调度任务进行定时更新缓存,使用场景如:报表统计数据、对账数据定时更新到缓存,实现比较简单

缓存穿透

**现象:**每次请求直接穿透缓存层,直接回源到数据库中,给数据库带来了巨大访问压力,甚至宕机。

**原因:**访问数据会先访问缓存,如果数据不存在缓存中才会查询数据库,但是如果查询数据库也查询不出来数据,也是说当前访问数据永远不会写入缓存中。这样就导致了,访问一定不存在的数据,就相当于缓存层形同虚设,每次请求都会到db层,造成数据库负担过大。

解决方案:

  • 方案一:采用bloom filter保存缓存过的key,在访问请求到来时可以过滤掉不存在的key,防止这些请求到db层;
  • 方案二:如果db查询不到数据,保存空对象到缓存层,设置较短的失效时间;
  • 方案三:针对业务场景对请求的参数进行有效性校验,防止非法请求击垮db。

缓存击穿

**现象:**当某一key失效时,造成大量请求到db层,击垮存储层。

**原因:**为了保证缓存数据的时效性,通常会设置一个失效时间,如果是热点key,高并发时会有海量请求直接越过缓存层到数据库,这样就会给数据库造成的负担增大,设置宕机。

解决方案

  • 方案一:使用互斥锁,当缓存数据失效时,保证一个请求能够访问到数据库,并更新缓存,其他线程等待并重试;
  • 方案二:缓存数据“永远不过期”,如果缓存数据不设置失效时间的话,就不会存在热点key过期造成了大量请求到数据库。但是,缓存数据就变成“静态数据”,因此当缓存数据快要过期时,采用异步线程的方式提前进行更新缓存数据。

缓存雪崩

**现象:**多个key失效,造成大量请求到db层,导致db层负担过重甚至宕机。

**原因:**缓存雪崩是指在我们设置缓存时采用了相同的过期时间,导致缓存在某一时刻同时失效,请求全部转发到数据库,最终导致数据库瞬时压力过大而崩溃。

解决方案:

  • 方案一:使用互斥锁的方式,保证只有单个线程进行请求能够达到db;
  • 方案二:多每个key的失效时间在基础时间上再加上一个1~5分钟的随机值,这样就能保证大规模key集体失效的概率,并且需要尽量让多个key的失效时间能够均匀分布;

我的博客地址

关注我

在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章