1. 分布式问题
分布式之前,单机没问题;
分布式之后,一个服务拆分为多个服务
单体应用被拆分成微服务应用,原来的三个模块被拆分成三个独立的应用,分别使用三三个独立的数据源,
业务操作需要调用三个服务来完成。此时每个服务内部的数据一致性由本地事务来保正,但是全局的数据一致性问题没法保证。
用户购买商品的业务逻辑。整个业务逻辑由3个微服务提供支持:
- 仓储服务:对给定的商品扣除仓储数量。
- 订单服务:根据采购需求创建订单
- 帐户服务:从用户帐户中扣除余额
一次业务操作需要跨多个数据源或者需要跨多个系统进行远程调用,就会产生分布式事务问题
2. Seata简介
2.1 是什么?
Seata是一款开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务
官网: http://seata.io/zh-cn/
官网 http://seata.io/en-us/docs/user/quickstart.html
2.2. 分布式事务处理过程-(ID+三组件模型)
2.2.1 全局唯一的事务ID Transaction ID XID
2.2.2 Transaction Coordinator(TC)
事务协调器,维护全局事务的运行状态,负责协调并驱动全局事务的提交或回滚;
2.2.3 Transaction Manager™
控制全局事务的边界,负责开启一个全局事务,并最终发起全局提交或全局回滚的决议;
2.2.4 Resource Manager(RM)
控制分支事务,负责分支注册,状态汇报,并接收事务协调器的指令,驱动分支(本地)事务的提交和回滚;
2.3 处理过程
- TM向TC申请开启一个全局事务,全局事务创建成功并生成一个全局唯一的XID;
- XID在微服务调用链路的上下文中传播:
- RM向TC注册分支事务,将其纳入XID对应全局事务的管辖;
- TM 向TC发起针对XID的全局提交或回滚决议;
- TC调度XD下管辖的全部分支事务完成提交或回滚请求
2.4 去哪下
下载地址: https://github.com/seata/seata/releases
2.5. 怎么玩
3. 安装
- 第一步: 官网地址 http://seata.io/zh-cn/
- 第二步: 下载版本
- seata-server-1.0.0.zip解压到指定目录修改conf目录下的file.conf配置文件
- 先备份原始file.conf文件
- 主要修改: 自定义事务组名称+事务日志存储模式为db+数据库连接信息
- file.conf里面的 service模块 和store模块
- 数据库当中创建seata库
- 在seata库里面创建表
注意,seata的1.0版本里面没有db_store.sql文件,需要自己到0.9版本里面找或到官网找,直接在seata库当中cv运行,会获取以下三张表
- 修改seata-server-1.0.0\seata\conf目录下的registry.conf配置文件
- 先启动Nacos端口号8848
- 再启动seata-server 不然seata-server会找不到nacos会报 no avaliable server to connect
4. sql文件
-- the table to store GlobalSession data
drop table if exists `global_table`;
create table `global_table` (
`xid` varchar(128) not null,
`transaction_id` bigint,
`status` tinyint not null,
`application_id` varchar(32),
`transaction_service_group` varchar(32),
`transaction_name` varchar(128),
`timeout` int,
`begin_time` bigint,
`application_data` varchar(2000),
`gmt_create` datetime,
`gmt_modified` datetime,
primary key (`xid`),
key `idx_gmt_modified_status` (`gmt_modified`, `status`),
key `idx_transaction_id` (`transaction_id`)
);
-- the table to store BranchSession data
drop table if exists `branch_table`;
create table `branch_table` (
`branch_id` bigint not null,
`xid` varchar(128) not null,
`transaction_id` bigint ,
`resource_group_id` varchar(32),
`resource_id` varchar(256) ,
`lock_key` varchar(128) ,
`branch_type` varchar(8) ,
`status` tinyint,
`client_id` varchar(64),
`application_data` varchar(2000),
`gmt_create` datetime,
`gmt_modified` datetime,
primary key (`branch_id`),
key `idx_xid` (`xid`)
);
-- the table to store lock data
drop table if exists `lock_table`;
create table `lock_table` (
`row_key` varchar(128) not null,
`xid` varchar(96),
`transaction_id` long ,
`branch_id` long,
`resource_id` varchar(256) ,
`table_name` varchar(32) ,
`pk` varchar(36) ,
`gmt_create` datetime ,
`gmt_modified` datetime,
primary key(`row_key`)
);
需要每个业务方创建的表undo_log表
drop table `undo_log`;
CREATE TABLE `undo_log` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`branch_id` bigint(20) NOT NULL,
`xid` varchar(100) NOT NULL,
`context` varchar(128) NOT NULL,
`rollback_info` longblob NOT NULL,
`log_status` int(11) NOT NULL,
`log_created` datetime NOT NULL,
`log_modified` datetime NOT NULL,
`ext` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
5. 案列
5.1 订单/库存/账户业务数据库准备
业务说明:
5.2.建表sql:
CREATE DATABASE seata_order;
CREATE DATABASE seata_storage;
CREATE DATABASE seata_account;
2.在各自库下创建业务表
5.3 order库
CREATE TABLE t_order(
`id` BIGINT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
`user_id` BIGINT(11) DEFAULT NULL COMMENT '用户id',
`product_id` BIGINT(11) DEFAULT NULL COMMENT '产品id',
`count` INT(11) DEFAULT NULL COMMENT '数量',
`money` DECIMAL(11,0) DEFAULT NULL COMMENT '金额',
`status` INT(1) DEFAULT NULL COMMENT '订单状态:0:创建中; 1:已完结'
) ENGINE=INNODB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
SELECT * FROM t_order;
5.4 seata_storage库
CREATE TABLE t_storage(
`id` BIGINT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
`product_id` BIGINT(11) DEFAULT NULL COMMENT '产品id',
`'total` INT(11) DEFAULT NULL COMMENT '总库存',
`used` INT(11) DEFAULT NULL COMMENT '已用库存',
`residue` INT(11) DEFAULT NULL COMMENT '剩余库存'
) ENGINE=INNODB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
INSERT INTO seata_storage.t_storage(`id`,`product_id`,`total`,`used`,`residue`)
VALUES('1','1','100','0','100');
SELECT * FROM t_storage;
5.5 seata_account库
CREATE TABLE t_account(
`id` BIGINT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT 'id',
`user_id` BIGINT(11) DEFAULT NULL COMMENT '用户id',
`total` DECIMAL(10,0) DEFAULT NULL COMMENT '总额度',
`used` DECIMAL(10,0) DEFAULT NULL COMMENT '已用余额',
`residue` DECIMAL(10,0) DEFAULT '0' COMMENT '剩余可用额度'
) ENGINE=INNODB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
INSERT INTO seata_account.t_account(`id`,`user_id`,`total`,`used`,`residue`) VALUES('1','1','1000','0','1000')
SELECT * FROM t_account;
5.6 创建undo日志表
重要: 在每个业务库下面创建undo日志表
最后达到这种效果