MySQL半同步复制与GTID实战详解

三、半同步复制与 GTID 实践笔记

3.1 半同步复制原理

  1. Master 执行事务后,暂不提交,等待至少一个 Slave 返回 ACK。
  2. Slave 的 IO 线程接收 Binlog 并写入 Relay Log 后,向 Master 返回 ACK。
  3. Master 收到 ACK 后提交事务,并向客户端返回成功。
  4. 若在超时时间内未收到 ACK(默认 10 秒),自动降级为异步复制。
  5. MySQL 5.6 使用 after_commit 模式(先提交再等 ACK),存在数据风险。MySQL 5.7+ 默认使用更安全的 AFTER_SYNC 模式。

3.2 gtid 模式

当为启用 gtid 时我们要考虑的问题

在 master 端的写入时多用户读写,在 slave 端的复制时单线程日志回放,所以 slave 端一定会延迟与 master 端

这种延迟在 slave 端的延迟可能会不一致,当 master 挂掉后 slave 接管,一般会挑选一个和 master 延迟日志最接近的充当新的 master

那么为接管 master 的主机继续充当 slave 角色并会指向到新的 master 上,作为其 slave

这时候按照之前的配置我们需要知道新的 master 上的 pos 的 id,但是我们无法确定新的 master 和 slave 之间差多

当激活 GITD 之后

当 master 出现问题后,slave2 和 master 的数据最接近,会被作为新的 master

slave1 指向新的 master,但是他不会去检测新的 master 的 pos id,只需要继续读取自己 gtid_next 即可

GTID 的简单工作流程

  1. 主库执行一个事务,提交后自动生成一个唯一的 GTID,记录到 binlog 里;
  2. 从库读取主库的 binlog,先记录这个 GTID(标记为 "已收到");
  3. 从库执行这个事务,执行完后把 GTID 标记为 "已执行";
  4. 主从同步时,从库只会向主库请求自己 "未执行" 的 GTID 对应的事务。

设置 gtid

#在master端和slave端开启gtid模式

复制代码
[root@mysql-node1 ~]# vim /etc/my.cnf
[mysqld]
datadir=/data/mysql
socket=/data/mysql/mysql.sock
server-id=1
log-bin=mysql-bin
gtid_mode=ON
enforce-gtid-consistency=ON
symbolic-links=0

[root@mysql-node1 ~]# /etc/init.d/mysqld restart
复制代码
[root@mysql-node2 ~]# vim /etc/my.cnf
[mysqld]
datadir=/data/mysql
socket=/data/mysql/mysql.sock
server-id=2
log-bin=mysql-bin
gtid_mode=ON
enforce-gtid-consistency=ON
symbolic-links=0

[root@mysql-node2 ~]# /etc/init.d/mysqld restart
复制代码
[root@mysql-node3 ~]# vim /etc/my.cnf
[mysqld]
datadir=/data/mysql
socket=/data/mysql/mysql.sock
server-id=3
log-bin=mysql-bin
gtid_mode=ON
enforce-gtid-consistency=ON
symbolic-links=0

三台主机全部执行 /etc/init.d/mysqld restart

#查看gtid状态

复制代码
mysql> show variables like '%gtid%';
+----------------------------------+-----------+
| Variable_name                    | Value     |
+----------------------------------+-----------+
| binlog_gtid_simple_recovery      | ON        |
| enforce_gtid_consistency         | ON        |
| gtid_executed                    |           |
| gtid_executed_compression_period | 0         |
| gtid_mode                        | ON        |
| gtid_next                        | AUTOMATIC |
| gtid_owned                       |           |
| gtid_purged                      |           |
| session_track_gtids              | OFF       |
+----------------------------------+-----------+
9 rows in set (0.01 sec)

gtid开启前

gtid开启后

bash 复制代码
#停止slave端
[root@mysql2 ~]# mysql -uroot -proot
mysql> stop slave;
Query OK, 0 rows affected (0.00 sec)

[root@mysql3 ~]# mysql -uroot -proot

