MySQL高可用与集群之:`GTID`(`Global Transaction ID`):其在主从切换和故障恢复中的作用。

MySQL高可用与集群之:GTID在主从切换和故障恢复中的作用

大家好,今天我们来深入探讨MySQL高可用与集群中一个至关重要的概念:GTID(Global Transaction ID),以及它在主从切换和故障恢复中的作用。GTID为MySQL复制提供了一种更加可靠和易于管理的方式,极大地简化了高可用集群的维护工作。

1. 什么是GTID?

传统基于binlog文件和position的复制方式,在主从切换和故障恢复时,需要手动查找合适的binlog文件和position点,容易出错且耗时。GTID的出现,就是为了解决这个问题。

GTID(Global Transaction ID)是一个全局唯一的事务ID。它由两部分组成:

  • source_id: 产生该事务的服务器的UUID。每个MySQL服务器都有一个唯一的UUID。
  • transaction_id: 在该服务器上产生的事务序列号。

因此,GTID的格式为 source_id:transaction_id, 例如:3E11FA47-71CA-11E1-9E33-C80AA9429562:12345

2. GTID的工作原理

当开启GTID后,每个在主服务器上执行的事务都会被分配一个唯一的GTID。这个GTID会被记录在binlog中,并随着binlog传输到从服务器。从服务器在执行该事务时,也会记录下该GTID。

这样,每个事务都被唯一标识,无论它在哪个服务器上执行。从服务器可以根据GTID来判断是否已经执行过某个事务,从而避免重复执行。

3. GTID的优势

相比于传统的基于binlog文件和position的复制方式,GTID具有以下优势:

  • 简化主从切换和故障恢复: 不需要手动查找binlog文件和position,只需要指定新的主服务器即可。
  • 提高复制的可靠性: 避免重复执行事务,保证数据的一致性。
  • 简化复制拓扑管理: 更容易构建复杂的复制拓扑,例如多主复制和环形复制。
  • 自动跳过已执行的事务: 从服务器可以自动跳过已经执行过的事务,例如在主服务器上执行了某些事务后,从服务器宕机,恢复后可以自动从上次中断的位置继续复制。

4. 如何启用GTID

要启用GTID,需要在MySQL的配置文件(通常是my.cnfmy.ini)中添加以下配置:

[mysqld]
gtid_mode = ON
enforce_gtid_consistency = ON
log_slave_updates = ON
server_id = 1  # 主服务器的server_id,确保唯一
binlog_format = ROW # 推荐使用ROW格式
relay_log_recovery = ON # 建议开启,保证relay log的一致性

解释一下这些参数:

  • gtid_mode = ON: 启用GTID。
  • enforce_gtid_consistency = ON: 强制GTID一致性,防止在没有GTID的情况下执行事务。这是非常重要的设置,可以保证数据的一致性。
  • log_slave_updates = ON: 允许从服务器将接收到的更新写入自己的binlog。这对于级联复制非常重要。
  • server_id = 1: 设置服务器ID,每个服务器的ID必须唯一。
  • binlog_format = ROW: 推荐使用ROW格式的binlog,可以更准确地记录数据的变化。
  • relay_log_recovery = ON: 启用中继日志恢复,防止从服务器崩溃后数据丢失。

重要提示:

  • 在启用GTID之前,建议备份数据。
  • 在启用GTID后,需要重启MySQL服务器。
  • 从MySQL 5.7版本开始, gtid_mode=ON 隐含地设置了 log_bin=ON,也就是说,启用GTID必须启用二进制日志。在MySQL 8.0版本中,log_bin默认开启。

5. 主从切换中的GTID

假设我们有一个主服务器(A)和一个从服务器(B),我们要将从服务器(B)切换为主服务器。

以下是使用GTID进行主从切换的步骤:

  1. 停止主服务器(A)的写入操作: 避免在切换过程中产生新的事务。

    FLUSH TABLES WITH READ LOCK;
  2. 确定从服务器(B)已经同步了所有来自主服务器(A)的事务: 可以通过查看 SHOW SLAVE STATUS 的输出来确认。 关键指标是 Seconds_Behind_Master 是否为0。

    SHOW SLAVE STATUSG

    注意 Executed_Gtid_Set 字段,这个字段表示从服务器已经执行过的GTID集合。我们需要确保这个集合包含了主服务器上所有已经提交的GTID。
    也可以通过查询:

    SELECT GTID_SUBSET( ( SELECT @@GLOBAL.GTID_EXECUTED ), ( SELECT @@GLOBAL.GTID_EXECUTED FROM performance_schema.replication_connection_status WHERE CHANNEL_NAME='channel_0' ) );

    如果返回 1, 则表示从库已经同步了主库的所有事务.

  3. 停止从服务器(B)的复制线程:

    STOP SLAVE;
  4. 将从服务器(B)提升为主服务器: 不需要进行任何特殊的操作,因为GTID已经记录了所有的事务信息。

  5. 配置原来的主服务器(A)成为新的从服务器:

    • 修改原来的主服务器(A)的配置文件,设置 server_id 为一个新的值,例如 2。
    • 启动原来的主服务器(A)。
    • 在原来的主服务器(A)上执行以下命令,将其配置为新的从服务器:

      STOP SLAVE;
      RESET SLAVE ALL; -- 非常重要,清空之前的复制信息
      CHANGE MASTER TO
          MASTER_HOST='new_master_ip',
          MASTER_USER='replication_user',
          MASTER_PASSWORD='replication_password',
          MASTER_AUTO_POSITION=1; -- 启用GTID自动定位
      START SLAVE;
      • MASTER_AUTO_POSITION=1:这是GTID的关键,它告诉从服务器使用GTID自动定位复制的起始位置,不需要手动指定binlog文件和position。

