MySQL复制:复制模式

异步复制

MySQL默认采用异步复制的模式,主节点提交事务后会立即返回客户端,从节点是否接收应用并不影响。在一个高可用的方案中,如果主节点发生Crash,集群发生切换,可能会造成事务数据丢失。其复制原理如下:

  1. MySQL master将数据变更写入二进制日志(binary log, 其中记录叫做二进制日志事件binary log events)
  2. MySQL slave的IO线程将 master 的 binary log events 拷贝到它的中继日志(relay log)
  3. MySQL slave的SQL线程重放 relay log 中事件,将数据变更反映它自己的数据(数据回放) replication

配置复制

开启二进制日志和设置server-id(主从server-id不能一致)

1
2
3
[mysqld]
log-bin=mysql-bin
server-id=1

主节点创建复制用户

1
2
mysql> CREATE USER 'repl'@'%' IDENTIFIED BY 'password';
mysql> GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';

从节点配置同步channel

1
2
3
4
5
6
mysql> CHANGE MASTER TO
         MASTER_HOST='master_host_name',
         MASTER_USER='replication_user_name',
         MASTER_PASSWORD='replication_password',
         MASTER_LOG_FILE='recorded_log_file_name',
         MASTER_LOG_POS=recorded_log_position;

Tips:如果主节点已经存在数据,需通过xtrabackup之类的方式进行数据复制到从节点

启动复制进程

1
mysql> start slave;

查看复制状态

 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
root@(none) 13:44:  show slave status\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 10.0.139.162
                  Master_User: repl
                  Master_Port: 33006
                Connect_Retry: 5
              Master_Log_File: mysql-bin.000003
          Read_Master_Log_Pos: 554
               Relay_Log_File: t-luhx03-v-szzb-relay-bin.000002
                Relay_Log_Pos: 554
        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: 554
              Relay_Log_Space: 811
              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: 139162
                  Master_UUID: 2ca6b28c-bff9-11ea-90b9-005056abb91e
             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: 2ca6b28c-bff9-11ea-90b9-005056abb91e:2
            Executed_Gtid_Set: 2ca6b28c-bff9-11ea-90b9-005056abb91e:1-2,
8ace4726-bf55-11ea-a030-005056ab71f1:1-8,
d4211ac1-bf55-11ea-8341-005056abc9c9:1-6
                Auto_Position: 1
         Replicate_Rewrite_DB: 
                 Channel_Name: 
           Master_TLS_Version: 

Tips:其中Slave_IO_Running和Slave_SQL_Running为IO线程和SQL线程的状态,Seconds_Behind_Master为同步延迟(可能不准),Master_Log_File和Read_Master_Log_Pos为主节点二进制日志信息,Relay_Master_Log_File和Exec_Master_Log_Pos为当前从节点已执行到的位置

半同步复制

MySQL5.5中开始引入了半同步复制,极大地减少了事务丢失的数量,它要求主节点至少需要等待一个从节点接收到该事务才能完成提交,在从节点确认之前主节点的事务提交将被阻塞,如果时间超过rpl_semi_sync_master_timeout参数的配置,就会临时切换为异步复制,直到下一次再接收从库的半同步响应。

在MySQL5.6中binlog的发送和接受从节点的ACK消息都是由dump线程完成的,两个任务是串行执行的,容易成为半同步复制的性能瓶颈,会影响数据库整体业务的效率。在5.7的半同步复制中,单独拆分出一个ack receiver线程,专门用于接受从节点反馈的消息,性能得到了极大的提升。

MySQL5.6 ack

MySQL5.7 ack

半同步复制依旧存在数据丢失的问题:主节点提交事务等待ACK反馈时,发生Crash切换,虽然客户端没有收到成功的消息,但事务实际上已经提交,其它事务也可以读取到事务提交的内容,但是新的主节点并不存在该数据,导致数据状态不一致。

半同步配置

半同步复制是以插件的形式提供的,在使用之前,我们需要手动安装相关插件

1
2
3
4
5
6
7
### Master
mysql> INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
mysql> SET GLOBAL rpl_semi_sync_master_enabled=1;

### Slave
mysql> INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
mysql> SET GLOBAL rpl_semi_sync_slave_enabled = 1;

查看插件状态

1
2
3
4
5
6
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
2
3
plugin-load = "rpl_semi_sync_master=semisync_master.so;rpl_semi_sync_slave=semisync_slave.so"
rpl-semi-sync-master-enabled = 1
rpl-semi-sync-slave-enabled = 1

查看半同步状态

1
2
3
4
5
6
mysql> show status like 'Rpl_semi_sync_master_status';
+-----------------------------+-------+
| Variable_name               | Value |
+-----------------------------+-------+
| Rpl_semi_sync_master_status | ON    |
+-----------------------------+-------+

多从库bug

存在多个半同步从节点时,如果参数rpl_semi_sync_master_wait_for_slave_count为1,在启动第二个从节点的时候容易触发一个io线程停滞的bug(ID:89370),该bug是由于主节点dump线程由于ack_receiver锁阻塞导致,官方已经在5.7.23中修复。具体可参考:深度分析 | 多从库时半同步复制不工作的BUG分析

无损(lossless)复制

MySQL5.7在半同步复制的基础上又引入了无损复制的方案,其由参数rpl_semi_sync_master_wait_point控制,参数设置为AFTER_SYNC则表示采用无损复制,AFTER_COMMIT则表示采用5.6中的半同步复制。

两种半同步复制方案的区别在于时机点的不同,根据事务的二阶段提交协议,之前的半同步复制将整个ACK确认过程放在InnoDB Commit log之后,这时事务实际已经提交成功了;而无损复制是将其迁移至write binary log之后,这时事务还没完成提交步骤,其它事务也无法读取该事务的提交内容。

半同步复制

无损复制

comments powered by Disqus