分布式事务

seata文档

分布式事务CAP原则

  • 一致性

多个服务节点,数据必须保持一致(同步)

  • 可用性

服务器节点收到请求,必须在规定时间内做出响应

  • 分区容忍度

出现通信故障时,仍能正常提供服务

要点:一致性和可用性二者必然互斥,需要平衡二者达到最优(数据同步时,外界请求会阻塞)

在分布式系统中,通常可用性高于一致性,即满足AP

保证最终一致性

分布式事务解决方案JTA (两阶段提交)

  • Pre阶段

  • Commit阶段

JTA适合内部系统,对于高并发的项目来说不适合,效率太低

TCC分布式事务解决方案 (三阶段提交)

  • Try 尝试阶段 对资源进行锁定

  • Confirm 确认阶段

  • Cancel 取消阶段

TCC如何保证最终一致性

  • 确认和取消阶段,尽可能逻辑简单,保证其不出错
  • 万一出错,则由TCC框架进行重试补偿
  • 还出错,需要定时任务检测或人工介入

Alibaba Seata分布式解决方案

Seata AT模式

TM:事务管理器
RM:资源管理器
TC:事务协调者

注意

  • 每个业务数据库中添加UNDO_LOG回滚日志表,用于保存回滚操作的数据(表中记录了原先的数据和操作后的数据,方便数据的回滚)
  • 全局提交时,UNDO_LOG记录直接删除
  • 全局回滚时,现有数据撤销,还原至beforeImage状态

具体使用参见yilvs-springcloud项目,mediationusers子项目

Docker搭建TC注意

在搭建中注意的是,如果我们选type为Eureka,那么本地测试的时候url需要映射,serviceUrl用映射之后的url,localhost是不行的,docker内localhost不是我们本地的url

搭建成功,如图所示

MMP,zipkin和seata冲突

解决方法

TCC解决方案

  • 每一个需要事务的地方都准备3个方法,准备–提交–回滚
1
2
3
4
5
6
@GetMapping("/tc1")
public String test1(){
String uuid = UUID.randomUUID().toString();
bussinessService.sale(uuid,"coke",10,30);
return "SUCCESS";
}
1
2
3
4
5
6
7
8
9
10
11
12
13
@GlobalTransactional //开启全局TCC分布式事务
/**
* sale方法执行成功,TC通知RM执行confirm方法(commit)
* sale方法抛出RuntimeException,TC通知RM执行cancel方法(rollback)
*/
public void sale(String orderCode,String goodsCode,
int quantity,float amount){
orderAction.prepare(new BusinessActionContext(), orderCode, goodsCode, quantity, amount);
storageAction.prepare(new BusinessActionContext(), goodsCode, quantity);
if(quantity == 100){
throw new RuntimeException("unknown exception");
}
}
1
2
3
4
5
6
7
8
9
10
11
public interface StorageAction {
//Seata TCC在RM端核心注解,用于声明TCC对应方法
@TwoPhaseBusinessAction(name="TccStorageAction" ,commitMethod = "commit" , rollbackMethod = "rollback")
boolean prepare(BusinessActionContext context,@BusinessActionContextParameter(paramName = "goodsCode") String goodsCode);
// 因为不确定是否有网络因素导致提交接口多次执行
// commit实现的时候为了保证接口幂等性,需要进行判断
// 具备幂等性的实现可以添加一个状态字段,如果当前状态字段已经为提交
// 那么说明改接口已经实现过一次了,那就直接返回成功即可
boolean commit(BusinessActionContext context);
boolean rollback(BusinessActionContext context);
}
  • 不需要像AT模式一样创建UNDO_LOG
  • 需要添加字段预准备字段,比如库存需要添加冻结库存,金额需要添加锁定金额
  • 在准备阶段对预准备字段进行更改,根据是否全部准备完成来具体判断是否要将预准备字段更新到实际字段中,失败则执行rollback方法回滚
赏个🍗吧
0%