GTS介绍
全局事务服务(Global
Transaction Service,简称 GTS)是一款高性能、高可靠、接入简单的分布式事务中间件,用于解决分布式环境下的数据一致性问题。
一个完整的业务往往需要调用多个子业务或服务,随着业务的不断增多,涉及的服务及数据也越来越多,越来越复杂。传统的系统难以支撑,出现了应用和数据库等的分布式系统。分布式系统又带来了数据一致性的问题,从而产生了分布式事务。
分布式事务是指事务发起者、资源管理器、事务协调者及资源分别位于不同的分布式系统的不同节点之上。
GTS 的架构如下图所示:
ü GTS 服务端:即事务协调器。负责分布式事务的推进,管理事务生命周期。
ü GTS 客户端:即事务发起者。通过事务协调器,开启、提交、回滚分布式事务。同时还包含部分资源管理器组件,负责管理和控制资源,与 GTS 服务器进行交互。
ü 服务框架:GTS 可以和 EDAS
等服务框架配合使用,管理服务框架中的事务。服务框架可以集成资源管理器组件,管理和控制资源。
ü 资源: 包括RDS、DRDS、MySQL以及其它数据库事务,还包括 MQ 消息事务
在单机数据库下很容易维持事务的 ACID(Atomicity、Consistency、Isolation、Durability)特性,但在分布式系统中并不容易,GTS 可以保证分布式系统中的分布式事务的 ACID 特性。
GTS 支持 DRDS、RDS、MySQL 等多种数据源,可以配合 EDAS 和 Dubbo 等微服务框架使用, 兼容 MQ 实现事务消息。通过各种组合,可以轻松实现分布式数据库事务、多库事务、消息事务、服务链路级事务等多种业务需求
GTS解决使用 DRDS 进行分库分表后产生的跨分库事务问题
DRDS 通过分库分表实现数据水平拆分, 来解决单机关系型数据库扩展性问题. 但是原有单库单表进行分库分表后, 单表的数据被分散到多个库的表中, 原来对单表多行数据进行的变更, 可能会变为对多库多表的数据变更,即单机本地事务变成了分布式事务。
DRDS 本身不支持分布式事务, 上述场景下再采用原来的单库事务进行操作会导致失败。在 DRDS 中加入 GTS 能够实现这种多个库交易操作的原子性,解决分布式数据库跨库事务的问题
应用端使用分布式事务流程,手工处理事务的典型 SQL 语句步骤如下:
1.set
autocommit=false //开启事务
2.select
last_txc_xid() //注册一个 GTS 事务
3.insert/update/delete
等业务 SQL
4.commit 或者 rollback //全局提交或回滚
5.autocommit=true //恢复自动提交
通过后端RDS的SQL审计可以查看到在分布式事务情况下分库的处理过程:
插入类型:
序号 |
SQL明细 |
1 |
SET autocommit=0 |
2 |
select * from `USER_TBL` limit 1 |
3 |
SHOW FULL TABLES FROM `marcotest_iirz_0004` LIKE 'user_tbl' |
4 |
SHOW FULL COLUMNS FROM `user_tbl` FROM `marcotest_iirz_0004` LIKE '%' |
5 |
SHOW INDEX FROM `user_tbl` FROM `marcotest_iirz_0004` |
6 |
/* 0aacc85e15058276714612682d3f81/9// *//*DRDS /11.193.54.46/bc105690c801000-d/ */insert into `user_tbl` ( `u_id`, `u_name`, `u_phone`, `u_national`, `createtime`, `updatetime`) values ( 7927652, 'marco7809361834', '8874414727236', 'China-RDS000', '2017-07-09 21:42:50', '2017-07-09 21:42:50') |
7 |
SELECT `USER_TBL`.U_PHONE,`USER_TBL`.U_NAME,`USER_TBL`.U_NATIONAL,`USER_TBL`.CREATETIME,`USER_TBL`.U_ID,`USER_TBL`.UPDATETIME FROM `USER_TBL` WHERE user_tbl.U_ID = 7927652 |
8 |
INSERT INTO txc_undo_log(id, xid, branch_id, rollback_info, gmt_create, gmt_modified, status, server) VALUES(769948877,'10.152.29.148:8091:769948876',769948877,'{\"branchId\":769948877,\"id\":0,\"info\":[{\"frontImage\":{\"line\":[],\"schemaName\":\"marcotest_iirz_0004\",\"tableName\":\"user_tbl\"},\"rearImage\":{\"line\":[{\"fields\":[{\"name\":\"U_PHONE\",\"type\":12,\"value\":\"8874414727236\"},{\"name\":\"U_NAME\",\"type\":12,\"value\":\"marco7809361834\"},{\"name\":\"U_NATIONAL\",\"type\":12,\"value\":\"China-RDS000\"},{\"name\":\"CREATETIME\",\"type\":93,\"value\":\"1499607770000\"},{\"name\":\"U_ID\",\"type\":4,\"value\":7927652},{\"name\":\"UPDATETIME\",\"type\":93,\"value\":\"1499607770000\"}]}],\"schemaName\":\"marcotest_iirz_0004\",\"tableName\":\"user_tbl\"},\"selectSql\":\"SELECT `USER_TBL`.U_PHONE,`USER_TBL`.U_NAME,`USER_TBL`.U_NATIONAL,`USER_TBL`.CREATETIME,`USER_TBL`.U_ID,`USER_TBL`.UPDATETIME FROM `USER_TBL`\",\"sql\":\"/* 0aacc85e15058276714612682d3f81/9// *//*DRDS /11.193.54.46/bc105690c801000-d/ */insert into `user_tbl` ( `u_id`, `u_name`, `u_phone`, `u_national`, `createtime`, `updatetime`) values ( 7927652, \'marco7809361834\', \'8874414727236\', \'China-RDS000\', \'2017-07-09 21:42:50\', \'2017-07-09 21:42:50\') \",\"sqlType\":\"INSERT\",\"whereCondition\":\" WHERE U_ID=7927652\"}],\"rT\":31553,\"rTFromLastPoint\":1,\"registBranch\":true,\"server\":\"10.152.29.148:8091\",\"status\":0,\"writeKeys\":\"user_tbl:7927652\",\"xid\":\"10.152.29.148:8091:769948876\"}',now(),now(),0,'10.152.29.148:8091') ON DUPLICATE KEY UPDATE id = 769948877,xid = '10.152.29.148:8091:769948876',branch_id = 769948877,rollback_info = '{\"branchId\":769948877,\"id\":0,\"info\":[{\"frontImage\":{\"line\":[],\"schemaName\":\"marcotest_iirz_0004\",\"tableName\":\"user_tbl\"},\"rearImage\":{\"line\":[{\"fields\":[{\"name\":\"U_PHONE\",\"type\":12,\"value\":\"8874414727236\"},{\"name\":\"U_NAME\",\"type\":12,\"value\":\"marco7809361834\"},{\"name\":\"U_NATIONAL\",\"type\":12,\"value\":\"China-RDS000\"},{\"name\":\"CREATETIME\",\"type\":93,\"value\":\"1499607770000\"},{\"name\":\"U_ID\",\"type\":4,\"value\":7927652},{\"name\":\"UPDATETIME\",\"type\":93,\"value\":\"1499607770000\"}]}],\"schemaName\":\"marcotest_iirz_0004\",\"tableName\":\"user_tbl\"},\"selectSql\":\"SELECT `USER_TBL`.U_PHONE,`USER_TBL`.U_NAME,`USER_TBL`.U_NATIONAL,`USER_TBL`.CREATETIME,`USER_TBL`.U_ID,`USER_TBL`.UPDATETIME FROM `USER_TBL`\",\"sql\":\"/* 0aacc85e15058276714612682d3f81/9// *//*DRDS /11.193.54.46/bc105690c801000-d/ */insert into `user_tbl` ( `u_id`, `u_nam |
9 |
commit |
10 |
SET autocommit=1 |
11 |
delete from txc_undo_log where id = 769948877 |
更新类型:
序号 |
SQL明细 |
1 |
SET autocommit=0 |
2 |
select * from USER_TBL limit 1 |
3 |
SHOW FULL TABLES FROM `marcotest_iirz_0004` LIKE 'user_tbl' |
4 |
SHOW FULL COLUMNS FROM `user_tbl` FROM `marcotest_iirz_0004` LIKE '%' |
5 |
SHOW INDEX FROM `user_tbl` FROM `marcotest_iirz_0004` |
6 |
SELECT USER_TBL.U_PHONE,USER_TBL.U_NAME,USER_TBL.U_NATIONAL,USER_TBL.CREATETIME,USER_TBL.U_ID,USER_TBL.UPDATETIME FROM USER_TBL WHERE USER_TBL.`u_id` = 7927652 FOR UPDATE |
7 |
/* 0aacc85e15058261818692667d3f81/9// *//*DRDS /11.193.54.46/bc0ffc01f801000-d/ */update `user_tbl` set `u_national` = 'China-RDS000--' where (`u_id` = 7927652) |
8 |
SELECT USER_TBL.U_PHONE,USER_TBL.U_NAME,USER_TBL.U_NATIONAL,USER_TBL.CREATETIME,USER_TBL.U_ID,USER_TBL.UPDATETIME FROM USER_TBL WHERE U_ID=7927652 |
9 |
INSERT INTO txc_undo_log(id, xid, branch_id, rollback_info, gmt_create, gmt_modified, status, server) VALUES(969949165,'10.152.29.138:8091:969949163',969949165,'{\"branchId\":969949165,\"id\":0,\"info\":[{\"frontImage\":{\"line\":[{\"fields\":[{\"name\":\"U_PHONE\",\"type\":12,\"value\":\"8874414727236\"},{\"name\":\"U_NAME\",\"type\":12,\"value\":\"marco7809361834\"},{\"name\":\"U_NATIONAL\",\"type\":12,\"value\":\"China-RDS000\"},{\"name\":\"CREATETIME\",\"type\":93,\"value\":\"1499607770000\"},{\"name\":\"U_ID\",\"type\":4,\"value\":7927652},{\"name\":\"UPDATETIME\",\"type\":93,\"value\":\"1499607770000\"}]}],\"schemaName\":\"marcotest_iirz_0004\",\"tableName\":\"user_tbl\"},\"rearImage\":{\"line\":[{\"fields\":[{\"name\":\"U_PHONE\",\"type\":12,\"value\":\"8874414727236\"},{\"name\":\"U_NAME\",\"type\":12,\"value\":\"marco7809361834\"},{\"name\":\"U_NATIONAL\",\"type\":12,\"value\":\"China-RDS000--\"},{\"name\":\"CREATETIME\",\"type\":93,\"value\":\"1499607770000\"},{\"name\":\"U_ID\",\"type\":4,\"value\":7927652},{\"name\":\"UPDATETIME\",\"type\":93,\"value\":\"1505826181000\"}]}],\"schemaName\":\"marcotest_iirz_0004\",\"tableName\":\"user_tbl\"},\"selectSql\":\"SELECT USER_TBL.U_PHONE,USER_TBL.U_NAME,USER_TBL.U_NATIONAL,USER_TBL.CREATETIME,USER_TBL.U_ID,USER_TBL.UPDATETIME FROM USER_TBL\",\"sql\":\"/* 0aacc85e15058261818692667d3f81/9// *//*DRDS /11.193.54.46/bc0ffc01f801000-d/ */update `user_tbl` set `u_national` = \'China-RDS000--\' where (`u_id` = 7927652)\",\"sqlType\":\"UPDATE\",\"whereCondition\":\" WHERE U_ID=7927652\"}],\"rT\":19155,\"rTFromLastPoint\":0,\"registBranch\":true,\"server\":\"10.152.29.138:8091\",\"status\":0,\"writeKeys\":\"user_tbl:7927652\",\"xid\":\"10.152.29.138:8091:969949163\"}',now(),now(),0,'10.152.29.138:8091') ON DUPLICATE KEY UPDATE id = 969949165,xid = '10.152.29.138:8091:969949163',branch_id = 969949165,rollback_info = '{\"branchId\":969949165,\"id\":0,\"info\":[{\"frontImage\":{\"line\":[{\"fields\":[{\"name\":\"U_PHONE\",\"type\":12,\"value\":\"8874414727236\"},{\"name\":\"U_NAME\",\"type\":12,\"value\":\"marco7809361834\"},{\"name\":\"U_NATIONAL\",\"type\":12,\"value\":\"China-RDS000\"},{\"name\":\"CREATETIME\",\"type\":93,\"value\":\"1499607770000\"},{\"name\":\"U_ID\",\"type\":4,\"value\":7927652},{\"name\":\"UPDATETIME\",\"type\":93,\"value\":\"1499607770000\"}]}],\"schemaName\":\"marcotest_iirz_0004\",\"tableName\":\"user_tbl\"},\"rearImage\":{\"line\":[{\"fields\":[{\"name\":\"U_PHONE\",\"type\":12,\"value\":\"8874414727236\"},{\"name\":\"U_NAME\",\"type\":12,\"value\":\"marco7 |
10 |
commit |
11 |
SET autocommit=1 |
12 |
delete from txc_undo_log where id = 969949165 |
删除类型:
序号 |
SQL明细 |
1 |
SET autocommit=0 |
2 |
select * from `USER_TBL` limit 1 |
3 |
SHOW FULL TABLES FROM `marcotest_iirz_0004` LIKE 'user_tbl' |
4 |
SHOW FULL COLUMNS FROM `user_tbl` FROM `marcotest_iirz_0004` LIKE '%' |
5 |
SHOW INDEX FROM `user_tbl` FROM `marcotest_iirz_0004` |
6 |
SELECT `USER_TBL`.U_PHONE,`USER_TBL`.U_NAME,`USER_TBL`.U_NATIONAL,`USER_TBL`.CREATETIME,`USER_TBL`.U_ID,`USER_TBL`.UPDATETIME FROM `USER_TBL` WHERE `USER_TBL`.`u_id` = 7927652 FOR UPDATE |
7 |
/* 0aacc85e15058271185702675d3f81/9// *//*DRDS /11.193.54.46/bc10169d0401000-27/ */delete from `user_tbl` where (`u_id` = 7927652) |
8 |
INSERT INTO txc_undo_log(id, xid, branch_id, rollback_info, gmt_create, gmt_modified, status, server) VALUES(869948781,'10.152.29.56:8091:869948780',869948781,'{\"branchId\":869948781,\"id\":0,\"info\":[{\"frontImage\":{\"line\":[{\"fields\":[{\"name\":\"U_PHONE\",\"type\":12,\"value\":\"8874414727236\"},{\"name\":\"U_NAME\",\"type\":12,\"value\":\"marco7809361834\"},{\"name\":\"U_NATIONAL\",\"type\":12,\"value\":\"China-RDS000--\"},{\"name\":\"CREATETIME\",\"type\":93,\"value\":\"1499607770000\"},{\"name\":\"U_ID\",\"type\":4,\"value\":7927652},{\"name\":\"UPDATETIME\",\"type\":93,\"value\":\"1505826181000\"}]}],\"schemaName\":\"marcotest_iirz_0004\",\"tableName\":\"user_tbl\"},\"rearImage\":{\"line\":[],\"schemaName\":\"marcotest_iirz_0004\",\"tableName\":\"user_tbl\"},\"selectSql\":\"SELECT `USER_TBL`.U_PHONE,`USER_TBL`.U_NAME,`USER_TBL`.U_NATIONAL,`USER_TBL`.CREATETIME,`USER_TBL`.U_ID,`USER_TBL`.UPDATETIME FROM `USER_TBL`\",\"sql\":\"/* 0aacc85e15058271185702675d3f81/9// *//*DRDS /11.193.54.46/bc10169d0401000-27/ */delete from `user_tbl` where (`u_id` = 7927652)\",\"sqlType\":\"DELETE\",\"whereCondition\":\" WHERE U_ID=7927652\"}],\"rT\":40160,\"rTFromLastPoint\":1,\"registBranch\":true,\"server\":\"10.152.29.56:8091\",\"status\":0,\"writeKeys\":\"user_tbl:7927652\",\"xid\":\"10.152.29.56:8091:869948780\"}',now(),now(),0,'10.152.29.56:8091') ON DUPLICATE KEY UPDATE id = 869948781,xid = '10.152.29.56:8091:869948780',branch_id = 869948781,rollback_info = '{\"branchId\":869948781,\"id\":0,\"info\":[{\"frontImage\":{\"line\":[{\"fields\":[{\"name\":\"U_PHONE\",\"type\":12,\"value\":\"8874414727236\"},{\"name\":\"U_NAME\",\"type\":12,\"value\":\"marco7809361834\"},{\"name\":\"U_NATIONAL\",\"type\":12,\"value\":\"China-RDS000--\"},{\"name\":\"CREATETIME\",\"type\":93,\"value\":\"1499607770000\"},{\"name\":\"U_ID\",\"type\":4,\"value\":7927652},{\"name\":\"UPDATETIME\",\"type\":93,\"value\":\"1505826181000\"}]}],\"schemaName\":\"marcotest_iirz_0004\",\"tableName\":\"user_tbl\"},\"rearImage\":{\"line\":[],\"schemaName\":\"marcotest_iirz_0004\",\"tableName\":\"user_tbl\"},\"selectSql\":\"SELECT `USER_TBL`.U_PHONE,`USER_TBL`.U_NAME,`USER_TBL`.U_NATIONAL,`USER_TBL`.CREATETIME,`USER_TBL`.U_ID,`USER_TBL`.UPDATETIME FROM `USER_TBL`\",\"sql\":\"/* 0aacc85e15058271185702675d3f81/9// *//*DRDS /11.193.54.46/bc10169d0401000-27/ */delete from `user_tbl` where (`u_id` = 7927652)\",\"sqlType\":\"DELETE\",\"whereCondition\":\" WHERE U_ID=7927652\"}],\"rT\":40160,\"rTFromLastPoint\":0,\"registBranch\":true,\"server\":\"10.152.29.56:8091\",\"s |
9 |
commit |
10 |
SET autocommit=1 |
11 |
delete from txc_undo_log where id = 869948781 |
客户端发起分布式事务的时候会获取一个全局事务ID,每个分库的任何更新操作前会发起分支事务或者BranchID,任何进行更新操作,当前客户端发起全局提交时,GTS会对每个分库的undo_log表插入回滚信息,然后提交(如果任一分库提交失败,使用回滚信息进行回滚操作);等所有分库提交成功后,在删除所有分库的回滚信息;
回滚信息主要是通过查询表结构元数据及通过主键来查询更新前后的行数据,所有使用GTS分布式事务涉及的表一定要有主键;
可以看看txc_undo_log表结构,在每个分库都会有一张:
XID:XID,即 GTS 分布式事务的全局事务 ID,GTS 服务会为每一个分布式事务生成一个全局唯一的分布式事务 ID
Branch_ID:GTS 分布式事务的分支事务 ID,它是事务分支的唯一标识。XID 和 BranchId 是一对多的包含关系,即一个全局事务可能包含多个事务分支
rollback_info:回滚信息,主要是保存UNDO LOG;