mysql> stop slave;
Query OK, 0 rows affected (0.01 sec)
bash 复制代码
#开启slave端的gtid
mysql> CHANGE MASTER TO MASTER_HOST='172.25.254.10', MASTER_USER='swp', MASTER_PASSWORD='swp', MASTER_AUTO_POSITIO                                                 N=1;
Query OK, 0 rows affected, 7 warnings (0.01 sec)

mysql> start slave;
Query OK, 0 rows affected, 1 warning (0.01 sec)

mysql> show slave status\G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for source to send event
                  Master_Host: 172.25.254.10
                  Master_User: swp
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000003
          Read_Master_Log_Pos: 158
               Relay_Log_File: mysql3-relay-bin.000002
                Relay_Log_Pos: 375
        Relay_Master_Log_File: mysql-bin.000003
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
              Replicate_Do_DB:
          Replicate_Ignore_DB:
           Replicate_Do_Table:
       Replicate_Ignore_Table:
      Replicate_Wild_Do_Table:
  Replicate_Wild_Ignore_Table:
                   Last_Errno: 0
                   Last_Error:
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 158
              Relay_Log_Space: 587
              Until_Condition: None
               Until_Log_File:
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File:
           Master_SSL_CA_Path:
              Master_SSL_Cert:
            Master_SSL_Cipher:
               Master_SSL_Key:
        Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error:
               Last_SQL_Errno: 0
               Last_SQL_Error:
  Replicate_Ignore_Server_Ids:
             Master_Server_Id: 10
                  Master_UUID: 3f9a4795-332a-11f1-beae-000c29059db4
             Master_Info_File: mysql.slave_master_info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
      Slave_SQL_Running_State: Replica has read all relay log; waiting for more updates
           Master_Retry_Count: 10
                  Master_Bind:
      Last_IO_Error_Timestamp:
     Last_SQL_Error_Timestamp:
               Master_SSL_Crl:
           Master_SSL_Crlpath:
           Retrieved_Gtid_Set:
            Executed_Gtid_Set:
                Auto_Position: 1
         Replicate_Rewrite_DB:
                 Channel_Name:
           Master_TLS_Version:
       Master_public_key_path:
        Get_master_public_key: 0
            Network_Namespace:
1 row in set, 1 warning (0.00 sec)

3.3.启用半同步模式

在 master 端配置启用半同步模式

复制代码
[root@mysql-node1 ~]# vim /etc/my.cnf
[mysqld]
datadir=/data/mysql
socket=/data/mysql/mysql.sock
server-id=1
log-bin=mysql-bin
gtid_mode=ON
enforce-gtid-consistency=ON
rpl_semi_sync_master_enabled=1			#开启半同步功能
symbolic-links=0
复制代码
[root@mysql-node1 ~]# mysql -uroot -proot
#安装半同步插件
mysql> INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';

#查看插件情况
mysql> SELECT PLUGIN_NAME, PLUGIN_STATUS
    ->  FROM INFORMATION_SCHEMA.PLUGINS
    ->  WHERE PLUGIN_NAME LIKE '%semi%';
+----------------------+---------------+
| PLUGIN_NAME          | PLUGIN_STATUS |
+----------------------+---------------+
| rpl_semi_sync_master | ACTIVE        |
+----------------------+---------------+
1 row in set (0.01 sec)
复制代码
#打开半同步功能
mysql> SET GLOBAL rpl_semi_sync_master_enabled = 1;

#查看半同步功能状态
mysql> SHOW VARIABLES LIKE 'rpl_semi_sync%';
+-------------------------------------------+------------+
| Variable_name                             | Value      |
+-------------------------------------------+------------+
| rpl_semi_sync_master_enabled              | ON         |
| rpl_semi_sync_master_timeout              | 10000      |
| rpl_semi_sync_master_trace_level          | 32         |
| rpl_semi_sync_master_wait_for_slave_count | 1          |
| rpl_semi_sync_master_wait_no_slave        | ON         |
| rpl_semi_sync_master_wait_point           | AFTER_SYNC |
+-------------------------------------------+------------+

