GreatDB cluster分布式事务(DTM)
DTM(Distributed Transaction Manager)分布式事务管理器为GreatDB cluster组件,提供分布式事务ID(DTID,全局唯一的编号,全局递增)和全局活跃事务视图,用于进行全局的事务控制和隔离级别的实现。自5.1.8版本引入。
DTM架构
DTM本身是经典的C-S架构,集成在GreatDB 引擎中,以组件的形式部署、启用。
当DTM启用后,GreatDB cluster存在唯一一个SQLNode担任DTM Server角色,至少存在一个SQLNode担任DTM Client角色; DTM Client的数量取决于GreatDB cluster的规模。 GreatDB cluster SQLNode都可以担任DTM Client角色。
DTM server由GreatDB cluster内部机制(Gdb task)选取,GreatDB cluster中存在一个DTM_SERVER task,抢占到此任务的SQLNode成为DTM server,无法手动指定。当DTM server所属SQLNode离线,集群中SQLNode通过重新抢占DTM_SERVER task来选举新的DTM server。由于DTM server内部的全局活跃事务视图全部维护在内存中,DTM server切换后全局活跃事务视图丢失。
DTM集成在GreatDB引擎中,DTM未增加新的探活机制,完全依赖SQLNode探活机制。
DTM没有主从概念。GreatDB cluster只有1个DTM server节点,server节点网络延迟会拖慢集群的整体性能,现阶段没有内部机制处理此问题。
DTM事务模型
LTA: Local Trx Agent,即单机本地事务机制。
在支持DTM之前,依靠单机本地事务机制LTA(Local Transaction Agent)保证事务特性。支持DTM后,DTM与LTA协同工作,实现分布式事务特性:
支持分布式事务的原子性,保证分布式事务整体提交或者回滚;
支持分布式事务一致性,DTM+LTA基于MVCC机制组合实现分布式RC、RR隔离级别
一个简单的DTM事务中DTM相关的交互:
事务开启时,SQLNode从DTM server获取DTID
根据不同的隔离级别,SQLNode从DTM获取snapshot(全局一致性事务视图)
SQLNode将全局事务信息(DTID+ snapshot)带入到DataNode
DataNode根据DTM信息和LTA进行数据的可见性判断
针对RC和RR不同的隔离级别,主要的区别在于获取snapshot的时机:
RC隔离级别下,针对每个语句都要从DTM获取snapshot
RR隔离级别下,只在事务启动时获取一次snapshot
DTM安装部署
DTM的引入并未对GreatDB cluster的安装部署带来任何冲击,可以按常规的方式部署GreatDB cluster,只需要在GreatDB cluster SQLNode配置文件中添加DTM专有配置参数即可启动DTM事务特性。DataNode的部署不需要任何调整。
DTM参数说明
功能相关参数
| 参数名称 | 说明 | 参数值 |
|---|---|---|
| greatdb_enable_dtm | 是否启用 DTM 分布式事务 如果要启用 DTM 分布式事务, GreatDB 集群中所有 SQLNode 都需要指定 greatdb_enable_dtm=ON | 布尔类型 默认值:OFF |
| greatdb_dtm_server_candidate | 当前 SQLNode 是否可以成为DTM Server 如果要保证 DTM 高可用,所有 SQLNode 都需要指定 greatdb_dtm_server_candidate=ON, 如果greatdb_dtm_server_candidate=OFF, 当前SQLNode不能成为DTM Server | 布尔类型 默认值:true |
| greatdb_dtm_server_port | DTM Server 监听端口。 当 DTM Server 启动后,DTM Server 的后端线程会在该端口监听连接请求。 | 整形值 默认值:10000 范围:[1025,65534] |
| greatdb_dtm_server_address | 当前DTM server的地址, 格式为ip:port:timestamp, 可以通过设置 此参数值来手动连接到DTM server。 timestamp为dtm server启动的时间戳 | 字符串类型 默认值:空 |
| greatdb_dtm_trx_timeout | DTM 事务超时时间,单位:秒 DTM client超过此时间未接收到DTM server回复, 会标记事务失败,触发DTM client 重新连接DTM server | 整形值 默认值:6,0表示无限等待 范围:[0, 4294967295] |
| greatdb_dtm_client_con_count | DTM client重新连接DTM server时的重连尝试次数, 超过此重连次数还未重连成功,自动重连失败, 需要手动执行set global greatdb_dtm_server_address 指令触发DTM client重连 | 整形值 默认值:1000 范围:[1,16384] |
| greatdb_dtm_client_con_interval | DTM client重新连接DTM server时的重连间隔,单位:毫秒 | 整形值 默认值:5000 范围:[1,4294967295] |
| greatdb_dtm_client_connect_tries | 用于设置DTM client连接DTM server的 连接超时时间,超时时间以2的指数进行增长 | 整形值 默认值:4,超时时间为1+2+4+8=15s 范围:[1,1000] |
| greatdb_dtm_handshake_timeout | DTM内部server与client通信接收 握手消息的超时时间,单位:毫秒 建议参数值小于greatdb_dtm_trx_timeout的一半 | 整形值 默认值:1000 范围:[1,3600000] |
| greatdb_dtm_log_file | DTM 日志文件 如果未设置此参数,DTM日志与log_error 日志在同一目录下,如果未设置log_error, DTM日志会写到/tmp目录下, DTM日志文件名拼接规则: dtmservice+greatdb_dtm_server_port.log | 字符串类型 默认值:空 |
| greatdb_wait_non_running_xa _trx_before_dtm_start | DTM server因故障进行切换时,新的DTM server启动前 是否会kill后端数据节点上的活跃事务的连接, 直到没有活跃事务才启动DTM server服务。 开启此参数能够保证DTM server切换瞬间的事务一致性。 开启此参数需要启动performance_schema 下的threads和events_transactions_current系统表 | 布尔类型 默认值:TRUE |
| greatdb_dtm_server_sqlnode _address | 当前DTM server所属的sqlnode连接信息, 格式为ip:port。 | 字符串类型 默认值:空 |
功能参数配置建议
如果要启用 DTM 分布式事务,所有 SQLNode 都需要指定 loose-greatdb_enable_dtm=ON,如果不是所有SQLNode指定loose-greatdb_enable_dtm=ON,并不会报错,只是loose-greatdb_enable_dtm=OFF的SQLNode依旧使用单机本地事务。
loose-greatdb_dtm_server_candidate只有在loose-greatdb_enable_dtm=ON时才有意义,如果要保证 DTM 高可用,所有 SQLNode 都需要指定 loose-greatdb_dtm_server_candidate=ON,greatdb_dtm_server_candidate=OFF的SQLNode无法成为DTM server,如果所有SQLNode都指定greatdb_dtm_server_candidate=OFF,GreatDB cluster无法提供事务操作。
greatdb_dtm_server_port端口被占用的话,DTM server启动失败,DTM server、client由后台线程启动,启动失败不会给客户端返回失败信息,失败信息记录在SQLNode error日志中。
如果要保证事务原子性,必须指定 loose-greatdb_enable_xa=ON。
如果要保证高可用,建议指定greatdb_dtm_trx_timeout为非0值,能够通过事务超时机制触发DTM client的重连。
当网络延迟较大时,适当调大greatdb_dtm_handshake_timeout但不要超过greatdb_dtm_trx_timeout的一半, 避免因DTM内部通信网络超时导致连接失败。
网络不稳定时,可以调大greatdb_dtm_client_con_count来提高自动重连次数,调大greatdb_dtm_client_connect_tries提高连接超时时间。
发生网络故障时,DTM client内部有自动重连机制,如果网络故障时间很长,在greatdb_dtm_client_con_count指定的重连次数后还未连接成功,可以在网络恢复后,通过set global greatdb_dtm_server_address的方式手动连接到DTM server。
性能相关参数
性能相关参数用于DTM性能调优,一般情况采用默认值即可。如果需要进行性能调优,需要结合服务器的CPU、内存情况进行调整,具体问题具体分析,找出最优值。具体参数说明如下:
| 参数名称 | 说明 | 参数值 |
|---|---|---|
| greatdb_dtm_server _recv_concurrency | DTM Server 端通信层用来接收 DTM Client 请求的并发线程数目 | 整型值 默认值:8 范围:[1,64] |
| greatdb_dtm_server _send_concurrency | DTM Server 端通信层用来给 DTM Client 发送数据的并发线程数目 | 整型值 默认值:8 范围:[1,64] |
| greatdb_dtm_client_gen _view_concurrency | DTM Client 用来生成活跃事务列表的并发线程数目 此参数需要大于greatdb_dtm_readview_read_count 并且为其整倍数 | 整型值 默认值:8 范围:[1,64] |
| greatdb_dtm_server _combine_snap | DTM Servers 是否批量向 DTM Client 发送活跃事务列表,指定为ON时能够减少 网络交互的开销,提升性能 | 布尔类型 默认值:ON |
| greatdb_dtm_client _incr_snap | DTM Client 是否以增量的形式向 DataNode 发送活跃事务列表,指定为ON时SQLNode 只向DataNode发送活跃事务列表中的增量部分,节省网络带宽 | 布尔类型 默认值:OFF |
| greatdb_dtm_log_level | DTM 日志输出级别,输出所有小于等于此级别的日志到dtm log文件,日志级别: DTM_FATAL=0 DTM_ERROR=1 DTM_WARNING=2 DTM_INFO=3 DTM_DEBUG=4 DTM_TRACE=5 global级别可动态修改 | 整形值 默认值:3 范围:[0,5] |
| greatdb_dtm_server _reply_threads | DTM server端处理事务请求回复的线程数量 | 整形值 默认值:8 范围:[1,2048] |
| greatdb_enable_dml_acquire _dtm_readview | DTM事务中insert、update、delete、 replace into statement是否获取DTM readview, 为OFF可以减少获取readviwe的网络交互开销,提升性能 | 布尔类型 默认值:OFF |
| greatdb_enable_purge _dtm_xa_log | 是否自动清理datanode的DTM xa log, 即是否自动清理mysql.greatdb_dtm_xa_log表中数据 | 布尔类型 默认值:ON |
| greatdb_dtm_server_wait _sync_time | DTM server出现时钟漂移时,DTM server启动事务时 等待时钟同步的超时时间,单位毫秒,超过此时间 DTM server还未完成时钟同步,事务启动失败。 此参数值需要小于greatdb_dtm_trx_timeout值 | 数值类型 默认值:3000, 0表示不等待时钟同步 范围:[0,4294967295] |
| greatdb_dtm_async _commit_level | 全局事务异步提交等级,参数取值会影响事务一致性。 0:事务强一致性,保证集群全局事务一致性 1:事务弱一致性,保证单个sqlnode上事务的一致性 不建议生产环境开启此选项 | 数值类型 默认值:0 范围[0,1] |
| greatdb_dtm_readview _wakeup_count | DTM client端唤醒请求readview事务的线程数 | 数值类型 默认值:4 范围[1,32] |
| greatdb_dtm_readview _read_count | DTM client端生成readview的线程数 greatdb_dtm_client_gen_view_concurrency 必须大于此参数并为此参数的整倍数。 | 数值类型 默认值:4 范围[1,32] |
| greatdb_dtm_trx_async _commit | DTM事务提交时计算节点向数据节点发送XA COMMIT 是否采用异步模式。 启用异步提交能够提升性能。 | 布尔类型 默认值:ON |
| greatdb_dtm_server_time _persist_timeout | DTM server启动事务时等待greatdb引擎持久化 用于生成DTID的时间戳的超时时间,单位秒。 要求小于greatdb_dtm_trx_timeout,为0表示无限等待。 | 整型值 默认值:5 范围[0,4294967295] |
| greatdbdtm_readview compress | DTM client向datanode发送readview时是否启用压缩。 | 整形值 默认值:1 范围[0,4294967295] |
运维相关参数
| 参数名称 | 说明 | 参数值 |
|---|---|---|
| greatdb_dtm_trx_available | 用于显示DTM client是否正常提供服务。 参数值由程序内部设置,不需要手动设置, DTM client启动成功后将此参数设置为ON, DTM client出现异常后将此参数设置为OFF。 限制:当MGR网络故障导致SQLNode被剔除出集群后, greatdb_dtm_trx_available无法准确显示DTM状态, 即只有SQLNode状态为ONLINE时 greatdb_dtm_trx_available能准确显示DTM状态。 | 布尔类型 默认值:OFF |
| innodb_greatdb_non_dtm _upgrade_to_dtm | 为非DTM版本升级到DTM版本服务。 DTM版本第一次启动之前,需要打开此参数, 启动DTM版本并确认成功后,必须关闭此参数并重启所有进程。 此参数不能在运行过程中处于打开状态,否则会触发未知的行为。 详细使用方式见手册离线升级中DTM升级部分。 | 布尔类型 默认值:FALSE |
| innodb_dtm_disable | InnoDB引擎是否禁用DTM特性。 DataNode为NODE_MGR模式时, 此参数由程序内部设置,primary状态的DataNode参数值为OFF, secondary状态的DataNode参数值为ON; DataNode为NODE_SINGLE模式时, 此参数由配置文件设置,如果GreatDB引擎要启用DTM事务, 此参数需要设置为OFF。 | 布尔类型 默认值:OFF |
| greatdb_print_dtm _debug_info | 是否打印DTM相关调试信息,调试信息可打印到DTM日志, 也可打印到log_error日志。系统级别变量,global级别可动态修改。 如果DTM出现异常,可以打开此参数输出DTM调试 信息进行问题定位,注意日志打印量可能非常大, 问题定位后需及时关闭此参数 | 布尔类型 默认值:OFF |
| show_dtid_enable_info | 参数表示show create table是否展示enable_dtid信息:show_dtid_enable_info = DTID_INFO_OFF时,则不显示;show_dtid_enable_info = ENABLE_DTID_INFO_OFF时,对于enable_dtid = OFF则不显示,只显示enable_dtid = ON;show_dtid_enable_info = ENABLE_DTID_INFO_ON时,对于enable_dtid = OFF和enable_dtid = ON都显示。 | 枚举类型 默认值:ENABLE_DTID_INFO_OFF 范围: DTID_INFO_OFF ENABLE_DTID_INFO_OFF ENABLE_DTID_INFO_ON |
| greatdb_output_dtm_status | show engine greatdb status是否展示DTM信息 | 整形值 默认值:0 范围:[0,2] |
| greatdbdtm_trx_perf track_frequency | show engine greatdb status DTM性能统计 的采样频率,为0关闭DTM性能统计。 详细说明见手册Show Dtm Status说明章节。 | 整形值 默认值:0 范围:[0,102410241024] |
| track_mvcc_dtm_footprint | 是否将可见性判断信息输入到error-log中 0:不输出,> 0:输出 详细说明见手册Show Dtm Status说明章节。 | 整型值 默认值:0 范围:[0,16] |
| greatdb_dtm_client_id _generate_method | client id的生成方式。 GENERATE_BY_SERVER_ID: client id = server_id GENERATE_BY_SERVER_UUID: client id = select CRC32(@@server_uuid)变量修改后需要重启sqlnode或者 切换DTM server使client id的修改生效 | 枚举类型 默认值:GENERATE_BY_SERVER_ID 范围: GENERATE_BY_SERVER_ID GENERATE_BY_SERVER_UUID |
启用DTM事务特性
启用DTM事务特性,greatdb引擎需要开启DTM,并且greatdb引擎的表需要开启enable_dtid属性。
greatdb引擎开启DTM
greatdb引擎启动DTM, 每个client对应一个client id,要求client id在集群范围内是唯一的,如果client id重复,会导致相同client id并且后连接到server的client启动失败,sqlnode error日志中会打印"is duplicated"日志,show engine greatdb status的dtm service status部分也会显示相应信息。
client id生成方式取决于枚举类型系统变量greatdb_dtm_client_id_generate_method,支持的取值有:
GENERATE_BY_SERVER_ID:client id与系统变量server_id相等,client id重复时需要修改sqlnode的server_id。
GENERATE_BY_SERVER_UUID:client id由系统变量server_uuid计算而来,client id=
select CRC32(@@server_uuid), server_uuid在sqlnode集群中是唯一的,但函数CRC32的计算结果可能出现重复导致client id重复,此时需要将greatdb_dtm_client_id_generate_method修改为GENERATE_BY_SERVER_ID,使用server_id生成client id。
特别注意,修改server_id或者greatdb_dtm_client_id_generate_method之后,需要重启sqlnode或者切换DTM server使client id的修改生效。
建议所有sqlnode greatdb_dtm_client_id_generate_method采用相同的配置。
启动DTM事务特性需配置以下参数:
loose-greatdb_enable_dtm=ON
loose-greatdb_dtm_server_candidate=ON
loose-greatdb_enable_xa=ON
测试高可用场景(DTM网络异常等)时,需要配置以下参数(可以根据网络延迟、负载等情况调整具体参数值):
loose-greatdb_dtm_trx_timeout=10
loose-greatdb_dtm_client_con_count=5
loose-greatdb_dtm_client_connect_tries=4
loose-greatdb_dtm_handshake_timeout=1000
greatdb_dtm_client_con_count * greatdb_dtm_client_connect_tries 大于故障时间DTM client才能够自动恢复服务,否则需要在故障恢复后,手动通过set global greatdb_dtm_server_address='current_dtm_server_address' 来启动client。
目前获取当前DTM server地址current_dtm_server_address值的方式有2种:
查询sqlnode的系统变量greatdb_dtm_trx_available,为on的sqlnode上系统变量greatdb_dtm_server_address的值作为current_dtm_server_address
在所有sqlnode的error日志里搜索"DTM Server started"关键字,最新的日志记录中的字符串即为current_dtm_server_address
greatdb表开启enable_dtid
可以在create table时指定enable_dtid属性,语法如下:
create table t (a int primary key) [enable_dtid=ON|OFF]
可以通过alter table修改enable_dtid属性,语法如下:
alter table t enable_dtid=ON|OFF
enable_dtid属性限制:
create table未指定enable_dtid属性,sqlnode greatdb_enable_dtm=ON时,enable_dtid默认为ON;greatdb_enable_dtm=OFF时,enable_dtid默认为OFF
greatdb_enable_dtm=OFF时,create table或alter table指定enable_dtid=ON会报错
DTM状态查询
DTM 部署后,系统级变量 greatdb_dtm_server_address 为 DTM Server 的地址(ip:port:timestamp), 系统级变量 greatdb_dtm_trx_available 为DTM client是否正常提供服务,如下:
| Variable_name | Value |
|---|---|
| greatdb_dtm_server_address | 127.0.0.1:8192:1646294691509 |
| greatdb_dtm_trx_available | ON |
只有在SQLNode状态为ONLINE时,greatdb_dtm_trx_available才能准确显示DTM状态,如果greatdb_dtm_trx_available为OFF,表示当前SQLNode DTM不可用,greatdb_dtm_server_address为过时的DTM server地址。
DTM Server高可用
DTM Server提供高可用服务,当DTM Server节点发生故障,GreatDB Cluster会选取新的SQLNode接管DTM Server服务。DTM Server故障检测依赖现有的SQLNode探活机制,从检测到DTM Server节点发生故障到选举出新的DTM Server节点,期间无法提供DTM服务。
DTID作为GreatDB Cluster全局唯一并且递增的事务编号,依赖DTM Server物理机器的时间。为了确保DTID递增,DTM Server物理机器时间不能回退。DTM Server将生成DTID的时间戳定时持久化到mysql.greatdb_sqlnode_tasks系统表中,可以通过select info from mysql.greatdb_sqlnode_tasks where task_id=3查询持久化的时间戳,查询结果为dtm server daemon task:1646294691502,其中1646294691502为DTM server持久化的毫秒级时间戳, 可以通过系统命令date -d @1646294691.502 将其转换为时间格式。
为了避免服务器系统时间不同导致DTM Server切换时间长,建议在所有SQLNode物理机器上配置NTP进行时间同步。
DTM 2PC事务
2PC将事务的提交分为2个阶段,先prepare,prepare成功之后commit。GreatDB cluster分布式事务2PC提交顺序为DTM prepare、XA prepare、DTM commit、XA commit,XA prepare成功之后XA commit必然成功,因此DTM commit成功之后分布式事务必然能成功提交,所以我们在DTM commit成功之后将事务提交成功返回给客户端,后台异步执行XA commit,给用户更快的事务提交体验。
XA recover
XA recover为后台处理线程,来处理异常的2PC事务。XA recover线程与DTM server在同一个SQLNode中,作为一个后台线程进行工作,每隔xa_recover_interval秒进行一次异常事务监控。
2PC事务prepare成功之后进入prepared状态,当事务涉及到多个shard,只有所有shard的事务都prepare成功进入prepared状态,事务才可以commit。当2PC事务prepared阶段之后有shard内的DataNode连接丢失,事务会进入pending状态,XA recover来处理丢失连接的pending状态事务。
测试Q&A
- DTM server故障发现机制?
DTM server依赖SQLNode故障发现机制,当SQLNode退出MGR集群时,会触发其他online的SQLNode抢占DTM server task,来选取新的DTM server。
DTM故障发现机制与SQLNode故障发现机制是紧绑定的,只有SQLNode退出MGR集群会触发DTM server的切换。单纯的DTM内部故障不会触发SQLNode离开MGR集群,也就不会触发DTM server切换;
由于DTM故障发现机制依赖SQLNode故障发现机制,故DTM从故障感知到完成切换并没有一个单独的时间指标;
切换过程中新的DTM server故障,如果是网络原因导致并且新DTM server所属的SQLNode离开MGR集群,会触发新一轮的DTM切换,否则不会触发新一轮DTM server切换。
- DTM Server切换耗时较长问题如何分析?
首先确认切换前后的DTM Server物理机器是否存在时间差,如果后一个DTM Server时间小于前一个DTM Server时间,请先进行时间同步再进行测试;如果不存在时间差,通过sqlnode的error日志和dtm日志进行分析。