代码示例:主从切换脚本(简化版)

#!/bin/bash

# 主服务器信息
OLD_MASTER_HOST="192.168.1.100"
OLD_MASTER_USER="root"
OLD_MASTER_PASSWORD="password"

# 新的主服务器信息 (原从服务器)
NEW_MASTER_HOST="192.168.1.101"
NEW_MASTER_USER="root"
NEW_MASTER_PASSWORD="password"

# 新的从服务器信息 (原主服务器)
NEW_SLAVE_HOST="192.168.1.100"
NEW_SLAVE_USER="root"
NEW_SLAVE_PASSWORD="password"
NEW_SLAVE_SERVER_ID="2"

# 1. 停止旧主服务器的写入
echo "Stopping writes on old master..."
mysql -h $OLD_MASTER_HOST -u $OLD_MASTER_USER -p$OLD_MASTER_PASSWORD -e "FLUSH TABLES WITH READ LOCK;"

# 2. 检查新主服务器的同步状态 (简化版,需要手动确认)
echo "Checking replication status on new master (was slave)..."
mysql -h $NEW_MASTER_HOST -u $NEW_MASTER_USER -p$NEW_MASTER_PASSWORD -e "SHOW SLAVE STATUSG"

# 3. 停止新主服务器的复制
echo "Stopping slave on new master..."
mysql -h $NEW_MASTER_HOST -u $NEW_MASTER_USER -p$NEW_MASTER_PASSWORD -e "STOP SLAVE;"

# 4.  配置旧主服务器成为新的从服务器
echo "Configuring old master as new slave..."
mysql -h $NEW_SLAVE_HOST -u $NEW_SLAVE_USER -p$NEW_SLAVE_PASSWORD -e "
    STOP SLAVE;
    RESET SLAVE ALL;
    CHANGE MASTER TO
        MASTER_HOST='$NEW_MASTER_HOST',
        MASTER_USER='$NEW_MASTER_USER',
        MASTER_PASSWORD='$NEW_MASTER_PASSWORD',
        MASTER_AUTO_POSITION=1;
    START SLAVE;
"

# 5. 解锁旧的主服务器
echo "Unlocking old master..."
mysql -h $OLD_MASTER_HOST -u $OLD_MASTER_USER -p$OLD_MASTER_PASSWORD -e "UNLOCK TABLES;"

echo "主从切换完成!"

注意: 这个脚本只是一个简化版的示例,实际环境中需要进行更完善的错误处理和状态检查。 例如,需要检查 SHOW SLAVE STATUS 的输出,确认复制是否正常启动。 还应该添加重试机制,以应对网络故障等问题。

6. 故障恢复中的GTID

假设主服务器(A)发生故障,我们需要将从服务器(B)提升为主服务器。

以下是使用GTID进行故障恢复的步骤:

  1. 确认主服务器(A)已经彻底宕机: 避免脑裂问题。

  2. 将从服务器(B)提升为主服务器: 如前所述,不需要进行任何特殊的操作。

  3. 修复原来的主服务器(A):

    • 修改原来的主服务器(A)的配置文件,设置 server_id 为一个新的值。
    • 启动原来的主服务器(A)。
    • 在原来的主服务器(A)上执行以下命令,将其配置为新的从服务器:

      STOP SLAVE;
      RESET SLAVE ALL;
      CHANGE MASTER TO
          MASTER_HOST='new_master_ip',
          MASTER_USER='replication_user',
          MASTER_PASSWORD='replication_password',
          MASTER_AUTO_POSITION=1;
      START SLAVE;

7. GTID的注意事项

  • GTID只能用于InnoDB存储引擎: 如果使用MyISAM等其他存储引擎,需要进行转换。
  • 确保所有服务器的GTID模式一致: 所有服务器必须都启用GTID,并且 enforce_gtid_consistency 必须设置为 ON
  • 谨慎使用 RESET MASTER 命令: 在GTID模式下,RESET MASTER 会清除所有的GTID信息,可能导致数据不一致。 除非非常清楚其影响,否则不要使用该命令。 可以使用 RESET MASTER TO <N> 命令,将 auto_increment 的偏移量重置为指定值。
  • 监控GTID状态: 定期检查GTID的状态,例如 gtid_executedgtid_purged,确保复制正常运行。
  • 处理遗留的非GTID事务: 如果之前未使用GTID,需要将所有事务转换为GTID事务。可以使用 SET GTID_NEXT = 'AUTOMATIC' 来让MySQL自动分配GTID。

8. GTID相关状态变量

以下是一些与GTID相关的重要的状态变量:

变量名 描述
gtid_mode GTID模式的状态:OFFONOFF_PERMISSIVEON_PERMISSIVE
gtid_executed 服务器已经执行的GTID集合。
gtid_purged 服务器已经清除的GTID集合。
enforce_gtid_consistency 是否强制GTID一致性。
slave_preserve_commit_order 控制从库是否按照主库的提交顺序来执行事务,推荐开启,尤其是在多线程复制的情况下。

9. 总结:GTID让主从切换和故障恢复更简单

GTID通过全局唯一事务ID,极大地简化了MySQL主从切换和故障恢复的流程。它避免了手动查找binlog文件和position的繁琐操作,提高了复制的可靠性和易用性。 启用GTID后,主从切换和故障恢复变得更加自动化和可预测,降低了运维成本,提高了数据库系统的可用性。 务必按照最佳实践配置GTID,并定期监控其状态,以确保数据库集群的稳定运行。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注