传统mysql主从在从库意外关机情况下,从库可能会失败,因此想将传统的mysql主从模式切换到Gtid模式下,测试下从库的健壮性。
本文,测试一下基于 mysql 8.0 版本,主从同步中,传统模式和 GTID 模式之间相互切换。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 --1)查看主从版本都是8.0 mysql> select version(); +-----------+ | version() | +-----------+ | 8.0.22 | +-----------+ 1 row in set (0.00 sec) mysql> show master status; +-------------------+----------+--------------+-------------------------------------------------+-------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +-------------------+----------+--------------+-------------------------------------------------+-------------------+ | master-bin.000001 | 1816 | | mysql,information_schema,performance_schema,sys | | +-------------------+----------+--------------+-------------------------------------------------+-------------------+ 1 row in set (0.00 sec) --2)slave同步情况: mysql> show slave status \G; *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: 172.72.0.11 Master_User: repl Master_Port: 3306 Connect_Retry: 60 Master_Log_File: master-bin.000001 Read_Master_Log_Pos: 1816 Relay_Log_File: slave1-relay-bin.000002 Relay_Log_Pos: 615 Relay_Master_Log_File: master-bin.000001 Slave_IO_Running: Yes Slave_SQL_Running: Yes Replicate_Do_DB: Replicate_Ignore_DB: information_schema,performance_schema,mysql,sys 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: 1816 Relay_Log_Space: 825 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: 573033261 Master_UUID: 081712e5-f45a-11ed-9af2-0242ac48000b Master_Info_File: mysql.slave_master_info SQL_Delay: 0 SQL_Remaining_Delay: NULL Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates Master_Retry_Count: 86400 Master_Bind: Last_IO_Error_Timestamp: Last_SQL_Error_Timestamp: Master_SSL_Crl: Master_SSL_Crlpath: Retrieved_Gtid_Set: Executed_Gtid_Set: Auto_Position: 0 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) ERROR: No query specified
可以看到当前同步状态为传统模式,未启用 GTID
传统模式切换成Gtid模式 1. 主从修改参数 enforce_gtid_consistency 1 2 3 -- 主从都执行,先后顺序不要求 mysql> set @@global.enforce_gtid_consistency=warn; Query OK, 0 rows affected (0.00 sec)
如果出现 GTID 不兼容的语句用法,在错误日志会记录相关信息,需要先修复,调整应该程序避免不兼容的写法,直到完全没有产生不兼容的语句,可以设置后观察错误日志一段时间,防止出现问题,这一步非常重要。
2. 主从修改参数 enforce_gtid_consistency 确定没有不兼容语法后,修改为 ON
1 2 3 -- 主从都执行,先后顺序不要求 mysql> set @@global.enforce_gtid_consistency=on; Query OK, 0 rows affected (0.01 sec)
3. 主从修改参数 gtid_mode 先设置 gtid_mode 为 off_permissiv=off_permissiv,再改成 on_permissiv
1 2 3 4 5 6 -- 建议先修改从库的gtid_mode为on_permissive,之后再修改主库的 mysql> SET @@GLOBAL.GTID_MODE = OFF_PERMISSIVE; Query OK, 0 rows affected (0.00 sec) mysql> SET @@GLOBAL.GTID_MODE = ON_PERMISSIVE; Query OK, 0 rows affected (0.00 sec)
gitd_mode 解释
OFF 不产生 GTID,Slave 只接收不带 GTID 的事务
OFF_PERMISSIVE 不产生 GTID,Slave 接收不带 GTID 的事务也接收带 GTID 的事务
ON_PERMISSIVE 产生 GTID,Slave 接收不带 GTID 的事务也接收带 GTID 的事务
ON 产生 GTID,Slave 只接收带 GTID 的事务
注意:需要严格按照以下顺序,不可跳跃,否则抛出如下错误:
OFF <= => OFF_PERMISSIVE <= => ON_PERMISSIVE <= => ON
1 2 3 4 5 6 7 8 9 10 11 -- 比如,直接从off改成on是不行的 mysql> show variables like 'gtid_mode'; +---------------+-------+ | Variable_name | Value | +---------------+-------+ | gtid_mode | OFF | +---------------+-------+ 1 row in set (0.00 sec) mysql> SET @@GLOBAL.GTID_MODE = on; ERROR 1788 (HY000): The value of @@GLOBAL.GTID_MODE can only be changed one step at a time: OFF <-> OFF_PERMISSIVE <-> ON_PERMISSIVE <-> ON. Also note that this value must be stepped up or down simultaneously on all servers. See the Manual for instructions.
4. 检查从库是否已经同步到当前主库位置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 --1)master: 取主库的file跟pos到从库去执行查看 mysql> show master status; +-------------------+----------+--------------+-------------------------------------------------+-------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +-------------------+----------+--------------+-------------------------------------------------+-------------------+ | master-bin.000002 | 635 | | mysql,information_schema,performance_schema,sys | | +-------------------+----------+--------------+-------------------------------------------------+-------------------+ 1 row in set (0.00 sec) --2)slave mysql> SELECT MASTER_POS_WAIT('master-bin.000002', 635); +-------------------------------------------+ | MASTER_POS_WAIT('master-bin.000002', 635) | +-------------------------------------------+ | 0 | -- 返回值为0,代表从库已经应用了指定的主库上binlog position位置数据 +-------------------------------------------+
5. 确认从库没等待的事务 1 2 3 4 5 6 7 8 -- 检查全部实例 正在进行的匿名交易数目,也就是非GTID事务有没有都传送到从库上了,需要等到这个变量为 0 mysql> show status like 'ongoing_anonymous_transaction_count'; +-------------------------------------+-------+ | Variable_name | Value | +-------------------------------------+-------+ | Ongoing_anonymous_transaction_count | 0 | +-------------------------------------+-------+ 1 row in set (0.01 sec)
注意:如果是一主多从,那么需要在所有从库上查看,等待所有从库都变为 0.
6. 启动 GTID 1 2 3 4 5 6 7 8 9 10 11 -- 主从都执行,先后顺序不要求 mysql> SET @@GLOBAL.GTID_MODE = ON; Query OK, 0 rows affected (0.00 sec) mysql> show variables like 'gtid_mode'; +---------------+-------+ | Variable_name | Value | +---------------+-------+ | gtid_mode | ON | +---------------+-------+ 1 row in set (0.00 sec)
7. 检查同步状态 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 --1)master mysql> insert into mytb1 values (4,'d'); Query OK, 1 row affected (0.00 sec) mysql> show master status; +-------------------+----------+--------------+-------------------------------------------------+----------------------------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +-------------------+----------+--------------+-------------------------------------------------+----------------------------------------+ | master-bin.000005 | 446 | | mysql,information_schema,performance_schema,sys | 081712e5-f45a-11ed-9af2-0242ac48000b:1 | +-------------------+----------+--------------+-------------------------------------------------+----------------------------------------+ 1 row in set (0.00 sec) --2)slave mysql> select * from mytb1; +------+------+ | id | name | +------+------+ | 1 | a | | 2 | b | | 3 | c | | 4 | d | +------+------+ 4 rows in set (0.00 sec) mysql> show slave status\G; *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: 172.72.0.11 Master_User: repl Master_Port: 3306 Connect_Retry: 60 Master_Log_File: master-bin.000005 Read_Master_Log_Pos: 446 Relay_Log_File: slave1-relay-bin.000010 Relay_Log_Pos: 663 Relay_Master_Log_File: master-bin.000005 Slave_IO_Running: Yes Slave_SQL_Running: Yes Replicate_Do_DB: Replicate_Ignore_DB: information_schema,performance_schema,mysql,sys 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: 446 Relay_Log_Space: 921 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: 573033261 Master_UUID: 081712e5-f45a-11ed-9af2-0242ac48000b Master_Info_File: mysql.slave_master_info SQL_Delay: 0 SQL_Remaining_Delay: NULL Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates Master_Retry_Count: 86400 Master_Bind: Last_IO_Error_Timestamp: Last_SQL_Error_Timestamp: Master_SSL_Crl: Master_SSL_Crlpath: Retrieved_Gtid_Set: 081712e5-f45a-11ed-9af2-0242ac48000b:1 Executed_Gtid_Set: 081712e5-f45a-11ed-9af2-0242ac48000b:1 Auto_Position: 0 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) ERROR: No query specified
可以看到:
主库新插入的数据,可以正常同步到 slave。
Retrieved_Gtid_Set、Executed_Gtid_Set 都识别到了事务编号。
Auto_Position 仍然是 0,说明还是传统模式。
8. 将传统复制转为 GTID 模式 1 2 3 4 5 6 7 8 9 --slave执行 mysql> stop slave; Query OK, 0 rows affected, 1 warning (0.00 sec) mysql> change master to master_auto_position=1; -- 设置为1,自动查找位置复制 Query OK, 0 rows affected (0.01 sec) mysql> start slave; Query OK, 0 rows affected, 1 warning (0.00 sec)
9. 测试同步 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 --1)master mysql> insert into mytb1 values (5,'e'); Query OK, 1 row affected (0.00 sec) --2)slave: 同步正常 mysql> select * from testdb.mytb1; +------+------+ | id | name | +------+------+ | 1 | a | | 2 | b | | 3 | c | | 4 | d | | 5 | e | +------+------+ 5 rows in set (0.00 sec)
10. 主从修改 my.cnf 文件 1 2 3 4 cat >> /etc/my.cnf <<EOF gtid-mode=ON enforce-gtid-consistency=on EOF
或者利用 MySQL 8.0 新特性,持久化修改参数:
1 2 3 4 5 6 7 8 9 10 11 mysql> set persist gtid_mode = on; Query OK, 0 rows affected (0.00 sec) mysql> set persist enforce_gtid_consistency = on; Query OK, 0 rows affected (0.00 sec) -- 这种方式会把参数设置写入到mysqld-auto.cnf文件中 root@slave1:/var/lib/mysql# more mysqld-auto.cnf { "Version" : 1 , "mysql_server" : { "mysql_server_static_options" : { "enforce_gtid_consistency" : { "Value" : "ON" , "Metadata" : { "Timestamp" : 1684293203484259 , "User" : "root" , "Host" : "localhost" } } , "gtid_mode" : { "Value" : "ON" , "Metadata" : { "Timestamp" : 1684293146585382 , "User" : "root" , "Host" : "localhost" } } } } }
此时,我们已经将原来的传统复制模式,修改为 GTID 复制模式。
Gtid模式切换成传统模式 1. 停止从库 1 2 mysql> stop slave; Query OK, 0 rows affected, 1 warning (0.02 sec)
2. 修改复制模式为传统模式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 --1)master:取主库file跟pos mysql> show master status; +-------------------+----------+--------------+-------------------------------------------------+------------------------------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +-------------------+----------+--------------+-------------------------------------------------+------------------------------------------+ | master-bin.000005 | 736 | | mysql,information_schema,performance_schema,sys | 081712e5-f45a-11ed-9af2-0242ac48000b:1-2 | +-------------------+----------+--------------+-------------------------------------------------+------------------------------------------+ 1 row in set (0.00 sec) --2)slave: mysql> change master to master_log_file='master-bin.000005',master_log_pos=736,master_auto_position=0; Query OK, 0 rows affected (0.01 sec) mysql> start slave; Query OK, 0 rows affected, 1 warning (0.00 sec)
3. 测试同步 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 --1)master mysql> insert into mytb1 values (6,'f'); Query OK, 1 row affected (0.00 sec) --2)slave mysql> select * from mytb1; +------+------+ | id | name | +------+------+ | 1 | a | | 2 | b | | 3 | c | | 4 | d | | 5 | e | | 6 | f | +------+------+ 6 rows in set (0.00 sec) mysql> show slave status\G; *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: 172.72.0.11 Master_User: repl Master_Port: 3306 Connect_Retry: 60 Master_Log_File: master-bin.000005 Read_Master_Log_Pos: 1026 Relay_Log_File: slave1-relay-bin.000002 Relay_Log_Pos: 615 Relay_Master_Log_File: master-bin.000005 Slave_IO_Running: Yes Slave_SQL_Running: Yes Replicate_Do_DB: Replicate_Ignore_DB: information_schema,performance_schema,mysql,sys 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: 1026 Relay_Log_Space: 825 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: 573033261 Master_UUID: 081712e5-f45a-11ed-9af2-0242ac48000b Master_Info_File: mysql.slave_master_info SQL_Delay: 0 SQL_Remaining_Delay: NULL Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates Master_Retry_Count: 86400 Master_Bind: Last_IO_Error_Timestamp: Last_SQL_Error_Timestamp: Master_SSL_Crl: Master_SSL_Crlpath: Retrieved_Gtid_Set: 081712e5-f45a-11ed-9af2-0242ac48000b:3 Executed_Gtid_Set: 081712e5-f45a-11ed-9af2-0242ac48000b:1-3 Auto_Position: 0 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) ERROR: No query specified
可以看到:
主库新插入的数据,可以正常同步到 slave。
Read_Master_Log_Pos、Exec_Master_Log_Pos 都产生了变化。
Auto_Position 变为 0,已经修改为传统模式。
4. 主从修改参数 gtid_mode 先设置 gtid_mode 为 off_permissiv=on_permissiv,再改成 off_permissiv
1 2 3 4 5 6 -- 主从都执行,先后顺序不要求 mysql> SET @@GLOBAL.GTID_MODE = ON_PERMISSIVE; Query OK, 0 rows affected (0.00 sec) mysql> SET @@GLOBAL.GTID_MODE = OFF_PERMISSIVE; Query OK, 0 rows affected (0.00 sec)
5. 禁用 GTID 1 2 3 4 5 6 7 8 9 10 11 12 13 14 -- 主从都执行,先后顺序不要求 mysql> SET @@GLOBAL.ENFORCE_GTID_CONSISTENCY=OFF; Query OK, 0 rows affected (0.00 sec) mysql> SET @@GLOBAL.GTID_MODE = OFF; Query OK, 0 rows affected (0.00 sec) mysql> show variables like 'gtid_mode'; +---------------+-------+ | Variable_name | Value | +---------------+-------+ | gtid_mode | OFF | +---------------+-------+ 1 row in set (0.00 sec)
7. 检查同步状态 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 --1)master mysql> insert into mytb1 values (7,'g'); Query OK, 1 row affected (0.00 sec) --2)slave: 同步正常 mysql> select * from mytb1; +------+------+ | id | name | +------+------+ | 1 | a | | 2 | b | | 3 | c | | 4 | d | | 5 | e | | 6 | f | | 7 | g | +------+------+ 7 rows in set (0.00 sec)
9. 主从修改 my.cnf 文件 如果使用 MySQL 8.0 新特性,持久化修改参数的,需要再重置回去:
1 2 3 -- 注释 #gtid-mode=ON #enforce-gtid-consistency=on
此时,我们已经将原来的 GTID 复制模式,修改为传统复制模式。
10. 思考? 在第一步,停止从库复制 (stop slave),到再次启动 slave 复制,期间是有时间差的,如果从库停止复制期间,主库有新的事务产生,那么从库在启动复制后,会丢失这部分数据,因此,从 GTID 模式修改为传统复制模式,需要将主库停止,防止丢失数据。但是从传统模式修改为 GTID 模式,不需要停止主库,可以在线操作。
–实验:
1 2 3 4 5 6 7 8 9 10 mysql> reset persist gtid_mode ; Query OK, 0 rows affected (0.00 sec) mysql> reset persist enforce_gtid_consistency ; Query OK, 0 rows affected (0.00 sec) -- 可以看到mysqld-auto.cnf文件,之前设置的参数已被删除 root@slave1:/var/lib/mysql# more mysqld-auto.cnf { "Version" : 1 , "mysql_server" : { } }
slave 重新启动同步后,丢失了主库插入的(8,h)这一行数据。
引用:Mysql 8.0 主从同步 传统模式和GTID模式相互切换 - 墨天轮 (modb.pro)