异步复制

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不能一致)

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

主节点创建复制用户

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

从节点配置同步channel

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之类的方式进行数据复制到从节点

启动复制进程

mysql> start slave;

查看复制状态

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切换,虽然客户端没有收到成功的消息,但事务实际上已经提交,其它事务也可以读取到事务提交的内容,但是新的主节点并不存在该数据,导致数据状态不一致。

半同步配置

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

### 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;

查看插件状态

mysql> SELECT PLUGIN_NAME, PLUGIN_STATUS FROM INFORMATION_SCHEMA.PLUGINS  WHERE PLUGIN_NAME LIKE '%semi%';
+----------------------+---------------+
| PLUGIN_NAME | PLUGIN_STATUS |
+----------------------+---------------+
| rpl_semi_sync_master | ACTIVE |
+----------------------+---------------+

设置配置文件

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

查看半同步状态

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之后,这时事务还没完成提交步骤,其它事务也无法读取该事务的提交内容。

半同步复制

无损复制