前面聊到,修改数据时,缓存和数据库,不管先操作哪个,都会有潜在的数据不一致问题。怎么解决呢?
前文阅读:《先操作缓冲,还是先操作数据库?》
问题分析
如图:1和2并发请求,1要将用户的余额从200修改为100,2读取用户余额。
假设先操作缓存,后操作数据库,由于无法保证时序,可能出现:
(1)写请求淘汰了缓存
(2)写请求操作了数据库,将用户余额改为100
(3)主从同步没有完成,读请求读了缓存(cache miss)
(4)读请求读了从库(读了一个旧数据:余额200)
(5)读请求set缓存:用户余额200
(6)数据库主从同步完成
最终,数据库中的用户余额为100,而缓存的用户余额为200,数据库和缓存的数据不一致。
如果改为先操作数据库,问题依然存在。因为无法保证读写请求的时序,可能出现:
(1)写请求操作了数据库,将用户余额改为100
(2)写请求淘汰了缓存
(3)主从同步没有完成,读请求读了缓存(cache miss)
(4)读请求读了从库(读了一个旧数据:余额200)
(5)读请求set缓存:用户余额200
(6)数据库主从同步完成
最终,数据库和缓存的数据不一致。
可见,和先操作谁无关。问题的根本原因在于:数据库的主从不一致。当主库上发生写操作之后cache数据库,在从库同步数据的时间间隔内cache数据库,读请求可能导致有旧数据入缓存。
优化方案
方案一:设置缓存过期时间
很多业务是允许一段时间内数据不一致的,比如:朋友圈文章的点赞数。新的点赞数,不及时看到也没问题。这时,只需要设置一个缓存过期时间,比如10分钟。那么10分钟之后,再发起读请求,会cache miss,这时重新从数据库加载数据到缓存,两边的数据就一致了。
付出的代价是每隔一段时间,都会cache miss一次,哪怕这期间数据没有发生修改。
如果业务能够接受,推荐用这个最简单的方案,别把系统架构搞得太复杂。
方案二:订阅binlog,删“脏”数据
如图,在并发读写导致缓存中读入了脏数据之后:
(6)主从同步
(7)通过工具订阅从库的binlog,从而能够准确的知道,从库数据同步完成的时间
订阅工具可以是DTS,cannal等,也可以自己订阅和分析binlog
(8)从库执行完同步,向缓存再次发起删除,淘汰这段时间内可能写入缓存的“脏”数据,此后两边数据一致。
思路比结论重要,希望能对你有所启发。
关注【老张聊架构】,前迅雷大数据CTO,带您成为百万年薪架构师!
———END———
限 时 特 惠:本站每日持续更新海量各大内部创业教程,一年会员只需128元,全站资源免费下载点击查看详情
站 长 微 信:jiumai99