一、Seata简介
1、Seata的核心组件
TC (Transaction Coordinator)事务协调者:维护全局和分支事务的状态,协调全局事务提交或回滚。
TM (Transaction Manager)事务管理器:定义全局事务的范围、开始全局事务、提交或回滚全局事务。
RM (Resource Manager)资源管理器:管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。
2、Seata的工作流程
1.TM 向 TC 申请开启一个全局事务,全局事务创建成功后,TC 会针对这个全局事务生成一个全局唯一的 XID;
2.XID 通过服务的调用链传递到其他服务;
3.RM 向 TC 注册一个分支事务,并将其纳入 XID 对应全局事务的管辖;
4.TM 根据 TC 收集的各个分支事务的执行结果,向 TC 发起全局事务提交或回滚决议;
5.TC 调度 XID 下管辖的所有分支事务完成提交或回滚操作。
3、Seata 提供的模式
XA模式:强一致性分阶段事务模式,牺牲了一定的可用性,无业务侵入。
TCC模式:最终一致的分阶段事务模式,有业务侵入。
AT模式:最终一致的分阶段事务模式,无业务侵入,Seata默认模式。
SAGA模式:长事务模式,有业务侵入。
4、AT、XA的架构
AT、XA都采用两阶段提交
二、AT模式
以分布式系统为锚点,锁系统,不锁数据。
1.配置文件
seata:
data-source-proxy-mode: AT # 默认就是AT
2.添加记录表
lock_table 是TC服务关联的表,undo_log是微服务关联的表:
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for undo_log
-- ----------------------------
DROP TABLE IF EXISTS `undo_log`;
CREATE TABLE `undo_log` (
`branch_id` bigint(20) NOT NULL COMMENT 'branch transaction id',
`xid` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 'global transaction id',
`context` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 'undo_log context,such as serialization',
`rollback_info` longblob NOT NULL COMMENT 'rollback info',
`log_status` int(11) NOT NULL COMMENT '0:normal status,1:defense status',
`log_created` datetime(6) NOT NULL COMMENT 'create datetime',
`log_modified` datetime(6) NOT NULL COMMENT 'modify datetime',
UNIQUE INDEX `ux_undo_log`(`xid`, `branch_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = 'AT transaction mode undo table' ROW_FORMAT = Compact;
-- ----------------------------
-- Records of undo_log
-- ----------------------------
-- ----------------------------
-- Table structure for lock_table
-- ----------------------------
DROP TABLE IF EXISTS `lock_table`;
CREATE TABLE `lock_table` (
`row_key` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`xid` varchar(96) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`transaction_id` bigint(20) NULL DEFAULT NULL,
`branch_id` bigint(20) NOT NULL,
`resource_id` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`table_name` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`pk` varchar(36) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`gmt_create` datetime NULL DEFAULT NULL,
`gmt_modified` datetime NULL DEFAULT NULL,
PRIMARY KEY (`row_key`) USING BTREE,
INDEX `idx_branch_id`(`branch_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
SET FOREIGN_KEY_CHECKS = 1;
三、XA模式
XA模式:基于数据库的XA协议来实现的2PC方案(锁数据),强一致性,性能较差。
四、TCC模式
import io.seata.rm.tcc.api.BusinessActionContext;
import io.seata.rm.tcc.api.BusinessActionContextParameter;
import io.seata.rm.tcc.api.LocalTCC;
import io.seata.rm.tcc.api.TwoPhaseBusinessAction;
@LocalTCC
public interface TCCService {
@TwoPhaseBusinessAction(name = "deduct", commitMethod = "confirm", rollbackMethod = "cancel")
void deduct(@BusinessActionContextParameter(paramName = "userId") String userId,
@BusinessActionContextParameter(paramName = "money")int money);
boolean confirm(BusinessActionContext ctx);
boolean cancel(BusinessActionContext ctx);
}
import cn.itcast.account.entity.AccountFreeze;
import cn.itcast.account.mapper.AccountFreezeMapper;
import cn.itcast.account.mapper.AccountMapper;
import cn.itcast.account.service.AccountTCCService;
import io.seata.core.context.RootContext;
import io.seata.rm.tcc.api.BusinessActionContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@Slf4j
public class TCCServiceImpl implements TCCService {
@Autowired
private AccountMapper accountMapper;
@Autowired
private AccountFreezeMapper freezeMapper;
@Override
@Transactional
public void deduct(String userId, int money) {
// 0.获取事务id
String xid = RootContext.getXID();
// 1.扣减可用余额
accountMapper.deduct(userId, money);
// 2.记录冻结金额,事务状态
AccountFreeze freeze = new AccountFreeze();
freeze.setUserId(userId);
freeze.setFreezeMoney(money);
freeze.setState(AccountFreeze.State.TRY);
freeze.setXid(xid);
freezeMapper.insert(freeze);
}
@Override
public boolean confirm(BusinessActionContext ctx) {
// 1.获取事务id
String xid = ctx.getXid();
// 2.根据id删除冻结记录
int count = freezeMapper.deleteById(xid);
return count == 1;
}
@Override
public boolean cancel(BusinessActionContext ctx) {
// 0.查询冻结记录
String xid = ctx.getXid();
AccountFreeze freeze = freezeMapper.selectById(xid);
// 1.恢复可用余额
accountMapper.refund(freeze.getUserId(), freeze.getFreezeMoney());
// 2.将冻结金额清零,状态改为CANCEL
freeze.setFreezeMoney(0);
freeze.setState(AccountFreeze.State.CANCEL);
int count = freezeMapper.updateById(freeze);
return count == 1;
}
}
五、SAGA模式
六、总结
AT、TCC、Saga 都是补偿型的,补偿型分布式事务机制因为不要求事务资源本身(如数据库)的机制参与,所以无法保证从事务框架之外的全局视角的数据一致性。XA 模式的加入,补齐了 Seata 在全局一致性场景下的缺口。