[微服务感悟] 分布式事务-tcc与事务管理器
分布式事务跨服务的事务的处理。对于分布式事务,处理起来都比较麻烦,首先应该考虑是否可以避开分布式事务,如因为服务拆分过细而出现分布式事务,就应该把微服务合并成一个,并处理本地事务。
tcc
和事务管理器
是两种十分常见的分布式事务模式,前者更适用于分布式的场景,后者无实现成功,框架可以傻瓜的解决一切。
tcc分布式事务
tcc是Try - Confirm - Cancel
的简写,使用这种分布式事务,需要在事务的各个服务都实现try
, confirm
, cancel
三套逻辑接口,业务发起方在事务开始时统一调用各微服务的try
接口,这是一个预执行方法,一般这个方法并不会直接修改各业务数据,只是尝试一下是否可以执行;如果try
都执行成功,调用各服务confirm
方法,这时才做业务数据的真正修改;如果try执行过程中发生错误,调用各服务的cancel
方法,将数据回滚。
比如有一个订单完成扣库存的需求,执行try
时,它会检查订单服务和库存服务的数据是否支持这次事务(订单状态是否正确,库存是否充足),并修改相关数据的(不直接修改订单状态和库存数量,修改用于事务专门新增的字段);try
都执行成功后,再执行每个服务的confirm
,修改order状态和库存数据;当try
执行失败时,执行服务的cancel
方法,将数据还原。
如果confirm
和cancel
执行失败,一般会重复执行,直到失败次数到达阀值,记录并转人工处理。因为try
执行成功,说明执行confirm
一般一定会成功的;而cancel
是数据回滚,也一般是可以成功的,所以这两个方法执行失败了,重复执行有大几率最终执行成功。
这里有一个介绍TCC事务具体实现的博客,写的很好,案例通俗易懂。博客中例子存在一个小问题,try
阶段如果库存服务压根没执行锁定库存+2,就报错了,来到cancel
阶段时,执行锁定库存-2,这会导致锁定库存平白的减了2,而实际上这个数应该保持不变。我认为cancel
不能通过++--
的方式去还原,还要通过不变的数据计算还原。终于有人把“TCC分布式事务”实现原理讲明白了!
我也实现了一个TCC事务的DEMO,采用springCloud+h2db技术实现。https://github.com/programluo/tcc-demo。
tcc更适用于分布式场景是因为在没有一个中心的事务管理器存在,每个事务的管理器都在事务发起业务本身,这样它会避免因事务管理器故障导致整个集群所有服务的事务都无法执行的严重隐患。
事务中心
事务中心模式是存在一个事务中心的服务,该事务中心统一协调调用各服务的commit或者rollback本地事务。业务方向事务中心提交一个事务请求,事务管理器先向所有服务发送预执行请求,并等待所有服务的返回,如果都返回成功,则在向所有服务发送commit请求;如果有一个服务返回失败,事务管理器向所有服务发送回滚请求。
这种模式最大的缺点是它的事务管理器这个服务太重要了,一旦挂掉,所有的事务都跑不了;它最大的优点是简单,基本不用写代码,框架都帮我们处理这些工作。