暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

MySQL 【主从模式(二)】基于全局事务标识符的复制

IT的世界 2025-02-26
6

在上次分享学习中MySQL 【主从模式(一)】基于binlog文件位置的复制,我们了解了MySQL主从复制的概念、作用、原理,以及基于binlog文件位置的复制方法。
在MySQL 5.6 中提供了更加安全与简便的复制方法——基于GTID(全局事务标识符)的复制。

GTID的定义、创建与呈现

定义:GTID,全局事务标识符,与源服务器上每个已提交事务相关联的唯一标识符,不仅在源服务器上唯一,在给定的复制拓扑结构的服务器中也是唯一的。

创建:在源服务器上,当一个事务被提交,并且被写入binlog中,则会为这个事务分配一个GTID。

呈现:GTID使用一对坐标进行表示,形如GTID = source_id:transaction_id

source_id:用来标识源服务器,通常使用源服务器的server_uuid表示;
transaction_id:事务在源服务器上被提交的顺序值。
例如:3E11FA47-71CA-11E1-9E33-C80AA9429562:23
,表示UUID为3E11FA47-71CA-11E1-9E33-C80AA9429562的源服务器上第23个被提交的事务。

GTID的呈现还包括如下的集合形式:
3E11FA47-71CA-11E1-9E33-C80AA9429562:1-3:11:47-49
:源自同一服务器的多个单个 GTID 或 GTID 范围;
2174B383-5441-11E8-B90A-C80AA9429562:1-3, 24DA167-0C0C-11E8-8442-00059A3C7B00:1-19
:来自不同服务器的 GTID;

mysql.gtid_executed 
:
git_mode
ON
或者ON_PERMISSIVE
的情况下,GTID被保存在mysql.git_executed表中。
在执行完reset master;
命令后,mysql.git_execued表会被清空

当开启了binlog,mysql.git_execued保存的不是所有事务完整的GTID记录
,要查询完整记录可以使用 @@GLOBAL.gtid_executed全局变量

为了节约空间,mysql.gtid_executed 会通过可控的频率进行压缩。

GTID的生命周期

  1. 1. 事务在源服务器上执行并提交
    :GTID被写入源服务器的binlog。如果事务未写入binlog,则不会为其分配GTID
  2. 2. 当binlog轮换或者服务器关闭
    时,binlog文件中的GTID被写入到mysql.gtid_executed
    表中;
  3. 3. 事务提交后不久
    ,GTID被添加到全局系统变量gtid_executed
    ( @@GLOBAL.gtid_executed)中。该变量包含所有已提交的GTID事务集
    。在复制中用来表示服务器状态的令牌。
  4. 4. 当binlog传输到副本并存储到其中继日志中
    后,副本将读取GTID并将其系统变量 gtid_next 设置为该值
    。该变量告诉副本必须使用这个GTID记录下一个事务。
  5. 5. 副本会验证是否有线程占有该GTID
    。在处理该事务前,会验证之前的事务使用已经应用了该GTID,也会验证没有其他的会话读取了该GTID但还未提交。如果有多个客户端尝试并发执行相同的事务,会保证只有一个成功。如果GTID已经被使用,会使用自动跳过功能忽略该功能。
  6. 6. 如果GTID未被使用,副本会复制事务(不会重新生成新的GTID)。
  7. 7. 如果副本开启了binlog
    ,GTID会在提交时以原子方式进行持久化,通过在事务开始时写入到binlog中
    。当binlog轮换或者服务器关闭时,binlog文件中的GTID被写入到mysql.gtid_executed表中。
  8. 8. 如果副本未开启binlog
    ,GTID通过直接写入到mysql.gtid_executed表中进行原子方式持久化
    。在这种情况下,mysql.gtid_executed表是事务的完整记录。
  9. 9. 在事务提交后不久
    ,GTID通过非原子方式外部化,通过将其加入到全局系统变量gtid_executed
    ( @@GLOBAL.gtid_executed)中。

GTID自动定位

使用基于binlog文件位置的复制,在使用CHANGE MASTER TO
语句时,需要指定MASTER_LOG_FILE
或者MASTER_LOG_POS
选项,用来指定日志文件及其开始复制的位置。
而基于GTID的复制,不需要指定这两个选项,只需要开启MASTER_AUTO_POSITION
,就会激活自动定位连接到源。

