最近打算给jSqlBox添加分布式事务功能,研究了几种分布式事务方案,对SAGA模式比较感兴趣,它是通过将多个事务隔离成多个单个事务,顺序执行(或回滚阶段倒序对冲)来完成的,但是SAGA分布式事务不能保证隔离性的问题,因为单纯的SAGA模式没有锁住资源。经考虑发现在SAGA的思路上,利用事务嵌套和全局锁,可以实现一种简单的分布式事务实现,暂时给它起个新名字叫“Bag分布式事务”,因为它实现的关键是所有事务都是层层嵌套的,象一个袋子装在另一个袋子里。这里以三层事务嵌套作为示例 , 见下图:
它将多个单机事务嵌套使用,并在最里层的事务里获取一个全局排它锁,这样如果业务出错,或排它锁未获取成功的情况下,所有事务自动回滚,无需人为干预,从而简洁地保证了数据的最终一致性。如果因为硬件、网络故障导致部分提交的现象,在业务层可以先尝试倒序执行UndoSQL来回滚全局事务, 回滚的最后一步是解锁。
这种分布式事务方案的优点是实现简单,无需专门的全局事务管理器,UndoSQL的尝试调用可以包含在业务方法里。而且数据库只须要支持单机ACID事务,无须XA协议支持,通用性好。
如果网络故障较多的情况下,有可能造成部分提交且无法解锁的情况(实际上是比较罕见的,因为它发生的前题是业务SQL执行没有异常抛出,且所有数据库连接在此之前正常工作,而且业务方法里的UndoSQL调用失败),这时除了人为介入外,如果工作量大也可以考虑设置一个单独的事务回滚服务器,专门用来监控和自动回滚锁定的事务,因为undoSQL或快照已经被保存在业务数据库里了。
这种模式下在最里层的事务里需要获得一个全局锁,如果不讲究高可用性的话,可以通过指定任意一个数据库来存放。
2019.5.31补充:
最近看到了这篇文章《关于分库分表,这有一套大而全的轻量级架构设计思路》,我的构思实际上就是这篇文章中提到的“最大努力保证模式”,不是什么新发明,只不过是在最里层加上了一个全局排它锁而已。