3.【多级缓存架构】数据库和缓存不一致的情况分析和解决方案
文章目录
- 3.【多级缓存架构】数据库和缓存不一致的情况分析和解决方案
- 1. 最初级的缓存不一致的问题以及解决方案
- 1.1 问题:先修改数据库,在删除缓存,如果删除缓存失败了,就会导致数据库中的是新数据,缓存中的是旧数据,数据出现不一致。
- 1.2 解决思路:
- 2. 复杂的数据不一致的问题分析(多线程并发读写同一个数据)
- 2.1 问题
- 2.2 出现原因:
- 2.3 解决方案:数据库和缓存更新与读取操作异步串行化
- 2.3 高并发场景下,该解决方案要注意的问题
- 2.3.1 读请求长时间阻塞
- 2.3.2 读请求并发量过高
- 2.3.3 热点商品的路由问题,导致请求的倾斜
数据库和缓存双写不一致的问题时一个很常见的问题,解决该问题也是缓存架构中必不可少的一部分
1. 最初级的缓存不一致的问题以及解决方案
1.1 问题:先修改数据库,在删除缓存,如果删除缓存失败了,就会导致数据库中的是新数据,缓存中的是旧数据,数据出现不一致。
1.2 解决思路:
- 先删除缓存,再修改数据库,如果删除缓存成功了,修改数据库失败了,那么数据库中的是旧数据,缓存中是空的,那么数据就会不一致
- 下次读请求过来的时候,发现缓存没有,则从数据库读取旧数据,然后更新到缓存中。虽然最后的结果是,数据库和缓存虽然都是旧数据,但是没有数据不一致的情况。
2. 复杂的数据不一致的问题分析(多线程并发读写同一个数据)
2.1 问题
- 数据发生了变更,先删除了缓存,然后要去修改数据库;此时还没有修改,另外一个请求过来了,去读缓存,发现缓存空了,去查询数据库,查到了修改前的旧数据,放到了缓存中。 数据变更的程序完成了数据库的修改,发现 缓存中的是 旧数据,数据库中的是 新数据,出现数据不一致的问题。
2.2 出现原因:
- 只有在对一个数据并发的进行读写的时候,才可能会出现上述问题;
- 其实如果说你的并发量很低的话,特别是读并发很低,每天访问量1万次,就很少会出现上述情况。但是,如果每天是上亿的流量,每秒并发读是几万,每秒只要有更新的请求,就很大的几率出现数据库+缓存不一致的情况。
2.3 解决方案:数据库和缓存更新与读取操作异步串行化
- 更新数据的时候,根据数据的唯一标识,将操作路由之后,发送到一个jvm内部队列中。
- 读取数据的时候,如果发现数据不再缓存中,那么将重新读取数据 + 更新缓存的操作串行化;读取数据的时候,也根据唯一标示路由之后,发送到同一个jvm内部队列中。
- 一个队列对应一个工作线程,每个工作线程串行拿到对应的操作,然后一条一条的执行
这样的话,一个数据变更的操作,先执行 删除缓存,然后去 更新数据库,但是还没更新,此时如果一个读请求过来,读到了 空的缓存,那么就可以 将缓存更新的请求发送到队列中,此时 读请求 会在队列中积压,然后同步等待缓存更新完成。
这里还有一个优化点,一个队列中,其实多个更新缓存请求串行化在一起是没有意义的,因此可以做过滤,如果发现有一个更新缓存的请求,那么就不用再放个更新请求操作进去了,直接等待前面的更长操作请求完成即可。
待 那个队列 对应的工作线程 完成了上一个操作的数据库修改之后,才会去执行下一个操作,也就是缓存更新操作,此时会从数据库中读取最新的值,然后写入到缓存中。
如果请求还在等待时间访问内,不断轮询发现可以取到值了,那么就直接返回;然后请求等待的时间超过一定的时长,那么这一次就就直接从数据库读取当前的旧值。
2.3 高并发场景下,该解决方案要注意的问题
2.3.1 读请求长时间阻塞
- 读请求长时间阻塞, 由于进行了非常轻度的异步化,所以一定要注意读超时的问题,每个读请求都必须在超时时间内返回。
- 该解决方案,最大的风险点在于说,可能数据更新和频繁,导致队列积压了大量的更新操作在里面,然后读请求会发生大量的超时,导致大量的数据直接走数据库。
- 另外一点,因为一个队列中,可能会基于针对多个数据项的更新操作,因此需要根据自己的业务进行测试,可能需要部署多个服务,每个服务分摊一些数据的更新操作。
- 如果一个内存队列里居然会积压100个商品的库存修改操作,每个库存修改操作10ms去完成,那么最后一个商品的读请求,可能就要等待10 * 100 = 1000ms = 1s,才能得到数据,这个时候就会导致读请求长时间阻塞。
- 一定要根据实际业务系统的运行情况,去进行一些压力测试
目的:和模拟线上环境,去看看最繁忙的时候,内存队列中可能会积压多少更新操作,可能导致最后一个更新操作对应读请求,会hang多少秒,如果读请求在200ms返回,如果你计算过后,哪怕是最繁忙的时候,积压10个更新操作,最多等待200ms,那还是可以的。
- 如果内存队列积压的的操作过多
解决方案:部署更多的机器,让每个机器部署的服务实例处理更少的数据,那么每个队列更新的操作就会减少。
2.3.2 读请求并发量过高
解决方案:多服务部署的请求路由,保证说,执行数据更新操作,以及执行缓存更新操作,都通过nginx服务器路由到相同的服务实例上
2.3.3 热点商品的路由问题,导致请求的倾斜
万一某个商品的读写请求特别高,全部达到相同的机器的相同队列中,可能造成某台机器压力过大。也就是说,因为只有在商品数据更新的时候才会请求缓存,然后才会有读写并发,所以更新频率不是太高的话,这个问题的影响并不是特别大,但的确坑你某些机器的负载会高一些。
参考石衫老师亿级流量笔记
如果对你有用,点个赞再走呗!!!