自动定位的原理:
在初始握手中,副本会向源服务器发送一个GTID集合
(该集合包括副本收到的和已经提交的事务的集合);
源服务器
在收到副本发来的GTID集合后,会向副本发送其binlog 中的所有的事务(排除了副本发来的GTIDs)

  • • 当需要发送给副本的事务已经从源服务器的binlog中清除
    ,或者通过其他方法添加到系统变量gtid_purged
    中,则源服务器会向副本发送错误,副本不会启动
    ,且不会自动从该错误中恢复过来
    。 处理这种情况,一般需要副本从存在缺失事务的另一个源中复制事务或者重构整个主从
  • • 如果副本发送的GTIDs包含源服务器UUID的事务,但源服务器本身没有这些记录(即副本的事务超前于源
    )。
    这种情况下通常发生在源服务器为设置sync_binlog=1
    而发生了系统崩溃,导致事务未同步到binlog,但已被副本接收。
    处理这种情况,首先要判断源与副本是否出现了分歧(不同事务使用的相同是GTID)
    ,手动处理分歧或者停掉主从,重构。 如果没有分歧,这可以将源变成副本,待同步结束,再变成源。

基于GTID的复制的一般步骤

假设最简单的主从结构(一主一从),两者基于binlog位置配置了主从关系,且可以随时停止的它们。

在上述前提下配置基于GTID的复制(冷配置):

  • • 源与副本服务器都设置为只读,等同步完成。
    mysql> SET @@GLOBAL.read_only = ON;
  • • 停止源与副本服务器,正确配置选项重启服务器。
    $> mysqladmin -uusername -p shutdown;

    gtid_mode=ON

    enforce-gtid-consistency=ON
  • • 将副本服务器指向源服务器并使用自动定位.
    mysql> CHANGE MASTER TO MASTER_HOST = host, MASTER_PORT = port,MASTER_USER = user,MASTER_PASSWORD = password, MASTER_AUTO_POSITION = 1;
  • • 进行新的备份。启用GTID后,之前的备份数据将无法在这些服务器上使用,需要重新备份。
  • • 将两个服务器的只读禁止,接受更新请求。
    mysql> START SLAVE;

    mysql> SET @@GLOBAL.read_only = OFF;

当源服务器已经开启GTID,并处理了大量的事务,存在了大量的数据,配置新的副本的方法:

  • • 在新服务器上重现所有的标识符和事务最简单的方法是将该服务器设置为包含所有执行历史
    的服务器的副本,并在两个服务器上都开启GTID;
  • • 将源服务器上的数据集、binlog和全局事务信息的快照导入到新副本上
    。该方法可以减少新副本同步数据的时间。
    具体的生成快照并导入到副本上的方法,应情况不同而不同,具体的方法下一次学习具体分享。

基于GTID的复制的局限与限制

  • • 使用非事务引擎(例如MyISAM)更新不能与使用事务引擎(例如InnoDB)的更新混合
    ,这将导致同一个事务被分配多个GTID
  • • CREATE TABLE ... SELECT 
    语句不能使用。当binlog_format的值不同,该语句被分配事务的情况不同,如果源与副本的binlog_format值不同,会导致无法正确处理事务
  • • CREATE TEMPORARY TABLE 和DROP TEMPORARY TABLE
    在事务、存储过程、函数和触发器中不支持。只可以在事务外使用
  • • 为了防止不受支持的语句导致复制失败,所有服务器启动都必须开启 `--enforce-gtid-consistency ``
  • • 不支持sql_slave_skip_counter
    ,使用修改 gtid_executed 
    的值替代
  • • IGNORE_SERVER_IDS
     选项CHANGE MASTER TO
    弃用,因为已应用的事务会被自动忽略
  • • 使用mysqldump生成的转储导入启用了 GTID 模式的 MySQL 服务器,需要保证目标服务器的二进制日志中没有 GTID。
  • • 不要通过mysql_upgrade (--write-binlog 选项) 
    启用二进制日志记录

分配GTID的情况

• 每个写入到binlog中的数据库变更额操作(DDL或DML)都会分配一个GTID。
• 非事务性更新与事务性更新都会分配GTID,在非事务性更新中,如果在尝试写入binlog缓存发生磁盘写入失败,导致binlog出现间隙,该日志事件也会分配GTID。
• 当binlog中生成语句自动删除表时,会为该语句分配GTID。
• 若事务未写入源服务器的binlog,不会为其分配GTID。
• XA事务会为事务的不同阶段单独分配GTID。
• 以下单个语句会分配多个GTID:调用存储过程提交多事务;多表删除语句删除不同类型的表; 在基于行复制的情况下CREATE TABLE ... SELECT
语句。

既然已经看到这里,请随手点个赞和“在看”吧。

欢迎关注我的公众号“IT的世界”,原创技术文章第一时间推送.


文章转载自IT的世界,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论