go语言下安装和配置DTM分布式事务管理器
· 首先需要安装go语言,因为dtm是go语言开发的,上一章节我们已经讲了如何安装go语言,这节就略过
DTM安装有多种方式,可以到DTM官网自行查看,选择自己的安装方式,这里我选择的是二进制包安装:
wget https://github.com/dtm-labs/dtm/releases/download/v1.18.0/dtm_1.18.0_linux_amd64.tar.gz tar -zxvf dtm_1.18.0_linux_amd64.tar.gz
#解压之后的文件就是一个单独的dtm二进制文件,只需要输入以下名令启动:
./dtm -c ./conf.sample.yml
DTM配置文件详细:
##################################################################### ### DTM无需任何配置即可运行 ### 该文件中的所有配置都是可选的。默认值与每行中指定的值一致 ### 所有配置都可以从env中指定。例如: ### MicroService.EndPoint => MICRO_SERVICE_END_POINT ##################################################################### Store: # 指定要存储转换状态的引擎 Driver: 'mysql' Host: 'localhost' User: 'root' Password: '' Port: 3306 Db: 'dtm' # Driver: 'boltdb' # 默认存储引擎 # Driver: 'redis' # Host: '192.168.43.51' # User: '192.168.43.51' # Password: '' # Port: 6379 # Driver: 'postgres' # Host: 'localhost' # User: 'postgres' # Password: 'mysecretpassword' # Port: '5432' # Db: 'postgres' # Schema: 'public' # default value is 'public' ### 以下配置仅适用于驱动postgres/mysql MaxOpenConns: 500 MaxIdleConns: 500 ConnMaxLifeTime: 5 # default value is 5 (minutes) ### 以下配置仅适用于某些驱动程序 # DataExpire: 604800 # Trans数据将在7天内过期。仅适用于redis/boltdb # FinishedDataExpire: 86400 # 完成的Trans数据将在1天内过期。只有redis # RedisPrefix: '{a}' # 默认值为“{a}”。Redis存储前缀。数据只存放到集群中的一个槽位 # MicroService: # 基于gRPC/HTTP的微服务配置 # Driver: 'dtm-driver-gozero' # 要处理寄存器/发现的驱动程序的名称 # Target: 'etcd://localhost:2379/dtmservice' # 将DTM服务器注册到此url # EndPoint: 'localhost:36790' ### 以下配置的单位为秒 # TransCronInterval: 3 # 为每个dtm进程轮询未完成的全局事务的间隔 # TimeoutToFail: 35 #超时XA, TCC失败。Saga的超时默认为无限,可以在Saga选项中覆盖 # RetryInterval: 10 # 子传输分支将在此间隔后重试 # RequestTimeout: 3 # HTTP/gRPC请求在dtm中的超时时间 # LogLevel: 'info' # default: info. can be debug|info|warn|error # Log: # Outputs: 'stderr' # default: stderr, split by ",", 如果需要,你可以在output中添加文件。例如:“stderr, /tmp /test.log” # RotationEnable: 0 # default: 0 # RotationConfigJSON: '{}' # example: '{"maxsize": 100, "maxage": 0, "maxbackups": 0, "localtime": false, "compress": false}' # HttpPort: 36789 # GrpcPort: 36790 # JsonRpcPort: 36791 ### 高级选项 # UpdateBranchAsyncGoroutineNum: 1 # 更新分支状态的异步goroutine的个数 # TimeZoneOffset: '' #default '' using system default. '+8': Asia/Shanghai; '0': GMT # AdminBasePath: '' #default '' #设置admin访问基本路径 # ConfigUpdateInterval: 10 # 在内存中更新配置的间隔,例如主题映射…(秒) # TimeZoneOffset: '' # default '' using system default. '+8': Asia/Shanghai; '0': GMT # AlertRetryLimit: 3 # default 3; 如果一个事务分支被重试了3次,就会调用AlertHook # AlertWebHook: '' # default ''; 示例:http://localhost: 8080/dtm-hook’。这个钩子将被这样调用: ## curl -H "Content-Type: application/json" -d '{"gid":"xxxx","status":"submitted","retry_count":3}' http://localhost:8080/dtm-hook
如果要指定配置文件运行的话,运行命令:
go run main.go -c ./conf.sample.yml
- dtm服务器如果使用数据库,那么一定要使用主库。一方面dtm是写多读少,读写分离,对于dtm的负载分摊有限;另一方面dtm对数据的一致性要求较高,从库延时会导致各种问题。
- dtm服务器的时区需要与数据库的时区保持一致
- dtm服务器的时间需要与数据库的时间保持一致,差别不要超过3s
RM 因为涉及本地资源管理,因此使用DTM提供的子事务屏障技术则需要在本地数据库中创建子事务屏障相关的表,建表语句详见:建表SQL中的barrier文件,因为我这里用的是mysql,所以需要在全局中创建,在mysql中执行SQL语句:
create database if not exists dtm_barrier /*!40100 DEFAULT CHARACTER SET utf8mb4 */ ; drop table if exists dtm_barrier.barrier; create table if not exists dtm_barrier.barrier( id bigint(22) PRIMARY KEY AUTO_INCREMENT, trans_type varchar(45) default '', gid varchar(128) default '', branch_id varchar(128) default '', op varchar(45) default '', barrier_id varchar(45) default '', reason varchar(45) default '' comment 'the branch type who insert this record', create_time datetime DEFAULT now(), update_time datetime DEFAULT now(), key(create_time), key(update_time), UNIQUE key(gid, branch_id, op, barrier_id) ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4;
DTM 作为TM角色,如果选择数据库作为存储引擎,那么会将全局事务信息保存在数据库中,需要在相应数据库中创建相关表,建表语句详见建表SQL中的storage文件,在mysql中执行SQL语句:
CREATE DATABASE IF NOT EXISTS dtm /*!40100 DEFAULT CHARACTER SET utf8mb4 */ ; drop table IF EXISTS dtm.trans_global; CREATE TABLE if not EXISTS dtm.trans_global ( `id` bigint(22) NOT NULL AUTO_INCREMENT, `gid` varchar(128) NOT NULL COMMENT 'global transaction id', `trans_type` varchar(45) not null COMMENT 'transaction type: saga | xa | tcc | msg', `status` varchar(12) NOT NULL COMMENT 'transaction status: prepared | submitted | aborting | succeed | failed', `query_prepared` varchar(1024) NOT NULL COMMENT 'url to check for msg|workflow', `protocol` varchar(45) not null comment 'protocol: http | grpc | json-rpc', `create_time` datetime DEFAULT NULL, `update_time` datetime DEFAULT NULL, `finish_time` datetime DEFAULT NULL, `rollback_time` datetime DEFAULT NULL, `options` varchar(1024) DEFAULT '' COMMENT 'options for transaction like: TimeoutToFail, RequestTimeout', `custom_data` varchar(1024) DEFAULT '' COMMENT 'custom data for transaction', `next_cron_interval` int(11) default null comment 'next cron interval. for use of cron job', `next_cron_time` datetime default null comment 'next time to process this trans. for use of cron job', `owner` varchar(128) not null default '' comment 'who is locking this trans', `ext_data` TEXT comment 'extra data for this trans. currently used in workflow pattern', `result` varchar(1024) DEFAULT '' COMMENT 'result for transaction', `rollback_reason` varchar(1024) DEFAULT '' COMMENT 'rollback reason for transaction', PRIMARY KEY (`id`), UNIQUE KEY `gid` (`gid`), key `owner`(`owner`), key `status_next_cron_time` (`status`, `next_cron_time`) comment 'cron job will use this index to query trans' ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4; drop table IF EXISTS dtm.trans_branch_op; CREATE TABLE IF NOT EXISTS dtm.trans_branch_op ( `id` bigint(22) NOT NULL AUTO_INCREMENT, `gid` varchar(128) NOT NULL COMMENT 'global transaction id', `url` varchar(1024) NOT NULL COMMENT 'the url of this op', `data` TEXT COMMENT 'request body, depreceated', `bin_data` BLOB COMMENT 'request body', `branch_id` VARCHAR(128) NOT NULL COMMENT 'transaction branch ID', `op` varchar(45) NOT NULL COMMENT 'transaction operation type like: action | compensate | try | confirm | cancel', `status` varchar(45) NOT NULL COMMENT 'transaction op status: prepared | succeed | failed', `finish_time` datetime DEFAULT NULL, `rollback_time` datetime DEFAULT NULL, `create_time` datetime DEFAULT NULL, `update_time` datetime DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `gid_uniq` (`gid`, `branch_id`, `op`) ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4; drop table IF EXISTS dtm.kv; CREATE TABLE IF NOT EXISTS dtm.kv ( `id` bigint(22) NOT NULL AUTO_INCREMENT, `cat` varchar(45) NOT NULL COMMENT 'the category of this data', `k` varchar(128) NOT NULL, `v` TEXT, `version` bigint(22) default 1 COMMENT 'version of the value', create_time datetime default NULL, update_time datetime DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE key `uniq_k`(`cat`, `k`) ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4;
设置DTM开机自动启动:
touch /usr/lib/systemd/system/dtm.service vi /usr/lib/systemd/system/dtm.service
在dtm.service文件中添加以下代码:
[Unit] Description=zookeeper After=network.target remote-fs.target nss-lookup.target [Service] Type=forking ExecStart=/www/server/dtm/start.sh KillSignal=SIGTERM [Install] WantedBy=multi-user.target
#在start.sh文件中添加以下代码
#! /bin/bash
cd /www/server/dtm
nohup /www/server/dtm/dtm -c /www/server/dtm/conf.sample.yml &
echo 'dtm started'
systemctl enable dtm.service systemctl daemon-reload systemctl is-enabled dtm.service #查看是否自启 systemctl disable dtm.service #取消自启 systemctl daemon-reload