MySQL半同步after_sync与after_commit
前言:
在MySQL半同步复制中,有两种日志同步的ACK模式,分别是after_sync与after_commit,本文主要介绍两种模式下,主从同步数据的一致性情况。
测试环境:
主库 | 从库 |
192.168.1.110:3306 | 192.168.1.111:3306 |
半同步配置参数:
rpl_semi_sync_master_timeout=10000000rpl_semi_sync_master_wait_for_slave_count=1rpl_semi_sync_master_wait_point=after_sync|after_commit
after_commit模式:
after_commit:主库写入事务到binlog以及同步从库,sync binlog,并且提交事务到存储引擎,在提交之后主库等待从库接受到事务的确认,在接受到确认之后,源端返回提交完成到客户端。
在after_commit下,提交事务的客户端需要等待确认从库已经接收到事务才能返回,但由于提交到存储引擎是在确认从库之前完成,所以,其他客户端将比提交事务的客户端更早的看到提交事务的数据,在发生故障切换时,在对于已经提交存储引擎但还没有确认从库已经提交的事务,其他客户端可能会出现与他们在源上看到的数据相关的数据丢失。
提交流程:client-->execute sql-->wrtie redolog-->write binlog-->innodb storage commit-->wait ACK-->client receive OK。
暂停从库io_thread。
stop slave io_thread;root@localhost : (none)06:19:40>stop slave io_thread;Query OK, 0 rows affected (0.01 sec)root@localhost : (none)06:19:55>show slave status\G* 1. row * Slave_IO_State: Master_Host: 192.168.1.110 Master_User: rep Master_Port: 3306 Connect_Retry: 60Master_Log_File: nlog.000010 Read_Master_Log_Pos: 377 Relay_Log_File: mysql-relay-bin.000018 Relay_Log_Pos: 500 Relay_Master_Log_File: nlog.000010 Slave_IO_Running: No Slave_SQL_Running: YesReplicate_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: 377Relay_Log_Space: 707Until_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: NULLMaster_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: 3306 Master_UUID: 2b3039c9-57fa-11eb-b504-000c29ed797a 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: 2b3039c9-57fa-11eb-b504-000c29ed797a:8346311 Executed_Gtid_Set: 1b80feab-4aa6-11ec-9a60-000c29a6e7be:1-10,2b3039c9-57fa-11eb-b504-000c29ed797a:1-8346311,3a59d149-d4b8-11eb-8cf6-000c29a6e7b4:1-10,a0a3d4b2-fff8-11eb-a420-000c29a6e7be:1-27 Auto_Position: 1 Replicate_Rewrite_DB: Channel_Name: Master_TLS_Version:
插入数据。
begin;insert into sbtest1(k,c,pad,d) values(1,'a','ziniu',1);commit;
可以看到commit被挂起,没有返回。
主库其他会话查询该条数据,可以查到数据。
select * from sbtest1 where pad='ziniu';root@localhost : sbtest06:27:17>select * from sbtest1 where pad='ziniu';+--------+---+---+-------+------+| id | k | c | pad | d |+--------+---+---+-------+------+| 170006 | 1 | a | ziniu | 1 |+--------+---+---+-------+------+1 row in set (0.05 sec)
但在从库查询不到该条数据。
root@localhost : sbtest06:27:27>select * from sbtest1 where pad='ziniu';Empty set (0.06 sec)
这时候,如果发生主从故障切换,就会出现有些客户端在源上看到相关的数据丢失,因为故障切换前,在主库查到"ziniu"这条数据,但在切换之后却查不到该条数据,并且对于写入数据的客户端是没有收到commit提交完成的确认,所以,after_commit下主从出现了数据丢失,主从两边不是强一致性。
after_sync模式:
after_sync(默认):主库写入事务到binlog以及同步从库并且sync binlog to disk,主库同步后等待从库接受到事务的确认,在等到从库的确认之后,主库提交事务到存储引擎并且返回客户端。
在after_sync下,全部客户端同一时间看到已经提交的事务,因为是在确认从库已经接收到事务之后再提交存储引擎的,所以全部客户端是同一时间看到已经提交事务的数据;此外,在发生故障切换时,主库全部已经提交的事务已经同步到从库的relay log,从库的数据是无损的。
提交流程:client-->execute sql-->wrtie redolog-->write binlog-->wait ACK-->innodb storage commit-->client receive OK。
暂停从库io_thread。
root@localhost : sbtest06:30:32>stop slave io_thread;Query OK, 0 rows affected (0.00 sec)root@localhost : sbtest06:59:44>root@localhost : sbtest06:59:45>root@localhost : sbtest06:59:45>root@localhost : sbtest06:59:45>show slave status\G* 1. row * Slave_IO_State: Master_Host: 192.168.1.110 Master_User: rep Master_Port: 3306 Connect_Retry: 60Master_Log_File: nlog.000010 Read_Master_Log_Pos: 3013 Relay_Log_File: mysql-relay-bin.000023 Relay_Log_Pos: 808 Relay_Master_Log_File: nlog.000010 Slave_IO_Running: No Slave_SQL_Running: YesReplicate_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: 3013Relay_Log_Space: 2099Until_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: NULLMaster_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: 3306 Master_UUID: 2b3039c9-57fa-11eb-b504-000c29ed797a 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: 2b3039c9-57fa-11eb-b504-000c29ed797a:8346311-8346318 Executed_Gtid_Set: 1b80feab-4aa6-11ec-9a60-000c29a6e7be:1-10,2b3039c9-57fa-11eb-b504-000c29ed797a:1-8346318,3a59d149-d4b8-11eb-8cf6-000c29a6e7b4:1-10,a0a3d4b2-fff8-11eb-a420-000c29a6e7be:1-27 Auto_Position: 1 Replicate_Rewrite_DB: Channel_Name: Master_TLS_Version: 1 row in set (0.00 sec)
插入数据。
begin;insert into sbtest1(k,c,pad,d) values(1,'a','niuniu',1);commit;
可以看到commit被挂起,没有返回。
主库其他会话查询该条数据,并没有查到数据。
select * from sbtest1 where pad='niuniu';root@localhost : sbtest07:02:06>select * from sbtest1 where pad='niuniu';Empty set (0.05 sec)root@localhost : sbtest07:02:06>root@localhost : sbtest07:02:07>
在从库也查询不到该条数据。
root@localhost : sbtest07:03:59>select * from sbtest1 where pad='niuniu';Empty set (0.06 sec)root@localhost : sbtest07:04:02>
这时候,如果发生主从故障切换,对于"niuniu"这条数据,只是一条客户端提交失败的数据,不存在数据的丢失,所以,after_sync下主从两边数据是强一致性。
总结:
对于生产环境半同步的配置,建议配置after_sync模式,在after_sync模式下,才能保证主从数据的强一致性。