首先应该看能不能规避分布式的事务,如果业务允许的话最好将事务整合到一起,或者整合为一个单一的服务
Sagas长事物本质上是补偿机制的复杂实现,每个业务活动都是一个原子操作,每个业务活动均提供正反操作,任何一个业务活动发生错误,按照执行的反顺序,实时执行反操作,进行事务回滚
回滚失败情况下,需要记录待冲正事务日志,通过重试策略进行重试,冲正重试依然失败的场景,提供定时冲正服务器,对回滚失败的业务进行定时冲正,定时冲正依然失败的业务,等待人工干预
Sagas长事务模型支持对 数据一致性要求比较高的场景比较适用 ,由于采用了补偿的机制,每个原子操作都是先执行任务,避免了长时间的资源锁定,能做到实时释放资源,性能相对有保障
补偿机制
可逆服务 如果实际业务场景上不需要复杂的Sagas事务框架支撑,可以在业务中实现简单的补偿模式,基本可以是做到准实时的补偿,不会有太大的影响
比如在线下单,订单和库存是两个服务两个数据库,则新增订单会有一个对应的逆向操作【移除订单】,而扣减库存也会有一个可逆的操作【增加库存】
事物协调器
基于消息通过最终一致性实现的中间件,通过协调器来对比各个事务方的记录来做最终决定 可能整个周期比较长,需要较长的时间才能给得到最终的一致性
假设现在三方的事务记录是 A 成功,B 失败,C 成功。那么最终决定有两种方式,根据具体场景:
1.重试 B,直到 B 成功,事务记录表里记录了各项调用参数等信息
2.执行 A 和 B 的补偿操作(一种可行的补偿方式是回滚)
对 b 场景做一个特殊说明:比如 B 是扣库存服务,在第一次调用的时候因为某种原因失败了,但是重试的时候库存已经变为 0,无法重试成功,这个时候只有回滚 A 和 C 了
注意这几种方式都需要保证幂等性,否则因为未知原因造成的网络延迟,导致本地RPC调用失败但实际上目标已经执行成功了之后,再在本地进行重试或取消操作,会让数据不一致
妥协
不管什么样的一致性需求,都是需求需要如此,是一种技术向业务妥协的结果,如果反过来改变需求呢(业务向技术妥协)
一个业务场景依赖A和B,我们不妨将服务降级,将这个业务场景精细化拆分成2个步骤,一个只管A,一个只管B
优点是彻底屏蔽了A与B的一致性问题
缺点是需要合理的设计来尽量保证用户体验,并且不管怎么保证都一定会比之前差
不过确实也有许多场景无法降级,因为某些场景本就是强一致性的,别说妥协,甚至连最终一致性可能都不允许,只能强一致性,比如:银行
除了妥协比较特殊,其他方式的原理其实都差不多,将分布式事务转换为多个本地事务,然后依靠溯源、验证、重试、补偿等手段达到最终一致性
并且,这个最终一致性的最终二字,也与具体场景息息相关,不同的业务对这个等待的时间窗口有不同要求,而导致使用不同的方式来实现最终一致性
说到底,任何方式都不过是在一致性(实时一致性、最终一致性)、吞吐量(可用性)和复杂度(业务混乱、代码耦合、实现复杂)之间,做一个选择
领域驱动设计早已阐明,具有强一致性要求的一组业务概念,属于同一个聚合、服务,不建议拆到不同服务中,从而尽可能避免分布式强事务一致性的处理
而可以拆分的服务边界,是在限界上下文的粒度上,比如订单系统与库存系统,这样的一致性属于最终一致性,可以用成熟的工具或者算法处理,比如基于消息的最终一致性
一致性也好,最终一致性也好,本就是这个领域存在悠久的一个复杂问题,它 没有银弹!没有银弹!没有银弹!