mysql> SHOW STATUS LIKE 'Rpl_semi_sync%';
+--------------------------------------------+-------+
| Variable_name                              | Value |
+--------------------------------------------+-------+
| Rpl_semi_sync_master_clients               | 0     |
| Rpl_semi_sync_master_net_avg_wait_time     | 0     |
| Rpl_semi_sync_master_net_wait_time         | 0     |
| Rpl_semi_sync_master_net_waits             | 0     |
| Rpl_semi_sync_master_no_times              | 0     |
| Rpl_semi_sync_master_no_tx                 | 0     |
| Rpl_semi_sync_master_status                | ON    |
| Rpl_semi_sync_master_timefunc_failures     | 0     |
| Rpl_semi_sync_master_tx_avg_wait_time      | 0     |
| Rpl_semi_sync_master_tx_wait_time          | 0     |
| Rpl_semi_sync_master_tx_waits              | 0     |
| Rpl_semi_sync_master_wait_pos_backtraverse | 0     |
| Rpl_semi_sync_master_wait_sessions         | 0     |
| Rpl_semi_sync_master_yes_tx                | 0     |
+--------------------------------------------+-------+
14 rows in set (0.00 sec)

在 slave 端开启半同步功能

复制代码
[root@mysql-slave和slave2都做 ~]# vim /etc/my.cnf
[mysqld]
datadir=/data/mysql
socket=/data/mysql/mysql.sock
server-id=1
log-bin=mysql-bin
gtid_mode=ON
enforce-gtid-consistency=ON
rpl_semi_sync_slave_enabled=1			#开启半同步功能
symbolic-links=0
复制代码
[root@mysql-slave和slave2都做# mysql -uroot -proot
mysql>  INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
Query OK, 0 rows affected (0.01 sec)

mysql> SET GLOBAL rpl_semi_sync_slave_enabled =1;
Query OK, 0 rows affected (0.00 sec)

mysql> STOP SLAVE IO_THREAD;			#重启io线程,半同步才能生效
Query OK, 0 rows affected (0.00 sec)


mysql> SHOW VARIABLES LIKE 'rpl_semi_sync%';
+---------------------------------+-------+
| Variable_name                   | Value |
+---------------------------------+-------+
| rpl_semi_sync_slave_enabled     | ON    |
| rpl_semi_sync_slave_trace_level | 32    |
+---------------------------------+-------+
2 rows in set (0.01 sec)

mysql>  SHOW STATUS LIKE 'Rpl_semi_sync%';
+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| Rpl_semi_sync_slave_status | ON    |
+----------------------------+-------+
1 row in set (0.00 sec)

3.4.测试

在 master 端写入数据

复制代码
mysql> insert into baibai.userlist values ('xixi','12340');
Query OK, 1 row affected (0.00 sec)

mysql> SHOW STATUS LIKE 'Rpl_semi_sync%';
+--------------------------------------------+-------+
| Variable_name                              | Value |
+--------------------------------------------+-------+
| Rpl_semi_sync_master_clients               | 2     |
| Rpl_semi_sync_master_net_avg_wait_time     | 0     |
| Rpl_semi_sync_master_net_wait_time         | 0     |
| Rpl_semi_sync_master_net_waits             | 4     |
| Rpl_semi_sync_master_no_times              | 1     |
| Rpl_semi_sync_master_no_tx  #未同步数据0笔  | 0     |
| Rpl_semi_sync_master_status                | ON    |
| Rpl_semi_sync_master_timefunc_failures     | 0     |
| Rpl_semi_sync_master_tx_avg_wait_time      | 633   |
| Rpl_semi_sync_master_tx_wait_time          | 633   |
| Rpl_semi_sync_master_tx_waits              | 1     |
| Rpl_semi_sync_master_wait_pos_backtraverse | 0     |
| Rpl_semi_sync_master_wait_sessions         | 0     |
| Rpl_semi_sync_master_yes_tx   #已同步数据1笔| 1     |
+--------------------------------------------+-------+

模拟故障:

复制代码
#在slave端
[root@mysql-slave2]# mysql -uroot -proot
mysql> STOP SLAVE IO_THREAD;
Query OK, 0 rows affected (0.00 sec)

[root@mysql-slave]# mysql -uroot -proot
mysql> STOP SLAVE IO_THREAD;
Query OK, 0 rows affected (0.00 sec)
复制代码
#在master端插入数据
mysql> insert  into lee.userlist values ('baibai','12340');
Query OK, 1 row affected (10.00 sec)			#10秒超时

mysql>  SHOW STATUS LIKE 'Rpl_semi%';
+--------------------------------------------+-------+
| Variable_name                              | Value |
+--------------------------------------------+-------+
| Rpl_semi_sync_master_clients               | 0     |
| Rpl_semi_sync_master_net_avg_wait_time     | 0     |
| Rpl_semi_sync_master_net_wait_time         | 0     |
| Rpl_semi_sync_master_net_waits             | 2     |
| Rpl_semi_sync_master_no_times              | 1     |
| Rpl_semi_sync_master_no_tx                 | 1     |		#一笔数据为同步
| Rpl_semi_sync_master_status                | OFF   |		#自动转为异步模式,当slave恢复
| Rpl_semi_sync_master_timefunc_failures     | 0     |		#会自动恢复
| Rpl_semi_sync_master_tx_avg_wait_time      | 981   |
| Rpl_semi_sync_master_tx_wait_time          | 981   |
| Rpl_semi_sync_master_tx_waits              | 1     |
| Rpl_semi_sync_master_wait_pos_backtraverse | 0     |
| Rpl_semi_sync_master_wait_sessions         | 0     |
| Rpl_semi_sync_master_yes_tx                | 1     |
+--------------------------------------------+-------+
14 rows in set (0.00 sec)

3.5 核心参数说明

参数 说明
rpl_semi_sync_master_enabled Master 是否启用半同步
rpl_semi_sync_slave_enabled Slave 是否启用半同步
rpl_semi_sync_master_timeout 等待 ACK 超时时间(毫秒),默认 10000
rpl_semi_sync_master_wait_for_slave_count 至少需要等待几个 Slave 返回 ACK
rpl_semi_sync_master_wait_point AFTER_SYNC(推荐) / AFTER_COMMIT
gtid_mode 是否开启 GTID
enforce_gtid_consistency 强制 GTID 一致性,开启 GTID 时必须启用

3.6 最佳实践建议

  1. 生产环境推荐 GTID + 半同步组合使用,兼顾高可用与数据一致性。
  2. 设置合理的 rpl_semi_sync_master_timeout(如 5--10 秒),避免网络抖动影响写入。
  3. 监控 Rpl_semi_sync_master_clientsRpl_semi_sync_master_status,及时发现半同步降级。
  4. 主从切换时,GTID 模式可大幅简化操作,无需手动找 position。
    _COMMIT | |gtid_mode | 是否开启 GTID | |enforce_gtid_consistency` | 强制 GTID 一致性,开启 GTID 时必须启用 |

3.6 最佳实践建议

  1. 生产环境推荐 GTID + 半同步组合使用,兼顾高可用与数据一致性。
  2. 设置合理的 rpl_semi_sync_master_timeout(如 5--10 秒),避免网络抖动影响写入。
  3. 监控 Rpl_semi_sync_master_clientsRpl_semi_sync_master_status,及时发现半同步降级。
  4. 主从切换时,GTID 模式可大幅简化操作,无需手动找 position。
  5. 半同步降级为异步后,待从库恢复会自动切回,无需人工干预。
相关推荐
SPC的存折2 小时前
openEuler 24.03 MariaDB Galera 集群部署指南(cz)
linux·运维·服务器·数据库·mysql
仲芒2 小时前
[24年单独笔记] MySQL 常用的 DML 命令
数据库·笔记·mysql
SPC的存折3 小时前
MySQL 8.0 分库分表
linux·运维·服务器·数据库·mysql
用户41659673693553 小时前
深度解码:记一次视频时间戳(PTS)异常导致的播放故障排查
android
大白菜和MySQL5 小时前
linux系统环境常用命令
android·linux·adb
翻斗包菜5 小时前
第 03 章 Python 操作 MySQL 数据库实战全解
数据库·python·mysql
Ehtan_Zheng5 小时前
彻底告别 AndroidX 依赖:如何在 KMP 中构建 100% 复用的 UI 逻辑层?
android
SPC的存折5 小时前
1、MySQL故障排查与运维案例
linux·运维·服务器·数据库·mysql
Hello小赵5 小时前
C语言如何自定义链接库——编译与调用
android·java·c语言