MySQL事务--两阶段提交
MySQL事务协调器
MySQL支持多种存储引擎,并在MySQL Server层实现Binlog机制来进行主从数据同步。每种存储引擎相互独立,使用不同的数据文件和日志文件,当MySQL实例内部一个事务涉及到多个事务存储引擎表时,需要使用2PC来保证数据一致性。
## 文件sql\mysqld.cc
static int init_server_components() {
tc_log = &tc_log_dummy;
if (total_ha_2pc > 1 || (1 == total_ha_2pc && opt_bin_log)) {
if (opt_bin_log)
tc_log = &mysql_bin_log;
else
tc_log = &tc_log_mmap;
}
}
## 等价于
static int init_server_components() {
tc_log = &tc_log_dummy;
if (total_ha_2pc > 0 && opt_bin_log) {
tc_log = &mysql_bin_log;
}
if (total_ha_2pc > 1 && !opt_bin_log) {
tc_log = &tc_log_mmap;
}
}
- 默认使用tc_log_dummy来作为事务协调者
- 当事务引擎超过1个且开启Binlog,则使用binlog来作为事务协调者。
- 当事务引擎大于1个且未开启binlog,则使用tc_log_mmap作为事务协调者。
无论tc_log_dummy还是Binlog或tc_log_mmap都基于TC_LOG这个基类来实现:
class TC_LOG {
public:
virtual int open(const char *opt_name) = 0;
virtual void close() = 0;
virtual enum_result commit(THD *thd, bool all) = 0;
virtual int rollback(THD *thd, bool all) = 0;
virtual int prepare(THD *thd, bool all) = 0;
};
tc_log_dummy是一个空实现,不会记录事务日志。
tc_log_mmap是一个标准的事务协调者实现,它会创建一个名为 tc.log
的日志并使用操作系统的内存映射(memory-map,mmap)机制将内容映射到内存中。tc.log
文件中分为一个一个 PAGE,每个 PAGE 上有多个XID。
binlog同样基于TC_LOG来实现事务协调者功能,会递增生成mysql-binlog.xxxxx的文件,每个文件中包含多个事务产生的binlog event,并在binlog event中包含XID。
tc_log_mmap和binlog都基于XID来确定事务是否已提交。
InnoDB事务存储引擎
MySQL存储引擎会在初始化时将相应方法注册到MySQL Server层,以InnoDB事务存储引擎为例,在初始化时会注册prepare、commit、rollback、recover等函数到MySQL Server层,供事务协调者调用。
## 文件 storage\innobase\handler\ha_innodb.cc
/** Initialize the InnoDB storage engine plugin.
@param[in,out] p InnoDB handlerton
@return error code
@retval 0 on success */
static int innodb_init(void *p) {
handlerton *innobase_hton = (handlerton *)p;
innodb_hton_ptr = innobase_hton;
innobase_hton->commit = innobase_commit;
innobase_hton->rollback = innobase_rollback;
innobase_hton->prepare = innobase_xa_prepare;
innobase_hton->recover = innobase_xa_recover;
}
在使用Binlog作为事务协调器的2PC过程中:
- 在prepare阶段,使用MYSQL_BIN_LOG::prepare调用InnoDB存储引擎的innobase_xa_prepare方法,将InnoDB的事务日志Redo Log持久化。
- 在Commit阶段,使用MYSQL_BIN_LOG::commit先将Binlog日志进行持久化,然后调用innobase_commit方法,将事务在InnoDB存储引擎层进行提交。
MySQL两阶段提交
无论时MySQL 外部XA事务还是内部XA事务,都需要通过两阶段事务提交2PC的方式来保证数据一致性。在大部分的使用场景中,都会开启MySQL Binlog来进行主从数据同步,同时InnoDB事务存储引擎成为主流选择,因此在讨论MySQL两阶段提交时更多的会关注在MySQL Server层的Binlog日志和InnoDB事务日志(Redo Log)。