zoukankan      html  css  js  c++  java
  • 【原创】分布式之数据库和缓存双写一致性方案解析(二)

    引言

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

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

    博主当时觉得,这种更新策略比较简单,没必要多做说明,结果太多人留言给博主,问我为什么不说这套方案?好吧,博主先跟大家道个歉,是我的问题。所以再开一文,把这个方案说明一下

    正文

    下面说明一下先更缓存,再更新数据库这套方案
    更新数据库失败了怎么办?
    这个问题其实很好解决,提供一个补偿措施即可。这个补偿措施,大家灵活变通,博主只是举例,如下图所示:
    image
    流程如下所示
    (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是有序的,就会出现最上面说的线程安全问题。所以,希望大家针对问题多思考总结。
    给大家留一个思考问题?
    如果此时是一个读多写多的场景,又要求更新数据库的操作必须严格保证顺序,那这个时候怎么保证缓存和数据库的一致性?大家可以来我的博客留言。

    总结

    本文是对上次文章的一次文章的一次补充。只怪博主思考问题太过简单,给大家留了个坑。因此再开一篇文章进行补充说明。希望大家能够有所收获。

  • 相关阅读:
    写作的益处
    【转载】德鲁克:激发我一生的七段经历
    PS如何删除灰色的自动切片
    其他经验博文分类链接
    LODOP单个简短问答(小页面无需拖动滚动条)
    LODOP导出excel的页眉页脚
    LODOP导出和写入excel测试
    LODOP导出Excel简短问答和相关博文
    Lodop导出excel带数字格式
    LODOP批量打印判断是否加入队列1
  • 原文地址:https://www.cnblogs.com/rjzheng/p/9240611.html
Copyright © 2011-2022 走看看