分布式事务处理方案

单数据库状况下的事务

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

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

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

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

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

业务系统业务逻辑的commit/rollback机制

这一点说的话确实不难,commit和rollback是数据库事务中的比较典型的概念,可是在系统分布式状况下,须要业务代码中实现这种,成功了commit,失败了rollback。多线程

业务应用系统的幂等性控制

为啥要作幂等呢? 缘由很简单,在系统调用没有达到指望的结果后,会重试。那重试就会面临问题,重试以后不能给业务逻辑带来影响,例如建立订单,第一次调用超时了,可是调用的系统不知道超时了是成功了仍是失败了,而后他就重试,可是实际上第一次调用订单建立是成功了的,这时候重试了,显然不能再建立订单了。并发

  • 查询

查询的API,能够说是自然的幂等性,由于你查询一次和查询两次,对于系统来说,没有任何数据的变动,因此,查询一次和查询屡次同样的。异步

  • MVCC方案

多版本并发控制,update with condition,更新带条件,这也是在系统设计的时候,合理的选择乐观锁,经过version或者其余条件,来作乐观锁,这样保证更新及时在并发的状况下,也不会有太大的问题。例如update table_xxx set name=#name#,version=version+1 where version=#version# ,或者是 update table_xxx set quality=quality-#subQuality# where quality-#subQuality# >= 0 。分布式

  • 单独的去重表

若是涉及到的去重的地方特别多,例如ERP系统中有各类各样的业务单据,每一种业务单据都须要去重,这时候,能够单独搞一张去重表,在插入数据的时候,插入去重表,利用数据库的惟一索引特性,保证惟一的逻辑。编码

  • 分布式锁

仍是拿插入数据的例子,若是是分布是系统,构建惟一索引比较困难,例如惟一性的字段无法肯定,这时候能够引入分布式锁,经过第三方的系统,在业务系统插入数据或者更新数据,获取分布式锁,而后作操做,以后释放锁,这样实际上是把多线程并发的锁的思路,引入多多个系统,也就是分布式系统中得解决思路。spa

  • 删除数据

删除数据,仅仅第一次删除是真正的操做数据,第二次甚至第三次删除,直接返回成功,这样保证了幂等。线程

  • 插入数据的惟一索引

插入数据的惟一性,能够经过业务主键来进行约束,例如一个特定的业务场景,三个字段确定肯定惟一性,那么,能够在数据库表添加惟一索引来进行标示。

  • API层面的幂等

这里有一个场景,API层面的幂等,例如提交数据,如何控制重复提交,这里能够在提交数据的form表单或者客户端软件,增长一个惟一标示,而后服务端,根据这个UUID来进行去重,这样就能比较好的作到API层面的惟一标示。

  • 状态机幂等

在设计单据相关的业务,或者是任务相关的业务,确定会涉及到状态机,就是业务单据上面有个状态,状态在不一样的状况下会发生变动,通常状况下存在有限状态机,这时候,若是状态机已经处于下一个状态,这时候来了一个上一个状态的变动,理论上是不可以变动的,这样的话,保证了有限状态机的幂等。

异步回调机制的引入

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流程。

总结

上面的几点总结,更多的在业务系统中体现,在超复杂的系统中,数据的一致性,不是说简单的引入啥中间件可以解决的,更多的是根据业务场景,来灵活应对。

相关文章
相关标签/搜索