什么是saga事务
一个Saga事务就是一个长期运行的事务,这个事务是由多个本地事务所组成, 每个本地事务有相应的执行模块和补偿模块,当saga事务中的任意一个本地事务出错了, 可以通过调用相关事务对应的补偿方法恢复,达到事务的最终一致性。
Saga模式的优势是:
- 一阶段提交本地数据库事务,无锁,高性能;
- 参与者可以采用事务驱动异步执行,高吞吐;
补偿服务即正向服务的“反向”,易于理解,易于实现;
缺点:
Saga 模式由于一阶段已经提交本地数据库事务,且没有进行“预留”动作,所以不能保证隔离性。
saga服务设计经验
- 允许空补偿
原服务未执行,补偿服务执行了。
出现原因:原服务超时(丢包),saga事务触发回滚,未收到原服务请求,先收到补偿请求 - 防悬挂状态
悬挂:补偿服务比原服务先执行了
出现原因:原服务超时(拥堵),saga事务回滚,触发回滚,拥堵的原服务到达
要求允许空补偿,但要拒绝空回补偿后的原服务执行 - 幂等控制
原服务与补偿服务都需要保证幂等性 - 自定义服务恢复策略
由于saga不保证隔离性,在极端情况下可能由于脏写无法完成回滚操作,所以状态机引擎除了提 供回滚能力还需要提供向前执行的恢复操作,让业务最终执行成功。
用户根据提供业务特点配置流程的事务处理策略是优先回滚还是重试,当事务超时Server端会根 据策略不断进行重试。
由于saga不保证隔离性在业务设计的时候要求做到宁可长款,不可短款。长款是出差错我方钱多,短款是我方钱少。就是在业务设计的时候,一定是先扣客户账再入账,因为如果隔离性问题造成覆盖更新,也不会钱少。
saga缺少隔离性带来的问题
- 两个saga事务同时操作一个资源会出现语义不一致
- 两个saga事务同时操作一个订单,彼此会覆盖对方(更新丢失)
- 两个saga事务同时访问扣款账号,无法看到退款(脏读问题)
- 在一个saga事务内,数据被其他事务修改,前后读取数值不一致(模糊读取问题)
saga的两种实现方式
- 集中式:集中式协调器负责服务调用及事务协调。集中式saga一般通过一个saga对象来追踪所有saga子任务调用情况,根据调用情况来决定是否调用对应的补偿应用,协调器和调用方式在一个进程内
- 分布式:一般采用时间驱动方式让参与的服务进行事务协调
参考文档:https://servicecomb.apache.org/cn/docs/distributed-transactions-saga-implementation/
https://www.sofastack.tech/blog/sofa-meetup-3-seata-retrospect/