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

3.1 半同步复制原理
- master 执行事务后,暂不提交,等待至少一个 slave 返回 ack。
- slave 的 io 线程接收 binlog 并写入 relay log 后,向 master 返回 ack。
- master 收到 ack 后提交事务,并向客户端返回成功。
- 若在超时时间内未收到 ack(默认 10 秒),自动降级为异步复制。
- 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 的简单工作流程
- 主库执行一个事务,提交后自动生成一个唯一的 gtid,记录到 binlog 里;
- 从库读取主库的 binlog,先记录这个 gtid(标记为 “已收到”);
- 从库执行这个事务,执行完后把 gtid 标记为 “已执行”;
- 主从同步时,从库只会向主库请求自己 “未执行” 的 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开启后

#停止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)

#开启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 最佳实践建议
- 生产环境推荐 gtid + 半同步组合使用,兼顾高可用与数据一致性。
- 设置合理的
rpl_semi_sync_master_timeout(如 5–10 秒),避免网络抖动影响写入。 - 监控
rpl_semi_sync_master_clients和rpl_semi_sync_master_status,及时发现半同步降级。 - 主从切换时,gtid 模式可大幅简化操作,无需手动找 position。
_commit| |gtid_mode| 是否开启 gtid | |enforce_gtid_consistency` | 强制 gtid 一致性,开启 gtid 时必须启用 |
3.6 最佳实践建议
- 生产环境推荐 gtid + 半同步组合使用,兼顾高可用与数据一致性。
- 设置合理的
rpl_semi_sync_master_timeout(如 5–10 秒),避免网络抖动影响写入。 - 监控
rpl_semi_sync_master_clients和rpl_semi_sync_master_status,及时发现半同步降级。 - 主从切换时,gtid 模式可大幅简化操作,无需手动找 position。
- 半同步降级为异步后,待从库恢复会自动切回,无需人工干预。
到此这篇关于mysql半同步复制与gtid实战指南的文章就介绍到这了,更多相关mysql半同步复制与gtid内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论