zoukankan      html  css  js  c++  java
  • 分布式事务最终一致性常用方案

    目前的应用系统,不管是企业级应用还是互联网应用,最终数据的一致性是每个应用系统都要面临的问题,随着分布式的逐渐普及,数据一致性更加艰难,但是也很难有银弹的解决方案,也并不是引入特定的中间件或者特定的开源框架能够解决的,更多的还是看业务场景,根据场景来给出解决方案。根据笔者最近几年的了解,总结了几个点,更多的应用系统在编码的时候,更加关注数据的一致性,这样系统才是健壮的。

    一、基础理论

       目前关于事务的几大理论包括:ACID事务特性,CAP分布式理论,以及BASE等。ACID在数据库事务中体现CAP和BASE则是分布式事务的理论,结合业务系统,例如订单管理,例如仓储管理等,可以借鉴这些理论,从而解决问题。

    1、ACID 特性

    2、CAP特性

    • C(一致性)一致性是指数据的原子性,在经典的数据库中通过事务来保障,事务完成时,无论成功或回滚,数据都会处于一致的状态,在分布式环境下,一致性是指多个节点数据是否一致;
    • A(可用性)服务一直保持可用的状态,当用户发出一个请求,服务能在一定的时间内返回结果;
    • P(分区容忍性)在分布式应用中,可能因为一些分布式的原因导致系统无法运转,好的分区容忍性,使应用虽然是一个分布式系统,但是好像一个可以正常运转的整体

    3、BASE特性

    • BA: Basic Availability 基本业务可用性;
    • S: Soft state 柔性状态;
    • E: Eventual consistency 最终一致性;

    二、最终一致性的常用做法

    1、单数据库事务

          如果应用系统是单一的数据库,那么这个很好保证,利用数据库的事务特性来满足事务的一致性,这时候的一致性是强一致性的。对于java应用系统来讲,很少直接通过事务的start和commit以及rollback来硬编码,大多通过spring的事务模板或者声明式事务来保证;

    2、多数据库事务

         针对多数据库事务可以根据二阶段提交协议,采用spring 3.0 + Atomikos + JTA进行支持;

    3、基于事务型消息队列的最终一致性

         借助消息队列,在处理业务逻辑的地方发送消息,业务逻辑处理成功后,提交消息,确保消息是发送成功的,之后消息队列投递来进行处理,如果成功,则结束,如果没有成功,则重试,直到成功,不过仅仅适用业务逻辑中,第一阶段成功,第二阶段必须成功的场景。对应上图中的C流程。

    4、基于消息队列+定时补偿机制的最终一致性

         前面部分和上面基于事务型消息的队列,不同的是,第二阶段重试的地方,不再是消息中间件自身的重试逻辑了,而是单独的补偿任务机制。其实在大多数的逻辑中,第二阶段失败的概率比较小,所以单独独立补偿任务表出来,可以更加清晰,能够比较明确的直到当前多少任务是失败的。对应上图的E流程。

    5、异步回调机制的引入

         A应用调用B,在同步调用的返回结果中,B返回成功给到A,一般情况下,这时候就结束了,其实在99.99%的情况是没问题的,但是有时候为了确保100%,记住最起码在系统设计中100%,这时候B系统再回调A一下,告诉A,你调用我的逻辑,确实成功了。其实这个逻辑,非常类似TCP协议中的三次握手。上图中的B流程。

    6、类似double check机制的确认机制

        还是上图中异步回调的过程,A在同步调用B,B返回成功了。这次调用结束了,但是A为了确保,在过一段时间,这个时间可以是几秒,也可以是每天定时处理,再调用B一次,查询一下之前的那次调用是否成功。例如A调用B更新订单状态,这时候成功了,延迟几秒后,A查询B,确认一下状态是否是自己刚刚期望的。上图中的D流程。

    三、分布式事务的缺点

    1、二阶段提交协议缺点

        两阶段提交涉及到多个节点的网络通信,通信时间如果过长,事务的相对时间也就会过长,那么锁定资源的时间也就长了.在高并发的服务中,就会存在严重的性能瓶劲

     2、消息队列

       在高并发的环境中,我们一般会采用消息队列来避免分布式事务的执行。

       在使用消息队列时,我们需要做到可靠凭证的保存(分布式事务的消息),有如下几种方式:

       以支付宝和余额宝为例进行说明.

       支付宝完成扣钱的动作时,记录消息数据,将消息数据和业务数据存在同一个数据库实例中.

    Begin Transaction
      update A set amount=amount-1000 where uid=100;
      insert into message(uid,amount,status) values (1,1000,1)
    End Transaction
    Commit;

    将支付宝完成扣钱的消息及时发送给余额宝,余额宝完成处理后返回成功消息,支付宝收到消息后,消除消息表中对应的消息记录,即完成本次扣钱操作.

    传统方式是,我做完了,发你消息。解决一致性的方案的意思就是,我先发你消息,我做完了再跟你确认我做完了。这是改进后的有事务的消息中间件。

    参见:http://coolshell.cn/articles/10910.html

  • 相关阅读:
    【python cookbook学习笔记】给字典增加一个条目
    UI设计星级评价
    弱引用和循环引用
    lua数据类型
    lua虚拟机笔记
    c++对象模型笔记
    使树控件方向键无效
    实现CListCtrl自定义行高
    创建对话框时常用配置
    C++格式化输出总结
  • 原文地址:https://www.cnblogs.com/soundcode/p/7146656.html
Copyright © 2011-2022 走看看