Mysql 5.7中Gtid和Last

63次阅读
没有评论

共计 6421 个字符,预计需要花费 17 分钟才能阅读完成。

本篇内容主要讲解“Mysql 5.7 中 Gtid 和 Last_commt/sequnce_number 的生成时机是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让丸趣 TV 小编来带大家学习“Mysql 5.7 中 Gtid 和 Last_commt/sequnce_number 的生成时机是什么”吧!

一、Gtid 生成类型

这里首先使用源码的解释给出三种类型:

AUTOMATIC_GROUP

GTID_GROUP

ANONYMOUS_GROUP

其中 AUTOMATIC_GROUP 通常用于主库开启 Gtid 的情况,GTID_GROUP 通常用于备库和使用了 GTID_NEXT 的情况下。

源码中有详细解释如下:

 /**
 Specifies that the GTID has not been generated yet; it will be
 generated on commit. It will depend on the GTID_MODE: if
 GTID_MODE =OFF_PERMISSIVE, then the transaction will be anonymous;
 if GTID_MODE =ON_PERMISSIVE, then the transaction will be assigned
 a new GTID.
 This is the default value: thd- variables.gtid_next has this state
 when GTID_NEXT= AUTOMATIC .
 It is important that AUTOMATIC_GROUP==0 so that the default value
 for thd- variables- gtid_next.type is AUTOMATIC_GROUP.
 */
 AUTOMATIC_GROUP= 0,
 /**
 Specifies that the transaction has been assigned a GTID (UUID:NUMBER).
 thd- variables.gtid_next has this state when GTID_NEXT= UUID:NUMBER .
 This is the state of GTID-transactions replicated to the slave.
 */
 GTID_GROUP,
 /**
 Specifies that the transaction is anonymous, i.e., it does not
 have a GTID and will never be assigned one.
 thd- variables.gtid_next has this state when GTID_NEXT= ANONYMOUS .
 This is the state of any transaction generated on a pre-GTID
 server, or on a server with GTID_MODE==OFF.
 */
ANONYMOUS_GROUP

二、Gtid 和 Last_commt/sequnce_number 的生成时机

Gtid 其实是在 commit 的时候调用 MYSQL_BIN_LOG::ordered_commit 执行到 flush 阶段产生 Gtid event 的时候才生成,生成后会将这个 Gtid 加入到 Gtid_state 的 Owned_gtids 中,实际上这个过程不仅要生成 Gtid 还会生成 sequence_number 和 last_commit 并且会构造 Gtid_event 写入到 binlog cache 最后将 binlog cache 写入到 binlog file,下面是 binlog_cache_data::flush 函数的片段:

if (!error)
 if ((error= mysql_bin_log.write_gtid(thd, this,  writer))) // 生成 Gtid 和 Last_commt/sequnce_number 构造好 Gtid event 并且写入到到 binlog cache 中
 thd- commit_error= THD::CE_FLUSH_ERROR;
if (!error)
 error= mysql_bin_log.write_cache(thd, this,  writer); // 将 binlog cache 写入到文件 

下面是 mysql_bin_log.write_gtid 中生成 Gtid 和 Last_commt/sequnce_number 的代码片段:

 if (thd- variables.gtid_next.type == AUTOMATIC_GROUP)// 如果过是非指定的 Gtid 则需要自动生成调用 generate_automatic_gtid 生成
 {
 if (gtid_state- generate_automatic_gtid(thd,
 thd- get_transaction()- get_rpl_transaction_ctx()- get_sidno(),
 thd- get_transaction()- get_rpl_transaction_ctx()- get_gno())
 != RETURN_STATUS_OK)
 DBUG_RETURN(true);
 }
.....
// 下面生成 sequence_number 和 last_committed
 int64 relative_sequence_number= trn_ctx- sequence_number - clock.get_offset();
 int64 relative_last_committed=
 trn_ctx- last_committed  = clock.get_offset() ?
 SEQ_UNINIT : trn_ctx- last_committed - clock.get_offset();

其调用栈帧如下:

#0 Gtid_state::get_automatic_gno (this=0x2ff8bb0, sidno=1) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/rpl_gtid_state.cc:564
#1 0x0000000001803248 in Gtid_state::generate_automatic_gtid (this=0x2ff8bb0, thd=0x7fff2c000b70, specified_sidno=0, specified_gno=0)
 at /root/mysql5.7.14/percona-server-5.7.14-7/sql/rpl_gtid_state.cc:628
#2 0x0000000001845703 in MYSQL_BIN_LOG::write_gtid (this=0x2dffc80, thd=0x7fff2c000b70, cache_data=0x7fff2c021178, writer=0x7ffff0358810)
 at /root/mysql5.7.14/percona-server-5.7.14-7/sql/binlog.cc:1167
#3 0x0000000001846307 in binlog_cache_data::flush (this=0x7fff2c021178, thd=0x7fff2c000b70, bytes_written=0x7ffff03588b8, wrote_xid=0x7ffff0358917)
 at /root/mysql5.7.14/percona-server-5.7.14-7/sql/binlog.cc:1454
