异步复制 MySQL默认采用异步复制的模式,主节点提交事务后会立即返回客户端,从节点是否接收应用并不影响。在一个高可用的方案中,如果主节点发生Crash,集群发生切换,可能会造成事务数据丢失。其复制原理如下:
MySQL master将数据变更写入二进制日志(binary log, 其中记录叫做二进制日志事件binary log events)
MySQL slave的IO线程将 master 的 binary log events 拷贝到它的中继日志(relay log)
MySQL slave的SQL线程重放 relay log 中事件,将数据变更反映它自己的数据(数据回放)
配置复制
开启二进制日志和设置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之类的方式进行数据复制到从节点
启动复制进程
查看复制状态
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线程,专门用于接受从节点反馈的消息,性能得到了极大的提升。
半同步复制依旧存在数据丢失的问题:主节点提交事务等待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之后,这时事务还没完成提交步骤,其它事务也无法读取该事务的提交内容。