一马平川
不积跬步无以至千里,后继才能薄发

缓存与数据库双写数据一致性问题

2021年08月03日
0
未分类

缓存与数据库双写数据一致性问题

本质上来说,双写一致性问题是因为更新数据库和更新缓存不是原子操作,如果要做到强一致性,只能加分布式锁。不然就是做取舍问题。

缓存是用在:不经常变动,但是又经常查询,而且发生脏读不敏感的场景下使用

缓存+数据库读写模式:

  1. cache aside pattern
    1. 读的时候,先读缓存,缓存没有的话就读数据库,读到的数据库的值再存入缓存。
    2. 数据更新的时候,更新数据库,删除缓存。
  2. Read-Through/Write-Through(读写穿透)
    1. 读写通过Cache Provider封装的api,Cache Provider进行缓存的读取和数据库的读取&更新缓存,写的时候也是通过Provider进行。
  3. Write-behind(异步缓存写入)
    1. 通过Cache Provider进行读写访问,Cache Provider在缓存层进行更新,不同步更新数据库,而是通过间隔一段时间批量异步更新数据库,如linux的os cache实现,写入之后定时进行fsync才会真正刷入磁盘

如何解决双写数据一致性问题
0. 读的时候,先读缓存,缓存没有的话就读数据库,读到的数据库的值再存入缓存,这种模式有极低的概率会导致不一致,可以给缓存设置一个过期时间,避免极少数key一直不一致

  1. 强一致性情况下使用分布式事务对读写进行控制,但会降低并发量,没有什么意义。
  2. 弱一致性情况下使用延迟双删,更新数据库之前删除缓存,更新之后再延迟删除缓存,延迟的时间可以是读业务逻辑的耗时+几百毫秒
  3. 高并发读写的情况下,在一个修改请求删除了缓存之后,准备进行数据库更新,这时候有一个读请求进来,发现缓存为空,然后去数据库获取到旧值,保存到缓存中,然后修改请求修改数据库完成,这时候出现不一致问题
    这时候可以考虑把缓存更新和读取操作进行异步串行化,将读写请求根据唯一标识进行路由,发送到一个内部队列中,
  4. 删除缓存重试机制
  5. 读取biglog异步删除缓存
  6. 写-延迟删缓存
  7. 消息队列异步更新缓存,注意带上时间戳避免并发写时顺序与写DB不一致

整体来说还是需要结合实际项目,一致性和并发不能兼顾,具体情况具体分析了,如果是需要强一致性,其实缓存也就没有意义了,直接读库就行了…

如果喜欢这篇文章,可以给作者评个份哦~

原文声明: "转载本站文章请注明作者和出处Nothinglin ,请勿用于任何商业用途"

公众号:苦逼的学生仔