#4 0x0000000001860e57 in binlog_cache_mngr::flush (this=0x7fff2c020ff0, thd=0x7fff2c000b70, bytes_written=0x7ffff0358918, wrote_xid=0x7ffff0358917)
 at /root/mysql5.7.14/percona-server-5.7.14-7/sql/binlog.cc:768
#5 0x0000000001856d46 in MYSQL_BIN_LOG::flush_thread_caches (this=0x2dffc80, thd=0x7fff2c000b70) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/binlog.cc:8470
#6 0x0000000001856f77 in MYSQL_BIN_LOG::process_flush_stage_queue (this=0x2dffc80, total_bytes_var=0x7ffff0358a88, rotate_var=0x7ffff0358a87, 
 out_queue_var=0x7ffff0358a78) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/binlog.cc:8532
#7 0x0000000001858593 in MYSQL_BIN_LOG::ordered_commit (this=0x2dffc80, thd=0x7fff2c000b70, all=false, skip_commit=false)

接下来我们就需要具体研究下一个 Gtid 是依靠什么逻辑生成的。我们需要查看函数 Gtid_state::generate_automatic_gtid 和 Gtid_state::get_automatic_gno 逻辑,他们用于生成一个 Gtid。

三、Gtid_state::generate_automatic_gtid 逻辑

 // If GTID_MODE = ON_PERMISSIVE or ON, generate a new GTID
 if (get_gtid_mode(GTID_MODE_LOCK_SID)  = GTID_MODE_ON_PERMISSIVE)// 如果 GTID_MODE 是 ON_PERMISSIVE 和 ON 则生成 GTID
 { Gtid automatic_gtid= { specified_sidno, specified_gno };
 if (automatic_gtid.sidno == 0)// 如果是备库则 sidno 0,如果是主库 sidno==0,因为主库的 Gtid 这个时候才生成,但是备库则是使用 GTID_GROUP 指定生成
 automatic_gtid.sidno= get_server_sidno();// 此处返回本 server 的 sidno
 lock_sidno(automatic_gtid.sidno);// 此处对并发生成 GNO 的多个线程进行控制
 if (automatic_gtid.gno == 0)// 如果是备库则 gno 0,如果是主库 gno == 0,因为主库的 Gtid 这个时候才生成,但是备库则是使用 GTID_GROUP 指定生成
 automatic_gtid.gno= get_automatic_gno(automatic_gtid.sidno);// 此处返回最后指定 sidno 的 end gno
 if (automatic_gtid.gno != -1)
 acquire_ownership(thd, automatic_gtid);// 此处将这个 gtid  及上面的 SIDNO:gno 加入到 owned_gtids 中   并且赋予给线程   经过本步骤   可以显示
 else
 ret= RETURN_STATUS_REPORTED_ERROR;
 unlock_sidno(automatic_gtid.sidno);// 分配完成其他线程可以分配
 }
 else // 如果是 OFF_PERMISSIVE 或者 OFF 状态如何处理   这里不做讨论了
 {
 // If GTID_MODE = OFF or OFF_PERMISSIVE, just mark this thread as
 // using an anonymous transaction.
 thd- owned_gtid.sidno= THD::OWNED_SIDNO_ANONYMOUS;
 thd- owned_gtid.gno= 0;
 acquire_anonymous_ownership();
 thd- owned_gtid.dbug_print(NULL,
  set owned_gtid (anonymous) in generate_automatic_gtid 
 }
 sid_lock- unlock();// 释放读写锁 

接下来看看 gno 的生成逻辑 Gtid_state::get_automatic_gno。

四、Gtid_state::generate_automatic_gtid 逻辑

while (true)
 { const Gtid_set::Interval *iv= ivit.get(); // 定义 Interval 指针指向   这个链表指针开头, 如果在进行下次循环会获得 NULL
 rpl_gno next_interval_start= iv != NULL ? iv- start : MAX_GNO; // 正常情况下不会为 NULL 因此  next_interval_start  等于第一个 interval 的 start,当然如果初始化会为 NULL, // 如果 Interval- next =NULL  则标示没有区间了。 while (next_candidate.gno   next_interval_start  
 DBUG_EVALUATE_IF(simulate_gno_exhausted , false, true)) // 这里 next_candidate.gno 正常不会小于 next_interval_start ,如果 Interval- next =NULL 或者初始化
 //next_interval_start 会被制为 MAX_GNO 那么条件成立  
 //DBUG_RETURN(next_candidate.gno); 返回了这个 gno  则 GTID 生成
 { if (owned_gtids.get_owner(next_candidate) == 0) // 如果本 GTID 已经被其他线程占用则 next_candidate.gno++; 返回这个 gno。 DBUG_RETURN(next_candidate.gno);
 next_candidate.gno++;
 }
 if (iv == NULL ||
 DBUG_EVALUATE_IF(simulate_gno_exhausted , true, false))
 { my_error(ER_GNO_EXHAUSTED, MYF(0));
 DBUG_RETURN(-1);
 }
 next_candidate.gno= iv-  //iv- end  则指向了本区间最大的值 +1
 ivit.next();
 }

到此,相信大家对“Mysql 5.7 中 Gtid 和 Last_commt/sequnce_number 的生成时机是什么”有了更深的了解,不妨来实际操作一番吧!这里是丸趣 TV 网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-07-20发表,共计6421字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)