mysql 5.7 缺点_MySQL · 特性分析 · MySQL 5.7 外部XA Replication实现及缺陷分析

MySQL 5.7 外部XA Replication实现及缺陷分析

MySQL 5.7增强了分布式事务的支持,解决了之前客户端退出或者服务器关闭后prepared的事务回滚和服务器宕机后binlog丢失的情况。

为了解决之前的问题,MySQL5.7将外部XA在binlog中的记录分成了两部分,使用两个GTID来记录。执行prepare的时候就记录一次binlog,执行commit/rollback再记录一次。由于XA是分成两部分记录,那么XA事务在binlog中就可能是交叉出现的。Slave端的SQL线程在apply的时候需要能够在这些不同事务间切换。

但MySQL XA Replication的实现只考虑了Innodb一种事务引擎的情况,当添加其他事务引擎的时候,原本的一些代码逻辑就会有问题。同时MySQL源码中也存在宕机导致主备不一致的缺陷。

MySQL 5.7 外部XA Replication源码剖析

Master写入

当执行 XA START ‘xid’后,内部xa_state进入XA_ACTIVE状态。

bool Sql_cmd_xa_start::trans_xa_start(THD *thd)

{

xid_state->set_state(XID_STATE::XA_ACTIVE);

第一次记录DML操作的时候,通过下面代码可以看到,对普通事务在binlog的cache中第一个event记录’BEGIN’,如果是xa_state处于XA_ACTIVE状态就记录’XA START xid’,xid为序列化后的。

static int binlog_start_trans_and_stmt(THD *thd, Log_event *start_event)

{

if (cache_data->is_binlog_empty())

{

if (is_transactional && xs->has_state(XID_STATE::XA_ACTIVE))

{

/*

XA-prepare logging case.

*/

qlen= sprintf(xa_start, "XA START %s", xs->get_xid()->serialize(buf));

query= xa_start;

}

else

{

/*

Regular transaction case.

*/

query= begin;

}

Query_log_event qinfo(thd, query, qlen,

is_transactional, false, true, 0, true);

if (cache_data->write_event(thd, &qinfo))

DBUG_RETURN(1);

XA END xid的执行会将xa_state设置为XA_IDLE。

bool Sql_cmd_xa_end::trans_xa_end(THD *thd)

{

xid_state->set_state(XID_STATE::XA_IDLE);

当XA PREPARE xid执行的时候,binlog_prepare会通过检查thd的xa_state是否处于XA_IDLE状态来决定是否记录binlog。如果在对应状态,就会调用MYSQL_BINLOG的commit函数,记录’XA PREPARE xid’,将之前cache的binlog写入到文件。

static int binlog_prepare(handlerton *hton, THD *thd, bool all){

DBUG_RETURN(all && is_loggable_xa_prepare(thd) ?

mysql_bin_log.commit(thd, true) : 0);

inline bool is_loggable_xa_prepare(THD *thd){

return DBUG_EVALUATE_IF("simulate_commit_failure",

false,

thd->get_transaction()->xid_state()->

has_state(XID_STATE::XA_IDLE));

TC_LOG::enum_result MYSQL_BIN_LOG::commit(THD *thd, bool all)

{

if (is_loggable_xa_prepare(thd))

{

XID_STATE *xs= thd->get_transaction()->xid_state();

XA_prepare_log_event end_evt(thd, xs->get_xid(), one_phase);

err= cache_mngr->trx_cache.finalize(thd, &end_evt, xs)

}

当XA COMMIT/ROLLBACK xid执行时候,调用do_binlog_xa_commit_rollback记录’XA COMMIT/ROLLBACK xid’。

TC_LOG::enum_result MYSQL_BIN_LOG::commit(THD *thd, bool all)

{

if (thd->lex->sql_command == SQLCOM_XA_COMMIT)

do_binlog_xa_commit_rollback(thd, xs->get_xid(),

true)))

int MYSQL_BIN_LOG::rollback(THD *thd, bool all)

{

if (thd->lex->sql_command == SQLCOM_XA_ROLLBACK)

if ((error= do_binlog_xa_commit_rollback(thd, xs->get_xid(), false)))

由于XA PREPARE单独记录binlog,那么binlog中的events一个xa事务就可能是分隔开的。举个例子,session1中xid为’a’的分布式事务执行xa prepare后,session2中执行并提交了xid为’z’的事务,然后xid ‘a’才提交。我们可以看到binlog events中xid ‘z’的events在’a’的prepare和commit之间。

session1:

xa start 'a'; insert into t values(1);

xa end 'a';

xa prepare 'a';

session2:

xa start 'z'; insert into t valu

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值