一、最终一致性
1单数据库情况下的事务
如果应用系统是单一的数据库,那么这个很好保证,利用数据库的事务特性来满足事务的一致性,这时候的一致性是强一致性的。对于java应用系统来讲,很少直接通过事务的start和commit以及rollback来硬编码,大多通过spring的事务模板或者声明式事务来保证。
2基于事务型消息队列的最终一致性
借助消息队列,在处理业务逻辑的地方,发送消息,业务逻辑处理成功后,提交消息,确保消息是发送成功的,之后消息队列投递来进行处理,如果成功,则结束,如果没有成功,则重试,直到成功,不过仅仅适用业务逻辑中,第一阶段成功,第二阶段必须成功的场景。对应上图中的C流程。
3基于消息队列+定时补偿机制的最终一致性
前面部分和上面基于事务型消息的队列,不同的是,第二阶段重试的地方,不再是消息中间件自身的重试逻辑了,而是单独的补偿任务机制。其实在大多数的逻辑中,第二阶段失败的概率比较小,所以单独独立补偿任务表出来,可以更加清晰,能够比较明确的直到当前多少任务是失败的。对应上图的E流程。
4业务系统业务逻辑的commit/rollback机制
这一点说的话确实不难,commit和rollback是数据库事务中的比较典型的概念,但是在系统分布式情况下,需要业务代码中实现这种,成功了commit,失败了rollback。
5业务应用系统的幂等性控制
为啥要做幂等呢? 原因很简单,在系统调用没有达到期望的结果后,会重试。那重试就会面临问题,重试之后不能给业务逻辑带来影响,例如创建订单,第一次调用超时了,但是调用的系统不知道超时了是成功了还是失败了,然后他就重试,但是实际上第一次调用订单创建是成功了的,这时候重试了,显然不能再创建订单了。
五事务选型
目前的iTool使用EJB提供的事务,也即是使用了容器管理事务,可以满足事务的实时一致性要求。
新系统在进行系统分析时,按照业务耦合度划分模块,尽量避免将耦合度较高、并且实时性要求较高的模块划分开,这样我们就可以按照最终一致性来处理。
我们使用基于事务性消息的最终一致性解决方案,消息队列工具使用RocketMQ,本地事务使用spring+jotm/+tomcat。