缓存与数据库双写一致性保障方案实战

2.在库存服务中实现缓存与数据库双写一致性保障方案实战
实时性比较高的数据缓存,选择的就是库存的服务

库存可能会修改,每次修改都要去更新这个缓存数据; 每次库存的数据,在缓存中一旦过期,或者是被清理掉了,前端的nginx服务都会发送请求给库存服务,去获取相应的数据

库存这一块,写数据库的时候,直接更新redis缓存

实际上没有这么的简单,这里,其实就涉及到了一个问题,数据库与缓存双写,数据不一致的问题

数据库与缓存双写不一致,很常见的问题,大型的缓存架构中,第一个解决方案

2.1、最初级的缓存不一致问题以及解决方案

问题:先修改数据库,再删除缓存,如果删除缓存失败了,那么会导致数据库中是新数据,缓存中是旧数据,数据出现不一致

解决思路:

先删除缓存,再修改数据库。如果删除缓存成功,修改数据库失败了,那么数据库中是旧数据,缓存中是空的,那么数据不会不一致,如果删除缓存失败不执行修改数据库(cache aside pattern)

2.2、比较复杂的数据不一致问题分析

数据发生了变更,先删除了缓存,然后要去修改数据库,此时还没修改

一个请求过来,去读缓存,发现缓存空了,去查询数据库,查到了修改前的旧数据,放到了缓存中

数据变更的程序完成了数据库的修改

完了,数据库和缓存中的数据不一样了。。。。

2.3、为什么上亿流量高并发场景下,缓存会出现这个问题?

只有在对一个数据在并发的进行读写的时候,才可能会出现这种问题

其实如果说你的并发量很低的话,特别是读并发很低,每天访问量就1万次,那么很少的情况下,会出现刚才描述的那种不一致的场景

但是问题是,如果每天的是上亿的流量,每秒并发读是几万,每秒只要有数据更新的请求,就可能会出现上述的数据库+缓存不一致的情况

高并发了以后,问题是很多的

2.4、数据库与缓存更新与读取操作进行异步串行化

更新数据的时候(写请求),根据数据的唯一标识,将操作路由之后,发送到AarrayBlockQueue中

读取数据的时候,如果发现数据不在缓存中,那么将读取mysql数据+更新缓存的操作(读请求),根据产品id路由之后,也发送同一个AarrayBlockQueue中

一个工作线程根据商品id路由到对应的内存队列

这样的话,一个数据变更的操作,先执行,删除缓存,然后再去更新数据库,但是还没完成更新

此时如果一个读请求过来,读到了空的缓存,那么可以先将缓存更新的请求发送到队列中,此时会在队列中积压,然后同步等待缓存更新完成

这里有一个优化点,一个队列中同一个商品,每次调用获取库存的接口时,都会发起一个读取mysql数据+更新缓存的异步请求,这些请求串在一起是没意义的,因此可以做过滤,如果发现队列中同一个商品已经有一个更新缓存的请求了,那么就不用再放这个商品的更新请求操作进去了,直接等待前面的更新操作请求完成即可(代码中利用flagMap实现过滤)

注解:同一个商品在同一个内存队列中,保证删除缓存,和修改数据库的操作不会有其他线程干扰

如果请求还在等待时间范围内,不断轮询发现可以取到值了,那么就直接返回; 如果请求等待的时间超过一定时长,那么这一次直接从数据库中读取当前的旧值

赞(3) 打赏
特别声明:除特殊标注,本站文章均为原创,遵循CC BY-NC 3.0,转载请注明出处。三伏磨 » 缓存与数据库双写一致性保障方案实战

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