分布式之数据库和缓存双写一致性方案解析(二)

引言

该文是对《分布式之数据库和缓存双写一致性方案解析》,一文的补充。博主在该文中,提到了这么一句话html

应该没人问我,为何没有先更新缓存,再更新数据库这种策略。web

博主当时以为,这种更新策略比较简单,不必多作说明,结果太多人留言给博主,问我为何不说这套方案?好吧,博主先跟你们道个歉,是个人问题。因此再开一文,把这个方案说明一下sql

正文

下面说明一下先更缓存,再更新数据库这套方案数据库

更新数据库失败了怎么办?apache

这个问题其实很好解决,提供一个补偿措施便可。这个补偿措施,你们灵活变通,博主只是举例,以下图所示:缓存

流程以下所示 (1)更新缓存数据安全

(2)更新数据库失败网络

(3)将须要更新的sql发送至消息队列并发

(4)本身消费消息,得到须要更新的sql异步

(5)继续重试更新操做,直到成功

其余方案不列举,由于重点不在这,在下面的状况

有存在其余的线程安全问题么? 有的,假设这会同时有请求A和请求B进行更新操做,那么会出现

(1)线程A更新了缓存

(2)线程B更新了缓存

(3)线程B更新了数据库

(4)线程A更新了数据库 请求A更新数据库应该比请求B更新数据库早才对,可是由于网络等缘由,B却比A更早更新了数据库。这就致使了脏数据,所以不考虑。

但是,这时候有一个细心的读者,给博主举了一个反例。该例子出自《从P1到P7——我在淘宝这7年》这篇博客,博主偷个懒,直接贴一下该博客的原话

在【招财进宝】项目中有一个技术的细节值得拿出来讲说,淘宝商品详情页面天天的流量在10亿以上,里面的内容都是放在缓存里的,作【招财进宝】的时候,咱们要给卖家显示他的商品被浏览的次数,这个数字必须实时更新,而用缓存的话通常都是异步更新的。因而商品表里面增长了这样一个字段,每增长一个PV这个字段就要更新一次。发布上去一个小时数据库就挂掉了,撑不住这么高的update。数据库撑不住怎么办?通常的缓存策略是不支持实时更新的,这时候多隆大神想了个办法,在apache上面写了一个模块,这个数字根本不通过下层的web容器(只通过apache)就写入一个集中式的缓存区了,这个缓存区的数据再异步更新到数据库。好像什么问题,到了多隆手里,总能迎刃而解。

好吧,若是没耐心的读者,直接看博主的总结吧。上面巴拉巴拉一堆,就是说,当时他们有一个读多写多的场景,而后多隆大神用了先更缓存,再异步更新数据库的策略。

难道淘宝的大神没发现线程安全问题?

不是的,上面提到的场景具备一个特殊性。咱们先摘取关键一句话

因而商品表里面增长了这样一个字段,每增长一个PV这个字段就要更新一次

ps:PV是page view,页面浏览量的意思。 博主斗胆猜想,他们作的应该是用户每次点击,数据库里的这个字段就加一的操做。 那咱们这时的SQL通常是这么写

update product_tb set number = number+1 where product_id =xxx

你们注意到了么,并发执行这句SQL并不须要关心执行顺序。哪一个更新线程先执行加一的SQL语句 ,与操做顺序有什么关系呢? 再说的通俗一点,假设咱们同时有请求A和请求B进行更新操做,那么会出现

(1)线程A更新了缓存

(2)线程B更新了缓存

(3)线程B更新了数据库

(4)线程A更新了数据库

由于他们这个时候执行的sql是无序的,因此上面的步骤(3)和步骤(4)哪个步骤先执行,并无关系。最终结果必定是一致的。

容博主啰嗦,来个实例,假设表product_tb以下

product_id number
1 3

这时请求A和请求B同时对product_id为1的数据进行更新操做,不管是按出现并发问题时的顺序

(1)线程B更新了数据库,进行加一

(2)线程A更新了数据库,进行加一

仍是正常的顺序

(1)线程A更新了数据库,进行加一

(2)线程B更新了数据库,进行加一

最终结果都是

product_id number
1 5

ok。说到这里,你们应该是懂了。换句话说,若是此时,操做的sql是有序的,就会出现最上面说的线程安全问题。因此,但愿你们针对问题多思考总结。

给你们留一个思考问题?

若是此时是一个读多写多的场景,又要求更新数据库的操做必须严格保证顺序,那这个时候怎么保证缓存和数据库的一致性?你们能够来个人博客留言。

总结

本文是对上次文章的一次文章的一次补充。只怪博主思考问题太过简单,给你们留了个坑。所以再开一篇文章进行补充说明。但愿你们可以有所收获。

相关文章
相关标签/搜索