目前的应用系统,不论是企业级应用仍是互联网应用,最终数据的一致性是每一个应用系统都要面临的问题,随着分布式的逐渐普及,数据一致性更加艰难,可是也很难有银弹的解决方案,也并非引入特定的中间件或者特定的开源框架可以解决的,更多的仍是看业务场景,根据场景来给出解决方案。根据笔者最近几年的了解,总结了几个点,更多的应用系统在编码的时候,更加关注数据的一致性,这样系统才是健壮的。java
1、基础理论spring
目前关于事务的几大理论包括:ACID事务特性,CAP分布式理论,以及BASE等。ACID在数据库事务中体现,CAP和BASE则是分布式事务的理论,结合业务系统,例如订单管理,例如仓储管理等,能够借鉴这些理论,从而解决问题。数据库
一、ACID 特性网络
二、CAP特性并发
三、BASE特性框架
2、最终一致性的经常使用作法异步
一、单数据库事务分布式
若是应用系统是单一的数据库,那么这个很好保证,利用数据库的事务特性来知足事务的一致性,这时候的一致性是强一致性的。对于java应用系统来说,不多直接经过事务的start和commit以及rollback来硬编码,大多经过spring的事务模板或者声明式事务来保证;高并发
二、多数据库事务性能
针对多数据库事务能够根据二阶段提交协议,采用spring 3.0 + Atomikos + JTA进行支持;
三、基于事务型消息队列的最终一致性
借助消息队列,在处理业务逻辑的地方发送消息,业务逻辑处理成功后,提交消息,确保消息是发送成功的,以后消息队列投递来进行处理,若是成功,则结束,若是没有成功,则重试,直到成功,不过仅仅适用业务逻辑中,第一阶段成功,第二阶段必须成功的场景。对应上图中的C流程。
四、基于消息队列+定时补偿机制的最终一致性
前面部分和上面基于事务型消息的队列,不一样的是,第二阶段重试的地方,再也不是消息中间件自身的重试逻辑了,而是单独的补偿任务机制。其实在大多数的逻辑中,第二阶段失败的几率比较小,因此单独独立补偿任务表出来,能够更加清晰,可以比较明确的直到当前多少任务是失败的。对应上图的E流程。
五、异步回调机制的引入
A应用调用B,在同步调用的返回结果中,B返回成功给到A,通常状况下,这时候就结束了,其实在99.99%的状况是没问题的,可是有时候为了确保100%,记住最起码在系统设计中100%,这时候B系统再回调A一下,告诉A,你调用个人逻辑,确实成功了。其实这个逻辑,很是相似TCP协议中的三次握手。上图中的B流程。
六、相似double check机制的确认机制
仍是上图中异步回调的过程,A在同步调用B,B返回成功了。此次调用结束了,可是A为了确保,在过一段时间,这个时间能够是几秒,也能够是天天定时处理,再调用B一次,查询一下以前的那次调用是否成功。例如A调用B更新订单状态,这时候成功了,延迟几秒后,A查询B,确认一下状态是不是本身刚刚指望的。上图中的D流程。
3、分布式事务的缺点
一、二阶段提交协议缺点
两阶段提交涉及到多个节点的网络通讯,通讯时间若是过长,事务的相对时间也就会过长,那么锁定资源的时间也就长了.在高并发的服务中,就会存在严重的性能瓶劲
二、消息队列
在高并发的环境中,咱们通常会采用消息队列来避免分布式事务的执行。
在使用消息队列时,咱们须要作到可靠凭证的保存(分布式事务的消息),有以下几种方式:
以支付宝和余额宝为例进行说明.
支付宝完成扣钱的动做时,记录消息数据,将消息数据和业务数据存在同一个数据库实例中.
Begin Transaction update A set amount=amount-1000 where uid=100; insert into message(uid,amount,status) values (1,1000,1) End Transaction Commit;
将支付宝完成扣钱的消息及时发送给余额宝,余额宝完成处理后返回成功消息,支付宝收到消息后,消除消息表中对应的消息记录,即完成本次扣钱操做.
传统方式是,我作完了,发你消息。解决一致性的方案的意思就是,我先发你消息,我作完了再跟你确认我作完了。这是改进后的有事务的消息中间件。