不同于ACID类型的事务,Saga并不具备隔离性。每个本地事务的结果对其他事务而言都是立即可见的。这种可见性意味着一个给定的实体可能会同时参与到多个并行的Saga中。因此,开发者在设计业务逻辑时,就需要提前预见到这种中间态并处理这种问题。这种事务交叉导致的复杂度主要依赖于底层业务逻辑的性质。
假设一位客户突然提交了一个订单然后又想取消掉,如果是在订单提交到市场上之前发起了这个请求(这时候下单的Saga还依旧处于执行中),那么这个新的指令可能就需要中断这个Saga。
处理这种Saga交叉的情况有3种常用的策略:短路、加锁和中断。
1.短路
在订单还处于其他Saga中时,开发者可以阻止发起新的Saga,比如客户只能在market服务将订单发布到市场后才能取消这个订单。对用户来说,这并不是一个好的办法,但却是最容易实现的策略。
2.加锁
开发者可以使用锁来控制对实体的访问。如果不同的Saga想要修改实体的状态,就需要等待获取实体对应的锁。举例:对股票余额进行了预留或者加锁,以确保客户不能将一个有效订单中的股份出售两次。
如果不同的Saga相互阻止对方获取锁,就可能导致死锁,所以需要开发者实现死锁监控方案和超时方案,以保证系统不会慢慢停下来。
3.中断
开发者可以中断正在执行的动作。比如,开发者可以将订单状态修改为“失败(failed)”。这样,在market网关收到消息要求把这个订单发布到市场上时,它可以再次验证订单的最新状态,以保证这个订单还是可以提交的,这时它会看到一个“失败(failed)”的状态。这种方式增加了业务逻辑的复杂度,但是避免了死锁的风险。
摘取自 摩根·布鲁斯和保罗·A.佩雷拉的《微服务实战》
网友评论