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=10000000
rpl_semi_sync_master_wait_for_slave_count=1
rpl_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: 60
              Master_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: 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: 377
              Relay_Log_Space: 707
              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: NULL
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: 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: 60
              Master_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: 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: 3013
              Relay_Log_Space: 2099
              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: NULL
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: 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被挂起,没有返回。

MySQL半同步after_sync与after_commit_第1张图片

主库其他会话查询该条数据,并没有查到数据。

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模式下,​才能保证主从数据的强一致性。

你可能感兴趣的:(MySQL,dba,mysql,数据库架构,数据库)