当一个事务中某个参与者失败后,传统acid特性的事务通过回滚来保证数据的一致性,但是在分布式架构下很难保证事务的acid特性,比较普遍的做法是保证分布式事务的base特性。Base模式下事务中某个参与者失败后可以通过逆向操作来达到回滚效果,保证数据最终逆向一致,鉴于有些场景不适合做回滚,这里主要探讨一种保证数据最终正向一致即最终成功的方案。
该方案主要参照ebay模式改进而来,举例有主应用、账户系统、订单系统三个系统,用户在主应用发起订单结算,主应用通过账户系统扣款后调用订单系统将订单改成支付完成状态。
1、 主应用以订单id值(结合具体场景选哪个值作为本次事务主键,甚至uuid) 为本次事务的唯一id,假设命名为transId,主应用携带transId请求账户系统扣款
2、 账户系统在本地执行扣款,并且在同事务内记录本次事务id到表transaction中,同时包含完成后续操作所需要的数据
3、 账户扣款成功后主应用携带transId请求订单系统将订单改成已付款状态
4、 订单系统接收到请求后先以transId到表trans_unique中匹配该事务是否处理过以确保幂等性,如果表中没有该事务的记录则新增该事物记录
5、 假设本次订单状态修改失败,主应用引入同步重试机制,因为是同步重试所以重试次数不能超过3次
6、 重试3次后如果成功直接反馈用户处理成功,如果仍然失败告诉用户“订单正在处理中无需继续提交,如在2小时内仍不成功请联系xxx“类似的文案
7、 最后在订单系统增加一个数据正向冲正服务,定时从账户系统获取未删除的事务记录和本地订单状态做校验,如果账户系统有事务记录但本地订单状态非已支付状态则将订单改成已成功进行正向冲正
8、 用户如果对未支付成功的订单执行删除操作要先去账户系统的transaction表做一次check,如果有记录说明该订单正在处理中,提示处理中不能删除
9、 本例讨论的是各个失败环节的处理机制,对于任何一个环节成功都要删除transaction表和trans_unique表记录
方案评估:
优点:
1、 准实时最终一致性,结合事务记录、重试、冲正和业务check等各个环节确保最终成功。因为是确保最终成功相对回滚用户体验较好
2、 相对异步消息机制引入的处理环节较少,风险也就较小
3、 事务方向只往前不后退,不会有脏读的现象
缺点:
1、 业务check环节需要开发人员具备事务意识,容易被忽略
2、 业务侵入性较强,不过貌似每个方案都会有很强侵入性