缓存与数据库的一致性

分布式场景下,缓存与数据库的一致性是必须要绕过去的一道坎。而强一致性同步成本太高,如果追求强一致,那么没必要用缓存了,直接用mysql即可。通常考虑的,都是最终一致性。我们要做的,就是把这个最终一致性的时间降到最低。

从理论上来说,给缓存设置过期时间,是保证最终一致性的解决方案。这种方案下,我们可以对存入缓存的数据设置过期时间,所有的写操作以数据库为准,对缓存操作只是尽最大努力即可。也就是说如果数据库写成功,缓存更新失败,那么只要到达过期时间,则后面的读请求自然会从数据库中读取新值然后回填缓存。

 

方案一:先同步数据库,再删除缓存。

失效:应用程序先从cache取数据,没有得到,则从数据库中取数据,成功后,放到缓存中。

命中:应用程序从cache中取数据,取到后返回。

更新:先把数据存到数据库中,成功后,再让缓存失效。

看看更新操作有没有问题。

如果数据库同步成功,缓存操作失败,则让事务回滚,最终还是一致的。

如果数据库同步失败, 缓存也不会再被操作,数据是一致的。

方案二:监听binlog日志

监听binlog日志,当监听到的数据变化时,让缓存失效或更新。

实现方法:业务服务,同步数据完成后,删除缓存。定义好缓存类与数据库表的映射关系,并定义为缓存同步类型,当监听到某一表变化时,调用该同步类型对应的实现类,把数据同步到redis中。

监听biglog的工具:

(1)mysql-binlog-connector这个jar,可以实现监听binlog。

https://github.com/shyiko/mysql-binlog-connector-java

(2)阿里开源的Canal(比较活跃的)

https://github.com/alibaba/canal

(3)zendesk开源的Maxwell

(4)Yelp开源的mysql_streamer

缓存与数据库的一致性_第1张图片

 

方案三:先删缓存,再同步数据库

先删除缓存,成功后,再同步数据库。如果缓存删除成功,数据库同步失败,则下次从数据库读。

此方案存在的最大问题:

1、线程A删除缓存,还没有来得及同步数据库时

2、线程B查询缓存,发现没有,则从数据库查询到旧值,并同步到缓存

3、线程A同步新值到数据库

这样,缓存和数据库就不一致了。

方案四:先更新缓存,再同步数据库

此方案绝对不能用,如果缓存更新成功,数据库操作失败,那就完了。

总结

方案一和方案二可以在实际中使用,其中,如果有强一致性的需求,可以使用方案二。

 

你可能感兴趣的:(架构师实战之数据访问层)