3

分布式事务最终一致性常用方案

 3 years ago
source link: http://wuwenliang.net/2017/04/09/%E5%88%86%E5%B8%83%E5%BC%8F%E4%BA%8B%E5%8A%A1%E6%9C%80%E7%BB%88%E4%B8%80%E8%87%B4%E6%80%A7%E5%B8%B8%E7%94%A8%E6%96%B9%E6%A1%88/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

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

一、基础理论

目前关于事务的几大理论包括: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.png

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;

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

2.png

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

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

出处:http://www.cnblogs.com/moonandstar08/p/5334820.html


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK