MySQL Replication
MySQL Replication
注意:
此文档对应的 MySQL 版本为 8.0.32 社区版。
为保障服务和数据的高可用,MySQL 提供了主从复制(Replication)功能,将数据从源库(Source,以前称为 Master)同步到副本库(Replicas,以前称为 Slave)。
复制方式:
- 基二进制日志文件位置的传统复制方式。
- 基于 GTID (Global Transaction Identifiers)的新方式。
复制同步类型:
- 异步复制。
- 半同步复制。
- 延迟复制。
复制格式类型:
- 基于语句的复制(Statement Based Replication SBR)。
- 基于行的复制(Row Based Replication RBR)。
- 混合复制(Mixed Based Replication MBR)。
Configuring Replication
本节介绍如何配置各种类型的复制。
Binary Log File Position Based Replication Configuration Overview
本节描述了在 MySQL Server 之间,基于二进制日志文件位置的传统复制方式,其中源库将数据库变更作为 Events(事件) 写入二进制日志。副本库从源库读取二进制日志并执行二进制日志中的 Events。
每个副本库都会获取完整二进制日志,可以根据需要只处理应用于特定数据库或表的 Events。
每个副本库会记录各自二进制日志中的当前位置,因此副本库可以断开连接,重新连接,然后恢复处理。
源库和副本库需配置不同的 server_id
参数,每个副本库还需要使用 CHANGE REPLICATION SOURCE TO
语句(从 MySQL 8.0.23 起)或者 CHANGE MASTER TO
语句(在 MySQL 8.0.23 前)配置源库的主机名或者 IP 地址,二进制日志文件名及位置。
Setting Up Binary Log File Position Based Replication
本节介绍如何设置基于二进制日志文件位置(Binary Log File Position)的复制。
Setting the Replication Source Configuration
源库的安装参考:Installing MySQL on Linux
在参数文件中配置复制环境唯一的 server_id
,一般取主机 IP(192.168.44.135)的后两位:
[mysqld]
server_id=44135
#gtid_mode=on
还需要确认以下参数是否保持为默认值:
[(none)]> show variables like 'log_bin';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_bin | ON |
+---------------+-------+
1 row in set (0.03 sec)
[(none)]> show variables like 'innodb_flush_log_at_trx_commit';
+--------------------------------+-------+
| Variable_name | Value |
+--------------------------------+-------+
| innodb_flush_log_at_trx_commit | 1 |
+--------------------------------+-------+
1 row in set (0.00 sec)
[(none)]> show variables like 'sync_binlog';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| sync_binlog | 1 |
+---------------+-------+
1 row in set (0.00 sec)
[(none)]> show variables like 'skip_networking';
+-----------------+-------+
| Variable_name | Value |
+-----------------+-------+
| skip_networking | OFF |
+-----------------+-------+
1 row in set (0.01 sec)
其中:
- 当
sync_binlog=1
时,表示每次提交事务时都会将 Binlog Cache 里的 Binlog 直接持久化到磁盘。 - 当
innodb_flush_log_at_trx_commit=1
时,表示每次提交事务时都会将 Redo Log Buffer 里的 Redo Log 直接持久化到磁盘。
Setting the Replica Configuration
副本库的安装参考:Installing MySQL on Linux
在参数文件中配置复制环境唯一的 server_id
,一般取主机 IP(192.168.44.136)的后两位:
[mysqld]
server_id=44136
event_scheduler=OFF
relay_log=relay-binlog
relay_log_index=/data/mysql/relay-binlog.index
#gtid_mode=on
参数 event_scheduler
设置为 OFF (默认为 ON)表示在副本库停止运行定时任务,也可以使用 ALTER EVENT
语句停止运行指定的定时任务。调整参数 relay_log
和 relay_log_index
与主机名无关(默认为 host_name-relay-bin 和 host_name-relay-bin.index),避免拷贝该副本库来创建其他副本库时出现问题。
二进制日志是默认启用的,可用于在副本库进行备份及崩溃恢复,不要禁用。
[(none)]> show variables like 'log_bin';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_bin | ON |
+---------------+-------+
1 row in set (0.01 sec)
如果需要将此副本库作为其他副本库的源库,除了确保默认启用二进制日志外,还要确保默认启用了参数 log_replica_updates
(从 MySQL 8.0.26 起)或者 log_slave_updates
(在 MySQL 8.0.26 之前)。
[(none)]> show variables like 'log_replica_updates';
+---------------------+-------+
| Variable_name | Value |
+---------------------+-------+
| log_replica_updates | ON |
+---------------------+-------+
1 row in set (0.00 sec)
注意:
如果通过直接克隆源库虚拟机或者虚拟机模板来创建副本库,需要进行如下操作:
- 启动副本库后需要执行
RESET MASTER
语句。否则在导入源库的导出文件时,会报以下错误:ERROR 3546 (HY000) at line 26: @@GLOBAL.GTID_PURGED cannot be changed: the added gtid set must not overlap with @@GLOBAL.GTID_EXECUTED
- 此时数据目录下的
/data/mysql/auto.cnf
文件中的server-uuid
相同,需要重命名该文件夹,并重启 MySQL Server,以便生成新的server-uuid
。[root@replica1 ~]# cat /data/mysql/auto.cnf [auto] server-uuid=f84c4937-eb10-11ed-a2ff-000c294b702c [root@replica1 ~]# mv /data/mysql/auto.cnf /data/mysql/auto.cnf.bak [root@replica1 ~]# systemctl restart mysqld.service [root@replica1 ~]# cat /data/mysql/auto.cnf [auto] server-uuid=42f223db-eb20-11ed-a7a4-000c2986525b
如果不进行以上操作,则在启用复制时会出现如下报错:
Last_IO_Error: Fatal error: The slave I/O thread stops because master and slave have equal MySQL server UUIDs; these UUIDs must be different for replication to work.
Creating a User for Replication
需要在源库创建一个复制用户并授予权限,以便副本库连接。
[(none)]> CREATE USER 'repl'@'%' IDENTIFIED WITH mysql_native_password BY 'pUrEv!2rAx';
Query OK, 0 rows affected (0.01 sec)
[(none)]> GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
Query OK, 0 rows affected (0.01 sec)
注意:
创建用户时,需要使用
WITH mysql_native_password
子句指定使用mysql_native_password
插件进行身份认证。否则在副本库启用复制时会出现如下报错:Last_IO_Error: error connecting to master 'repl@192.168.44.135:3306' - retry-time: 60 retries: 1 message: Authentication plugin 'caching_sha2_password' reported error: Authentication requires secure connection.
Choosing a Method for Data Snapshots
当源库包含用户数据,则在创建主从复制前,需要将源库的数据拷贝到副本库。
当数据量较小时,建议使用 mysqldump 从源库导出数据,在副本库导入数据。
当数据量较大时,建议使用克隆插件来进行数据初始化。
Creating a Data Snapshot Using mysqldump
使用 --source-data
选项自动添加 CHANGE REPLICATION SOURCE TO
或者 CHANGE MASTER TO
语句到导出文件中。--all-databases
表示导出所有数据库数据,也可以使用 --databases
选项导出指定数据库。
[root@mysql ~]# mysqldump --all-databases --source-data > dbdump.sql
导出文件中包含 CHANGE MASTER TO
语句,指定了二进制日志的位置:
CHANGE MASTER TO MASTER_LOG_FILE='binlog.000003', MASTER_LOG_POS=878;
Setting Up Replicas
Setting Up Replication with Existing Data
配置副本库的具体步骤如下:
- 在副本库导入源库的导出文件。
[root@replica1 ~]# mysql < dbdump.sql
- 使用
CHANGE REPLICATION SOURCE TO
语句(从 MySQL 8.0.23 起)或者CHANGE MASTER TO
语句(在 MySQL 8.0.23 前)在副本库配置到源库的连接信息,包括源库 IP,端口及二进制日志位置。
[(none)]> CHANGE REPLICATION SOURCE TO
SOURCE_HOST='192.168.44.135',
SOURCE_USER='repl',
SOURCE_PASSWORD='pUrEv!2rAx',
SOURCE_LOG_FILE='binlog.000003',
SOURCE_LOG_POS=878;
Query OK, 0 rows affected, 2 warnings (0.01 sec)
- 使用
START REPLICA
语句(从 MySQL 8.0.23 起)或者START SLAVE
语句(在 MySQL 8.0.23 前)在副本库启动复制线程并使用SHOW REPLICA STATUS
语句查看复制状态,其中Replica_IO_Running
和Replica_SQL_Running
均为Yes
。
[(none)]> START REPLICA;
Query OK, 0 rows affected (0.15 sec)
[(none)]> SHOW REPLICA STATUS\G
*************************** 1. row ***************************
Replica_IO_State: Waiting for source to send event
Source_Host: 192.168.44.135
Source_User: repl
Source_Port: 3306
Connect_Retry: 60
Source_Log_File: binlog.000003
Read_Source_Log_Pos: 878
Relay_Log_File: relay-binlog.000002
Relay_Log_Pos: 323
Relay_Source_Log_File: binlog.000003
Replica_IO_Running: Yes
Replica_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_Source_Log_Pos: 878
Relay_Log_Space: 530
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Source_SSL_Allowed: No
Source_SSL_CA_File:
Source_SSL_CA_Path:
Source_SSL_Cert:
Source_SSL_Cipher:
Source_SSL_Key:
Seconds_Behind_Source: 0
Source_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Source_Server_Id: 44135
Source_UUID: f84c4937-eb10-11ed-a2ff-000c294b702c
Source_Info_File: mysql.slave_master_info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Replica_SQL_Running_State: Replica has read all relay log; waiting for more updates
Source_Retry_Count: 86400
Source_Bind:
Last_IO_Error_Timestamp:
Last_SQL_Error_Timestamp:
Source_SSL_Crl:
Source_SSL_Crlpath:
Retrieved_Gtid_Set:
Executed_Gtid_Set: f84c4937-eb10-11ed-a2ff-000c294b702c:1-18
Auto_Position: 0
Replicate_Rewrite_DB:
Channel_Name:
Source_TLS_Version:
Source_public_key_path:
Get_Source_public_key: 0
Network_Namespace:
1 row in set (0.00 sec)
Adding Replicas to a Replication Environment
源库创建好一个副本库后,为源库增加第二个副本库就很简单了,只需要拷贝现有副本库的数据目录即可。
具体步骤如下:
- 先为第二个副本库所在服务器安装MySQL Server,参考:Installing MySQL on Linux
在参数文件中配置复制环境唯一的 server_id
,一般取主机 IP(192.168.44.137)的后两位:
[mysqld]
server_id=44137
event_scheduler=OFF
relay_log=relay-binlog
relay_log_index=/data/mysql/relay-binlog.index
#gtid_mode=on
参数 event_scheduler
设置为 OFF (默认为 ON)表示在副本库停止运行定时任务,也可以使用 ALTER EVENT
语句停止运行指定的定时任务。调整参数 relay_log
和 relay_log_index
与主机名无关(默认为 host_name-relay-bin 和 host_name-relay-bin.index),避免拷贝该副本库来创建其他副本库时出现问题。
二进制日志是默认启用的,可用于在副本库进行备份及崩溃恢复,不要禁用。
[(none)]> show variables like 'log_bin';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_bin | ON |
+---------------+-------+
1 row in set (0.01 sec)
如果需要将此副本库作为其他副本库的源库,除了确保默认启用二进制日志外,还要确保默认启用了参数 log_replica_updates
(从 MySQL 8.0.26 起)或者 log_slave_updates
(在 MySQL 8.0.26 之前)。
[(none)]> show variables like 'log_replica_updates';
+---------------------+-------+
| Variable_name | Value |
+---------------------+-------+
| log_replica_updates | ON |
+---------------------+-------+
1 row in set (0.00 sec)
关闭 MySQL Server,然后删除数据目录下的文件。
[root@replica2 ~]# systemctl stop mysqld.service
[root@replica2 ~]# rm -fr /data/mysql/*
- 关闭第一个副本库的复制并查看状态,其中
Replica_IO_Running
和Replica_SQL_Running
均为No
。
[(none)]> STOP REPLICA;
Query OK, 0 rows affected (0.01 sec)
[(none)]> SHOW REPLICA STATUS\G
*************************** 1. row ***************************
Replica_IO_State:
Source_Host: 192.168.44.135
Source_User: repl
Source_Port: 3306
Connect_Retry: 60
Source_Log_File: binlog.000003
Read_Source_Log_Pos: 1161
Relay_Log_File: relay-binlog.000002
Relay_Log_Pos: 606
Relay_Source_Log_File: binlog.000003
Replica_IO_Running: No
Replica_SQL_Running: No
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_Source_Log_Pos: 1161
Relay_Log_Space: 813
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Source_SSL_Allowed: No
Source_SSL_CA_File:
Source_SSL_CA_Path:
Source_SSL_Cert:
Source_SSL_Cipher:
Source_SSL_Key:
Seconds_Behind_Source: NULL
Source_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Source_Server_Id: 44135
Source_UUID: f84c4937-eb10-11ed-a2ff-000c294b702c
Source_Info_File: mysql.slave_master_info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Replica_SQL_Running_State:
Source_Retry_Count: 86400
Source_Bind:
Last_IO_Error_Timestamp:
Last_SQL_Error_Timestamp:
Source_SSL_Crl:
Source_SSL_Crlpath:
Retrieved_Gtid_Set:
Executed_Gtid_Set: f84c4937-eb10-11ed-a2ff-000c294b702c:1-18
Auto_Position: 0
Replicate_Rewrite_DB:
Channel_Name:
Source_TLS_Version:
Source_public_key_path:
Get_Source_public_key: 0
Network_Namespace:
1 row in set (0.00 sec)
再关闭第一个副本库的 MySQL Server。
[root@replica1 ~]# systemctl stop mysqld.service
- 拷贝第一个副本库的数据目录下的文件到第二个副本库的数据目录下,完成后启动 MySQL Server。
[root@replica1 ~]# scp -r /data/mysql/* root@192.168.44.137:/data/mysql/
[root@replica1 ~]# systemctl start mysqld.service
- 在第二个副本库调整目录属主和属组,并启动。
[root@replica2 ~]# chown -R mysql:mysql /data/mysql/
[root@replica2 ~]# mv /data/mysql/auto.cnf /data/mysql/auto.cnf.bak
[root@replica2 ~]# systemctl start mysqld.service
- 在第二个副本库启动复制。
[(none)]> STOP REPLICA;
Query OK, 0 rows affected (0.01 sec)
[(none)]> START REPLICA;
Query OK, 0 rows affected (0.05 sec)
[(none)]> SHOW REPLICA STATUS\G
*************************** 1. row ***************************
Replica_IO_State: Waiting for source to send event
Source_Host: 192.168.44.135
Source_User: repl
Source_Port: 3306
Connect_Retry: 60
Source_Log_File: binlog.000003
Read_Source_Log_Pos: 1161
Relay_Log_File: relay-binlog.000005
Relay_Log_Pos: 323
Relay_Source_Log_File: binlog.000003
Replica_IO_Running: Yes
Replica_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_Source_Log_Pos: 1161
Relay_Log_Space: 696
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Source_SSL_Allowed: No
Source_SSL_CA_File:
Source_SSL_CA_Path:
Source_SSL_Cert:
Source_SSL_Cipher:
Source_SSL_Key:
Seconds_Behind_Source: 0
Source_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Source_Server_Id: 44135
Source_UUID: f84c4937-eb10-11ed-a2ff-000c294b702c
Source_Info_File: mysql.slave_master_info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Replica_SQL_Running_State: Replica has read all relay log; waiting for more updates
Source_Retry_Count: 86400
Source_Bind:
Last_IO_Error_Timestamp:
Last_SQL_Error_Timestamp:
Source_SSL_Crl:
Source_SSL_Crlpath:
Retrieved_Gtid_Set:
Executed_Gtid_Set: f84c4937-eb10-11ed-a2ff-000c294b702c:1-18
Auto_Position: 0
Replicate_Rewrite_DB:
Channel_Name:
Source_TLS_Version:
Source_public_key_path:
Get_Source_public_key: 0
Network_Namespace:
1 row in set (0.00 sec)
Replication with Global Transaction Identifiers
本节介绍使用全局事务标识符(Global Transaction Identifiers GTID)进行基于事务的复制。前面配置复制需要指定二进制日志位置,而使用 GTID 进行复制就不需要了。只要在源库上提交的所有事务也在副本库上提交,就可以保证两者之间的一致性。虽然 GTID 支持基于语句的复制和基于行的复制,但官方推荐使用基于行的复制。
GTID Format and Storage
全局事务标识符(GTID)是在源库上创建的唯一标识符,并与每个提交的事务相关联,此标识符在整个复制拓扑中唯一。
在源库上提交事务时,如果事务已写入二进制日志,则会为其分配一个新的 GTID,GTID 单调递增且连续。如果事务未写入二进制日志(例如,事务被过滤,或者事务只读),则不会在源库为其分配 GTID。
复制的事务保留分配给源库事务的 GTID。GTID 在复制的事务开始执行之前就存在,即使复制的事务未写入副本库上的二进制日志,或者在副本库上被筛选掉,GTID 也会保留。使用MySQL 系统表 mysql.gtid_executed
保存为事务分配的 GTID,也会存储到参数 gtid_executed
中。
[(none)]> SHOW VARIABLES LIKE 'gtid_mode';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| gtid_mode | ON |
+---------------+-------+
1 row in set (0.01 sec)
[(none)]> SELECT * FROM mysql.gtid_executed;
+--------------------------------------+----------------+--------------+
| source_uuid | interval_start | interval_end |
+--------------------------------------+----------------+--------------+
| f84c4937-eb10-11ed-a2ff-000c294b702c | 1 | 18 |
+--------------------------------------+----------------+--------------+
1 row in set (0.00 sec)
[(none)]> SELECT @@GLOBAL.gtid_executed;
+------------------------------------------+
| @@GLOBAL.gtid_executed |
+------------------------------------------+
| f84c4937-eb10-11ed-a2ff-000c294b702c:1-8 |
+------------------------------------------+
1 row in set (0.00 sec)
[(none)]> SHOW VARIABLES LIKE 'gtid_executed';
+---------------+------------------------------------------+
| Variable_name | Value |
+---------------+------------------------------------------+
| gtid_executed | f84c4937-eb10-11ed-a2ff-000c294b702c:1-8 |
+---------------+------------------------------------------+
1 row in set (0.00 sec)
[(none)]> SHOW MASTER STATUS\G
*************************** 1. row ***************************
File: binlog.000001
Position: 1006
Binlog_Do_DB:
Binlog_Ignore_DB:
Executed_Gtid_Set: f84c4937-eb10-11ed-a2ff-000c294b702c:1-18
1 row in set (0.00 sec)
GTID 的自动跳过功能意味着在源库上提交的事务在副本库上最多只能应用一次,以保证一致性。在给定服务器上提交具有指定 GTID 的事务后,该服务器将忽略后续任何使用相同 GTID 执行事务的尝试。
GTID 格式如下:
GTID = server_uuid:transaction_id
参数 server_uuid
来自于数据目录下的 auto.cnf
文件,如果不存在,在启动 MySQL Server 时会自动创建。
[root@mysql ~]# cat /data/mysql/auto.cnf
[auto]
server-uuid=f84c4937-eb10-11ed-a2ff-000c294b702c
[(none)]> SHOW VARIABLES LIKE 'server_uuid';
+---------------+--------------------------------------+
| Variable_name | Value |
+---------------+--------------------------------------+
| server_uuid | f84c4937-eb10-11ed-a2ff-000c294b702c |
+---------------+--------------------------------------+
1 row in set (0.00 sec)
transaction_id
是在事务提交的时候由系统顺序分配的一个序列号,单调递增且连续,最大为 2^63-1(9,223,372,036,854,775,807)。
server_uuid
和 transaction_id
以冒号(:)分隔,组成 GTID,例如:
3E11FA47-71CA-11E1-9E33-C80AA9429562:23
GTID Sets
GTID 集和是由一个或多个单个 GTID 或 GTID 范围组成的集合。
一个范围内的 GTID 可以合并为单个表达式,如下所示:
3E11FA47-71CA-11E1-9E33-C80AA9429562:1-5
多个单个 GTID 或 GTID 范围也可以包含在单个表达式中,用冒号分隔,以下所示:
3E11FA47-71CA-11E1-9E33-C80AA9429562:1-3:11:47-49
GTID 集和可以包含单个 GTID 和 GTID 范围的任意组合,并且可以包含来自不同服务器的 GTID。以下示例表示在副本库上来自 2 个源库的事务组成的 GTID,存储在参数 gtid_executed
中:
2174B383-5441-11E8-B90A-C80AA9429562:1-3, 24DA167-0C0C-11E8-8442-00059A3C7B00:1-19
GTID 的语法为:
gtid_set:
uuid_set [, uuid_set] ...
| ''
uuid_set:
uuid:interval[:interval]...
uuid:
hhhhhhhh-hhhh-hhhh-hhhh-hhhhhhhhhhhh
h:
[0-9|A-F]
interval:
n[-n]
(n >= 1)
mysql.gtid_executed Table
GTID 存储在 mysql.gtid_executed
表中,且只有在参数 gtid_mode
为 ON 或 ON_PERMISSIVE (默认为 OFF)时才会存储,即使 MySQL Server 处于只读模式也会写入该表。
[(none)]> SHOW VARIABLES LIKE 'gtid_mode';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| gtid_mode | ON |
+---------------+-------+
1 row in set (0.01 sec)
[(none)]> desc mysql.gtid_executed;
+----------------+----------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------------+----------+------+-----+---------+-------+
| source_uuid | char(36) | NO | PRI | NULL | |
| interval_start | bigint | NO | PRI | NULL | |
| interval_end | bigint | NO | | NULL | |
+----------------+----------+------+-----+---------+-------+
3 rows in set (0.01 sec)
[(none)]> SELECT * FROM mysql.gtid_executed;
+--------------------------------------+----------------+--------------+
| source_uuid | interval_start | interval_end |
+--------------------------------------+----------------+--------------+
| f84c4937-eb10-11ed-a2ff-000c294b702c | 1 | 18 |
+--------------------------------------+----------------+--------------+
1 row in set (0.00 sec)
如果发出 RESET MASTER
语句,则会清空 mysql.gtid_executed
表。
[(none)]> RESET MASTER;
Query OK, 0 rows affected (0.01 sec)
[(none)]> SELECT * FROM mysql.gtid_executed;
Empty set (0.00 sec)
mysql.gtid_executed Table Compression
随着时间的推移,表 mysql.gtid_executed
中可能会填充许多行,类似如下:
[(none)]> SELECT * FROM mysql.gtid_executed;
+--------------------------------------+----------------+--------------+
| source_uuid | interval_start | interval_end |
+--------------------------------------+----------------+--------------+
| f84c4937-eb10-11ed-a2ff-000c294b702c | 1 | 1 |
| f84c4937-eb10-11ed-a2ff-000c294b702c | 2 | 2 |
| f84c4937-eb10-11ed-a2ff-000c294b702c | 3 | 3 |
| f84c4937-eb10-11ed-a2ff-000c294b702c | 4 | 4 |
| f84c4937-eb10-11ed-a2ff-000c294b702c | 5 | 5 |
| f84c4937-eb10-11ed-a2ff-000c294b702c | 6 | 6 |
| f84c4937-eb10-11ed-a2ff-000c294b702c | 7 | 7 |
| f84c4937-eb10-11ed-a2ff-000c294b702c | 8 | 8 |
+--------------------------------------+----------------+--------------+
8 rows in set (0.00 sec)
MySQL Server 在切换二进制日志时将多行压缩为单行来节约空间,如下所示:
[(none)]> flush logs;
Query OK, 0 rows affected (0.02 sec)
[(none)]> SELECT * FROM mysql.gtid_executed;
+--------------------------------------+----------------+--------------+
| source_uuid | interval_start | interval_end |
+--------------------------------------+----------------+--------------+
| f84c4937-eb10-11ed-a2ff-000c294b702c | 1 | 8 |
+--------------------------------------+----------------+--------------+
1 row in set (0.00 sec)
MySQL Server 使用名称为 thread/sql/compress_gtid_table
的专用前台线程执行压缩。此线程未在 SHOW PROCESSLIST
的输出中列出,通过查询表 performance_schema.threads
查看:
[(none)]> SELECT * FROM performance_schema.threads WHERE NAME LIKE '%compress_gtid_table%'\G
*************************** 1. row ***************************
THREAD_ID: 48
NAME: thread/sql/compress_gtid_table
TYPE: FOREGROUND
PROCESSLIST_ID: 7
PROCESSLIST_USER: NULL
PROCESSLIST_HOST: NULL
PROCESSLIST_DB: NULL
PROCESSLIST_COMMAND: Daemon
PROCESSLIST_TIME: 8007
PROCESSLIST_STATE: Suspending
PROCESSLIST_INFO: NULL
PARENT_THREAD_ID: 1
ROLE: NULL
INSTRUMENTED: YES
HISTORY: YES
CONNECTION_TYPE: NULL
THREAD_OS_ID: 11168
RESOURCE_GROUP: SYS_default
EXECUTION_ENGINE: PRIMARY
CONTROLLED_MEMORY: 8240
MAX_CONTROLLED_MEMORY: 8240
TOTAL_MEMORY: 14482
MAX_TOTAL_MEMORY: 14618
1 row in set (0.00 sec)
GTID Life Cycle
GTID 的生命周期包括以下阶段:
- 在源库执行并提交事务。为客户端事务分配一个 GTID,该 GTID 由源库的 UUID 和尚未使用的最小非零事务序列号组成。GTID 被写入源库的二进制日志中(位于事务前面)。如果客户端事务没有写入二进制日志(例如,事务被过滤,或者事务只读),则不会为其分配 GTID。
- 如果为事务分配了 GTID,则 GTID 在事务提交时会以原子方式持久化,写入二进制日志中事务开始位置(作为
Gtid_log_event
)。 - 如果为事务分配了 GTID,则在事务提交后将该 GTID 添加到参数
gtid_executed
的 GTID 集和中,此 GTID 集和包含所有已提交事务的 GTID,并在复制中用作表示 MySQL Server 状态的令牌。源库默认启用二进制日志,参数gtid_executed
中的 GTID 集和是已应用事务的完整记录,但表mysql.gtid_executed
不是,因为最近的历史记录仍在当前二进制日志文件中。 - 将二进制日志数据传输到副本库并存储在副本库的中继日志中,副本库读取日志中的 GTID 并设置参数
gtid_next
值为此 GTID,则副本库下一个事务会使用此 GTID。 - 副本库验证尚未有线程取得参数
gtid_next
的 GTID 的所有权以处理事务。如果多个客户端尝试同时应用同一事务,MySQL Server 仅让其中一个客户端执行。副本库的参数gtid_owned
显示当前正在使用的 GTID 以及拥有它的线程的 ID。如果 GTID 已被使用,则不会引发任何错误,并且使用自动跳过函数忽略事务。 - 如果尚未使用 GTID,则副本库将应用复制的事务。由于参数
gtid_next
被设置为源库已分配的 GTID,因此副本库不会尝试为此事务生成新的 GTID,而是使用存储在参数gtid_next
中的 GTID。 - 如果在副本库上启用了二进制日志,则 GTID 将在事务提交时以原子方式持久化,写入二进制日志中事务开始位置(作为
Gtid_log_event
)。 - 如果在副本库上禁用了二进制日志,则通过将 GTID 直接写入表
mysql.gtid_executed
来原子持久化。 - 在副本库上提交复制的事务后,通过将该 GTID 添加到副本库参数
gtid_executed
中的 GTID 集和中,以非原子方式外部化。对于源库,GTID 集和包含所有已提交的 GTID 事务。如果在副本库上禁用二进制日志,则表mysql.gtid_executed
也是副本库上应用事务的完整记录。如果在副本库上启用了二进制日志,这意味着某些 GTID 仅记录在二进制日志中,那么参数gtid_executed
中的 GTID 集和是唯一的完整记录。
在源库上过滤掉的客户端事务不会分配 GTID,不会添加到参数 gtid_executed
的 GTID 集和中,也不会添加到表 mysql.gtid_executed
中。但是,在副本库上将保留过滤掉的复制事务的 GTID。如果副本库启用二进制日志,则过滤掉的事务将作为 Gtid_log_event
写入二进制日志,后跟仅包含 BEGIN
和 COMMIT
语句的空事务。如果副本库禁用二进制日志,则过滤掉的事务的 GTID 将写入表 mysql.gtid_executed
。保留过滤掉的事务的 GTID 以确保可以压缩表 mysql.gtid_executed
和参数 gtid_executed
中的 GTID 集和,还确保在副本库重新连接到源库时不会再次检索过滤掉的事务。
在多线程副本库(replica_parallel_workers > 0
或者 slave_parallel_workers > 0
)上,事务可以并行应用,因此复制的事务可以无序提交(除非设置了 replica_preserve_commit_order=1
或者 slave_preserve_commit_order=1
)。发生这种情况时,参数 gtid_executed
的 GTID 集和包含多个 GTID 范围,它们之间存在间隙。(在源库或单线程副本库上,为单调递增的 GTID,数字之间没有间隙)多线程副本库上的间隙仅出现在最近应用的事务中,随着复制的进行将被填充。使用 STOP REPLICA
语句干净地停止复制线程时,将应用正在进行的事务,以便填充间隙。
参数 replica_parallel_workers
从 MySQL 8.0.27 开始默认值为 4,之前默认值为 0。 参数 replica_preserve_commit_order
从 MySQL 8.0.27 开始默认值为 ON,之前默认值为 OFF。即在当前版本 8.0.32,副本库默认 4 个应用线程并行执行复制事务,且执行顺序与副本库的中继日志里面的事务顺序一致。
[(none)]> SHOW VARIABLES LIKE 'replica_parallel_workers';
+--------------------------+-------+
| Variable_name | Value |
+--------------------------+-------+
| replica_parallel_workers | 4 |
+--------------------------+-------+
1 row in set (0.01 sec)
[(none)]> SHOW VARIABLES LIKE 'replica_preserve_commit_order';
+-------------------------------+-------+
| Variable_name | Value |
+-------------------------------+-------+
| replica_preserve_commit_order | ON |
+-------------------------------+-------+
1 row in set (0.01 sec)
The gtid_purged System Variable
参数 gtid_purged
(@@GLOBAL.gtid_purged
)中的 GTID 集合包含了所有已提交事务的 GTID,且这些事务不存在于服务器上的任何二进制日志文件中,也就是说这些事务对应的二进制日志文件已经被删除了。gtid_purged
是 gtid_executed
的子集。
以下示例为切换二进制日志并删除之前的二进制日志,就可以看到被删除二进制日志对应的 GTID 出现在参数 gtid_purged
中:
[(none)]> SELECT @@GLOBAL.gtid_executed;
+------------------------------------------+
| @@GLOBAL.gtid_executed |
+------------------------------------------+
| f84c4937-eb10-11ed-a2ff-000c294b702c:1-2 |
+------------------------------------------+
1 row in set (0.00 sec)
[(none)]> SELECT @@GLOBAL.gtid_purged;
+----------------------+
| @@GLOBAL.gtid_purged |
+----------------------+
| |
+----------------------+
1 row in set (0.01 sec)
[(none)]> FLUSH LOGS;
Query OK, 0 rows affected (0.06 sec)
[(none)]> SHOW BINARY LOGS;
+---------------+-----------+-----------+
| Log_name | File_size | Encrypted |
+---------------+-----------+-----------+
| binlog.000001 | 180 | No |
| binlog.000002 | 180 | No |
| binlog.000003 | 180 | No |
| binlog.000004 | 662 | No |
| binlog.000005 | 197 | No |
+---------------+-----------+-----------+
5 rows in set (0.00 sec)
[(none)]> SHOW MASTER STATUS\G
*************************** 1. row ***************************
File: binlog.000005
Position: 197
Binlog_Do_DB:
Binlog_Ignore_DB:
Executed_Gtid_Set: f84c4937-eb10-11ed-a2ff-000c294b702c:1-2
1 row in set (0.00 sec)
[(none)]> PURGE BINARY LOGS TO 'binlog.000005';
Query OK, 0 rows affected (0.01 sec)
[(none)]> SHOW BINARY LOGS;
+---------------+-----------+-----------+
| Log_name | File_size | Encrypted |
+---------------+-----------+-----------+
| binlog.000005 | 197 | No |
+---------------+-----------+-----------+
1 row in set (0.00 sec)
[(none)]> SELECT @@GLOBAL.gtid_executed;
+------------------------------------------+
| @@GLOBAL.gtid_executed |
+------------------------------------------+
| f84c4937-eb10-11ed-a2ff-000c294b702c:1-2 |
+------------------------------------------+
1 row in set (0.00 sec)
[(none)]> SELECT @@GLOBAL.gtid_purged;
+------------------------------------------+
| @@GLOBAL.gtid_purged |
+------------------------------------------+
| f84c4937-eb10-11ed-a2ff-000c294b702c:1-2 |
+------------------------------------------+
1 row in set (0.00 sec)
Resetting the GTID Execution History
使用 RESET MASTER
语句重置 GITD 执行历史,包括:
- 设置参数
gtid_purged
为空字符串。 - 设置参数
gtid_executed
为空字符串。 - 清除表
mysql.gtid_executed
数据。 - 如果启用了二进制日志,会删除二进制日志文件,清理二进制日志索引文件。
当前二进制日志文件和二进制日志索引文件:
[root@mysql ~]# ll /data/mysql/binlog.*
-rw-r----- 1 mysql mysql 2465 May 6 20:46 /data/mysql/binlog.000001
-rw-r----- 1 mysql mysql 220 May 6 20:50 /data/mysql/binlog.000002
-rw-r----- 1 mysql mysql 471 May 7 10:41 /data/mysql/binlog.000003
-rw-r----- 1 mysql mysql 48 May 7 05:52 /data/mysql/binlog.index
[root@mysql ~]# cat /data/mysql/binlog.index
./binlog.000001
./binlog.000002
./binlog.000003
重置 GTID 执行历史,查看参数 gtid_executed
的值和查询表 mysql.gtid_executed
:
[(none)]> SELECT @@GLOBAL.gtid_executed;
+------------------------------------------+
| @@GLOBAL.gtid_executed |
+------------------------------------------+
| f84c4937-eb10-11ed-a2ff-000c294b702c:1-9 |
+------------------------------------------+
1 row in set (0.00 sec)
[(none)]> SELECT * FROM mysql.gtid_executed;
+--------------------------------------+----------------+--------------+
| source_uuid | interval_start | interval_end |
+--------------------------------------+----------------+--------------+
| f84c4937-eb10-11ed-a2ff-000c294b702c | 1 | 8 |
| f84c4937-eb10-11ed-a2ff-000c294b702c | 9 | 9 |
+--------------------------------------+----------------+--------------+
2 rows in set (0.00 sec)
[(none)]> RESET MASTER;
Query OK, 0 rows affected (0.02 sec)
[(none)]> SELECT @@GLOBAL.gtid_executed;
+------------------------+
| @@GLOBAL.gtid_executed |
+------------------------+
| |
+------------------------+
1 row in set (0.00 sec)
[(none)]> SELECT * FROM mysql.gtid_executed;
Empty set (0.01 sec)
再次查看二进制日志文件和二进制日志索引文件:
[root@mysql ~]# ll /data/mysql/binlog.*
-rw-r----- 1 mysql mysql 157 May 7 17:31 /data/mysql/binlog.000001
-rw-r----- 1 mysql mysql 16 May 7 17:31 /data/mysql/binlog.index
[root@mysql ~]# cat /data/mysql/binlog.index
./binlog.000001
GTID Auto-Positioning
使用 GTID 进行复制不再需要指定二进制日志文件名及具体位置,只需要在 CHANGE REPLICATION SOURCE TO
语句(从 MySQL 8.0.23 起)或者 CHANGE MASTER TO
语句(在 MySQL 8.0.23 前)中启用 SOURCE_AUTO_POSITION
| MASTER_AUTO_POSITION
选项即可。
当副本库使用 GTID 及启用 MASTER_AUTO_POSITION
选项时,到源库的连接将自动定位复制位置,此时源库也必须设置 gtid_mode=ON
。初始握手时,副本库发送一个 GTID 集和,其中包含已接收和已提交的事务,此 GTID 集和等于参数 gtid_executed
(@@GLOBAL.gtid_executed
) 中的 GTID 集和与 performance_schema.replication_connection_status
表 RECEIVED_TRANSACTION_SET
字段中记录为已接收事务的 GTID 集和的并集。
当源库接收到副本库 GITD 集合后,从最近的二进制日志文件开始,检查每个二进制日志文件标头中的 Previous_gtids_log_event
,当找到第一个不包含副本库缺失事务的 Previous_gtids_log_event
时,则源库从该二进制日志文件开始,读取其及后续二进制文件中的事务,发送副本库缺少的事务及其 GTID,并跳过副本库发送的 GTID 集合中的事务。以上交互可以确保源库仅发送副本库尚未接收或提交的 GTID 事务。
如果源库删除了副本库所需的二进制日志文件,或者在参数 gtid_purged
中添加了副本库所需事务的 GTID,则源库会将错误 ER_MASTER_HAS_PURGED_REQUIRED_GTIDS
发送到副本库,副本库无法启动复制。故需要修改参数 binlog_expire_logs_seconds
,调整二进制日志保留时间以避免该问题。
如果源库没有指定参数 sync_binlog=1
,则当遇到电源故障或操作系统崩溃时,有可能源库会比副本库少一些 GTID。这是由于写二进制日志文件时先使用 wirte()
从内存写到操作系统缓存,再 fsync()
写到磁盘。假设源库在 wirte()
之后, fsync()
之前,同时副本库也拉取了这些未 fsync()
的二进制日志,此时源库宕机,则源库这部分二进制日志丢失,而副本库则获得并应用了这部分二进制日志。源库会将错误 ER_SLAVE_HAS_MORE_GTIDS_THAN_MASTER
发送到副本库,副本库无法启动复制。此时可以将源库配置为副本库,从其他副本库中获取二进制日志应用丢失的事务,再切换为源库。
对于多源 GTID 复制,需要确保副本库上所有的通道过滤器配置相同。
Setting Up Replication Using GTIDs
使用 GTID 配置复制步骤如下:
- 如果已经配置了非 GTID 复制,则在源库和副本库配置参数
read_only
为 ON。如果没有配置,则从第 3 步开始。
源库:
[(none)]> SET @@GLOBAL.read_only = ON;
Query OK, 0 rows affected (0.00 sec)
副本库:
[(none)]> SET @@GLOBAL.read_only = ON;
Query OK, 0 rows affected (0.00 sec)
等待所有正在运行的事务提交或者回滚,副本库与源库一致。
- 停止源库和副本库。
源库:
[root@source ~]# systemctl stop mysqld.service
副本库:
[root@replica1 ~]# systemctl stop mysqld.service
- 源库和副本库启用 GTID。
源库修改参数文件并启动:
[root@mysql ~]# vi /etc/my.cnf
[mysqld]
server_id=44135
gtid_mode=on
enforce_gtid_consistency=on
[root@mysql ~]# systemctl start mysqld.service
副本库修改参数并启动:
[root@replica1 ~]# vi /etc/my.cnf
[mysqld]
server_id=44136
gtid_mode=on
enforce_gtid_consistency=on
event_scheduler=OFF
relay_log=relay-binlog
relay_log_index=/data/mysql/relay-binlog.index
[root@replica1 ~]# systemctl start mysqld.service
源库必须启用二进制日志(默认启用),副本库最好也启用二进制日志。
- 配置复制。
副本库执行:
[(none)]> RESET REPLICA;
Query OK, 0 rows affected (0.02 sec)
[(none)]> CHANGE REPLICATION SOURCE TO
SOURCE_HOST='192.168.44.135',
SOURCE_PORT = 3306,
SOURCE_USER='repl',
SOURCE_PASSWORD='pUrEv!2rAx',
SOURCE_AUTO_POSITION = 1;
Query OK, 0 rows affected, 2 warnings (0.02 sec)
- 创建备份,参考 MySQL Backup and Recovery。启用 GTID 后,之前做的备份就失效了,不能用于启用了 GTID 的数据库,需要创建新的备份。
- 副本库启用复制。
[(none)]> START REPLICA;
Query OK, 0 rows affected (0.05 sec)
[(none)]> SHOW REPLICA STATUS\G
*************************** 1. row ***************************
Replica_IO_State: Waiting for source to send event
Source_Host: 192.168.44.135
Source_User: repl
Source_Port: 3306
Connect_Retry: 60
Source_Log_File: binlog.000004
Read_Source_Log_Pos: 157
Relay_Log_File: relay-binlog.000002
Relay_Log_Pos: 367
Relay_Source_Log_File: binlog.000004
Replica_IO_Running: Yes
Replica_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_Source_Log_Pos: 157
Relay_Log_Space: 574
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Source_SSL_Allowed: No
Source_SSL_CA_File:
Source_SSL_CA_Path:
Source_SSL_Cert:
Source_SSL_Cipher:
Source_SSL_Key:
Seconds_Behind_Source: 0
Source_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Source_Server_Id: 44135
Source_UUID: f84c4937-eb10-11ed-a2ff-000c294b702c
Source_Info_File: mysql.slave_master_info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Replica_SQL_Running_State: Replica has read all relay log; waiting for more updates
Source_Retry_Count: 86400
Source_Bind:
Last_IO_Error_Timestamp:
Last_SQL_Error_Timestamp:
Source_SSL_Crl:
Source_SSL_Crlpath:
Retrieved_Gtid_Set:
Executed_Gtid_Set:
Auto_Position: 1
Replicate_Rewrite_DB:
Channel_Name:
Source_TLS_Version:
Source_public_key_path:
Get_Source_public_key: 0
Network_Namespace:
1 row in set (0.00 sec)
注意:
- 如果副本库执行
START REPLICA
出现以下报错:ERROR 1872 (HY000): Slave failed to initialize relay log info structure from the repository
则需要执行
RESET REPLICA
命令后重新执行CHANGE REPLICATION SOURCE TO
命令。
- 如果在
SHOW REPLICA STATUS
出现如下错误:Last_IO_Error: Got fatal error 1236 from master when reading data from binary log: 'Slave has more GTIDs than the master has, using the master's SERVER_UUID. This may indicate that the end of the binary log was truncated or that the last binary log file was lost, e.g., after a power or disk failure when sync_binlog != 1. The master may or may not have rolled back transactions that were already replicated to the slave. Suggest to replicate any transactions that master has rolled back from slave to master, and/or commit empty transactions on master to account for transactions that have been'
表示副本库比源库多 GTID,如果源库的
@@GLOBAL.gtid_executed
为空,则可以在副本库执行RESET MASTER
清空该参数,再重启复制即可。
Using GTIDs for Failover and Scaleout
使用 GTID 进行复制的环境可以方便地进行故障切换和横向扩展。
对于已经存在用户数据的源库,配置副本库时,常用的数据初始化方式有:
在源库使用 mysqldump 创建导出文件, 使用
--source-data
选项自动添加CHANGE REPLICATION SOURCE TO
或者CHANGE MASTER TO
语句到导出文件中。使用备份工具,例如 Percona XtraBackup,备份源库,恢复到副本库。
关闭源库和副本库,直接拷贝源库的数据目录到副本库的数据目录。
Restrictions on Replication with GTIDs
由于基于 GTID 的复制依赖于事务,因此使用 GTID 进行复制存在一些限制:
- 涉及非事务存储引擎的更新:使用 GTID 时,对非事务存储引擎表(例如 MyISAM)的更新不能与事务存储引擎表(例如 InnoDB)的更新在同一事务中,可能会导致将多个 GTID 分配给同一事务。另外对非事务上创建触发器也有可能导致此问题。
- 语句
CREATE TABLE ... SELECT statements
:在 MySQL 8.0.21 之前,在使用 GTID 复制时不允许使用CREATE TABLE ... SELECT statements
语句。因为当使用基于语句的复制时(参数binlog_format
为STATEMENT
),此将此语句使用 1 个 GTID 记录为 1 个事务,但在使用基于行的复制时(参数binlog_format
为ROW
),此将此语句使用 2 个 GTID 记录为 2 个事务。如果在源库使用基于语句的复制,而在副本库使用基于行的复制,则副本库就不能正确处理该事务。从 MySQL 8.0.21 开始,对于支持原子 DDL 操作的存储引擎,将此语句记录为 1 个事务。 - 临时表:当参数
binlog_format
为STATEMENT
,且使用 GTID 时,不能在事务,存储过程,函数和触发器中使用CREATE TEMPORARY TABLE
和DROP TEMPORARY TABLE
语句。从 MySQL 8.0.13 开始,当参数binlog_format
为ROW
,且使用 GTID 时,允许在事务,存储过程,函数和触发器中使用CREATE TEMPORARY TABLE
和DROP TEMPORARY TABLE
语句。因为此语句不会被写入到二进制日志,也就不会复制到副本库。 - 阻止执行不支持的语句:设置参数
enforce_gtid_consistency
为ON
,阻止执行会导致 GTID 复制失败的语句。 - 跳过事务:使用基于 GTID 的复制时,参数
sql_replica_skip_counter
或sql_slave_skip_counter
不可用。如果需要跳过事务,可以使用源库的gtid_executed
参数值。如果在副本库使用CHANGE REPLICATION SOURCE TO
语句的ASSIGN_GTIDS_TO_ANONYMOUS_TRANSACTIONS
选项配置 GTID 复制,则可以使用参数sql_replica_skip_counter
或sql_slave_skip_counter
。
Verifying Replication of Anonymous Transactions
验证是否已复制所有匿名事务:
- 源库查看状态。
[(none)]> SHOW MASTER STATUS\G
*************************** 1. row ***************************
File: binlog.000006
Position: 197
Binlog_Do_DB:
Binlog_Ignore_DB:
Executed_Gtid_Set: f84c4937-eb10-11ed-a2ff-000c294b702c:1-2
1 row in set (0.00 sec)
- 副本库查看是否已执行到源库查询出来的二进制日志位置。
[(none)]> SELECT SOURCE_POS_WAIT('binlog.000006', 197);
+---------------------------------------+
| SOURCE_POS_WAIT('binlog.000006', 197) |
+---------------------------------------+
| 0 |
+---------------------------------------+
1 row in set (0.00 sec)
返回值为 0 表示副本库上没有需要等待执行到指定二进制日志位置的事件。
MySQL Multi-Source Replication
副本库可以从多个源库复制数据。
- 副本库可以创建多个复制通道,通道名称唯一,不超过 64 个字符,不区分大小写。一个复制通道对应一个源库,最多 256 个。每个通道有一个 I/O 线程,一个或多个 SQL 线程及其中继日志。
- 应用事务时,不检测和解决冲突。
- 使用参数
replica_parallel_workers
(从 MySQL 8.0.26 起)或slave_parallel_workers
为每个通道配置多线程复制,包括多个 SQL 线程及一个协调线程。 - 可以在指定复制通道上配置过滤。
Configuring Multi-Source Replication
多源复制环境至少需要 2 个源库,一个副本库,环境如下:
角色 | 主机名 | 数据库 |
---|---|---|
源库 1 | source1 | db1 |
源库 2 | source2 | db2 |
副本库 | replica | db1,db2 |
参考:Installing MySQL on Linux 安装源库和副本库。
多源复制既可以使用基于二进制日志文件位置的复制,参考 Setting Up Binary Log File Position Based Replication,也可以使用基于 GTID 的复制,参考 Replication with Global Transaction Identifiers。
在源库上创建复制用户并授权:
[(none)]> CREATE USER 'repl'@'%' IDENTIFIED WITH mysql_native_password BY 'pUrEv!2rAx';
Query OK, 0 rows affected (0.01 sec)
[(none)]> GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
Query OK, 0 rows affected (0.01 sec)
Provisioning a Multi-Source Replica for GTID-Based Replication
在多源复制中,不能通过克隆或者复制数据目录的方式来初始化,最佳方式为使用 mysqldump 从源库导出指定数据,在副本库导入数据。
步骤如下:
- 使用基于 GITD 的复制,需要调整参数。
源库参数文件增加如下配置并重启服务:
[root@source1 ~]# vi /etc/my.cnf
[mysqld]
server_id=44135
gtid_mode=on
enforce_gtid_consistency=on
[root@source1 ~]# systemctl start mysqld.service
[root@source2 ~]# vi /etc/my.cnf
[mysqld]
server_id=44136
gtid_mode=on
enforce_gtid_consistency=on
[root@source2 ~]# systemctl start mysqld.service
副本库参数文件增加如下配置并重启服务:
[root@replica ~]# vi /etc/my.cnf
[mysqld]
server_id=44137
gtid_mode=on
enforce_gtid_consistency=on
event_scheduler=OFF
relay_log=relay-binlog
relay_log_index=/data/mysql/relay-binlog.index
[root@replica ~]# systemctl start mysqld.service
- 分别在两个源库上导出需要同步的数据库。
[root@source1 ~]# mysqldump --single-transaction --triggers --routines --set-gtid-purged=COMMENTED --databases db1 > dumpM1.sql
[root@source2 ~]# mysqldump --single-transaction --triggers --routines --set-gtid-purged=COMMENTED --databases db2 > dumpM2.sql
- 在副本库导入。
[root@replica ~]# mysql < dumpM1.sql
[root@replica ~]# mysql < dumpM2.sql
Adding GTID-Based Sources to a Multi-Source Replica
在副本库上使用 CHANGE REPLICATION SOURCE TO
语句(从 MySQL 8.0.23 起)或者 CHANGE MASTER TO
语句(在 MySQL 8.0.23 前)为每个源库配置复制通道。
[(none)]> CHANGE REPLICATION SOURCE TO
SOURCE_HOST='192.168.44.135',
SOURCE_USER='repl',
SOURCE_PASSWORD='pUrEv!2rAx',
SOURCE_AUTO_POSITION=1 FOR CHANNEL "source_1";
Query OK, 0 rows affected, 2 warnings (0.03 sec)
[(none)]> CHANGE REPLICATION SOURCE TO
SOURCE_HOST='192.168.44.136',
SOURCE_USER='repl',
SOURCE_PASSWORD='pUrEv!2rAx',
SOURCE_AUTO_POSITION=1 FOR CHANNEL "source_2";
Query OK, 0 rows affected, 2 warnings (0.02 sec)
配置副本库只从源库 source1
中复制 db1
,从源库 source2
中复制 db2
。
[(none)]> CHANGE REPLICATION FILTER REPLICATE_WILD_DO_TABLE = ('db1.%') FOR CHANNEL "source_1";
Query OK, 0 rows affected (0.00 sec)
[(none)]> CHANGE REPLICATION FILTER REPLICATE_WILD_DO_TABLE = ('db2.%') FOR CHANNEL "source_2";
Query OK, 0 rows affected (0.00 sec)
Starting Multi-Source Replicas
启动所有复制通道。
[(none)]> START REPLICA;
Query OK, 0 rows affected (0.12 sec)
或者启动指定复制通道。
[(none)]> START REPLICA FOR CHANNEL "source_1";
Query OK, 0 rows affected (0.07 sec)
[(none)]> START REPLICA FOR CHANNEL "source_2";
Query OK, 0 rows affected (0.03 sec)
查看通道复制状态。
[(none)]> SHOW REPLICA STATUS FOR CHANNEL "source_1"\G
*************************** 1. row ***************************
Replica_IO_State: Waiting for source to send event
Source_Host: 192.168.44.135
Source_User: repl
Source_Port: 3306
Connect_Retry: 60
Source_Log_File: binlog.000001
Read_Source_Log_Pos: 1106
Relay_Log_File: relay-binlog-source_1.000002
Relay_Log_Pos: 1316
Relay_Source_Log_File: binlog.000001
Replica_IO_Running: Yes
Replica_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table: db1.%
Replicate_Wild_Ignore_Table:
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Source_Log_Pos: 1106
Relay_Log_Space: 1532
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Source_SSL_Allowed: No
Source_SSL_CA_File:
Source_SSL_CA_Path:
Source_SSL_Cert:
Source_SSL_Cipher:
Source_SSL_Key:
Seconds_Behind_Source: 0
Source_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Source_Server_Id: 44135
Source_UUID: f84c4937-eb10-11ed-a2ff-000c294b702c
Source_Info_File: mysql.slave_master_info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Replica_SQL_Running_State: Replica has read all relay log; waiting for more updates
Source_Retry_Count: 86400
Source_Bind:
Last_IO_Error_Timestamp:
Last_SQL_Error_Timestamp:
Source_SSL_Crl:
Source_SSL_Crlpath:
Retrieved_Gtid_Set: f84c4937-eb10-11ed-a2ff-000c294b702c:1-5
Executed_Gtid_Set: 42f223db-eb20-11ed-a7a4-000c2986525b:1-5,
f84c4937-eb10-11ed-a2ff-000c294b702c:1-5
Auto_Position: 1
Replicate_Rewrite_DB:
Channel_Name: source_1
Source_TLS_Version:
Source_public_key_path:
Get_Source_public_key: 0
Network_Namespace:
1 row in set (0.00 sec)
[(none)]> SHOW REPLICA STATUS FOR CHANNEL "source_2"\G
*************************** 1. row ***************************
Replica_IO_State: Waiting for source to send event
Source_Host: 192.168.44.136
Source_User: repl
Source_Port: 3306
Connect_Retry: 60
Source_Log_File: binlog.000001
Read_Source_Log_Pos: 1106
Relay_Log_File: relay-binlog-source_2.000002
Relay_Log_Pos: 1316
Relay_Source_Log_File: binlog.000001
Replica_IO_Running: Yes
Replica_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table: db2.%
Replicate_Wild_Ignore_Table:
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Source_Log_Pos: 1106
Relay_Log_Space: 1532
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Source_SSL_Allowed: No
Source_SSL_CA_File:
Source_SSL_CA_Path:
Source_SSL_Cert:
Source_SSL_Cipher:
Source_SSL_Key:
Seconds_Behind_Source: 0
Source_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Source_Server_Id: 44136
Source_UUID: 42f223db-eb20-11ed-a7a4-000c2986525b
Source_Info_File: mysql.slave_master_info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Replica_SQL_Running_State: Replica has read all relay log; waiting for more updates
Source_Retry_Count: 86400
Source_Bind:
Last_IO_Error_Timestamp:
Last_SQL_Error_Timestamp:
Source_SSL_Crl:
Source_SSL_Crlpath:
Retrieved_Gtid_Set: 42f223db-eb20-11ed-a7a4-000c2986525b:1-5
Executed_Gtid_Set: 42f223db-eb20-11ed-a7a4-000c2986525b:1-5,
f84c4937-eb10-11ed-a2ff-000c294b702c:1-5
Auto_Position: 1
Replicate_Rewrite_DB:
Channel_Name: source_2
Source_TLS_Version:
Source_public_key_path:
Get_Source_public_key: 0
Network_Namespace:
1 row in set (0.00 sec)
Stopping Multi-Source Replicas
停止所有复制通道。
[(none)]> STOP REPLICA;
Query OK, 0 rows affected, 1 warning (0.01 sec)
或者停止指定复制通道。
[(none)]> STOP REPLICA FOR CHANNEL "source_1";
Query OK, 0 rows affected (0.01 sec)
[(none)]> STOP REPLICA FOR CHANNEL "source_2";
Query OK, 0 rows affected (0.01 sec)
Resetting Multi-Source Replicas
重置所有复制通道。
[(none)]> STOP REPLICA;
Query OK, 0 rows affected, 2 warnings (0.01 sec)
[(none)]> RESET REPLICA;
Query OK, 0 rows affected (0.04 sec)
或者重置指定复制通道。
[(none)]> RESET REPLICA FOR CHANNEL "source_1";
Query OK, 0 rows affected (0.01 sec)
[(none)]> RESET REPLICA FOR CHANNEL "source_2";
Query OK, 0 rows affected (0.01 sec)
RESET REPLICA
语句只是清除复制位置及中继日志,RESET REPLICA ALL
语句才能重置连接参数和复制过滤器。
Monitoring Multi-Source Replication
除了使用 SHOW REPLICA STATUS
查看所有复制通道状态或 SHOW REPLICA STATUS FOR CHANNEL channel
查看指定复制通道状态外,还可以查询 performance_schema
模式下的表来监控复制通道。
例如查看所有复制通道的连接状态:
[(none)]> SELECT * FROM performance_schema.replication_connection_status\G
*************************** 1. row ***************************
CHANNEL_NAME: source_1
GROUP_NAME:
SOURCE_UUID: f84c4937-eb10-11ed-a2ff-000c294b702c
THREAD_ID: 211
SERVICE_STATE: ON
COUNT_RECEIVED_HEARTBEATS: 14
LAST_HEARTBEAT_TIMESTAMP: 2023-05-09 22:57:26.610770
RECEIVED_TRANSACTION_SET:
LAST_ERROR_NUMBER: 0
LAST_ERROR_MESSAGE:
LAST_ERROR_TIMESTAMP: 0000-00-00 00:00:00.000000
LAST_QUEUED_TRANSACTION:
LAST_QUEUED_TRANSACTION_ORIGINAL_COMMIT_TIMESTAMP: 0000-00-00 00:00:00.000000
LAST_QUEUED_TRANSACTION_IMMEDIATE_COMMIT_TIMESTAMP: 0000-00-00 00:00:00.000000
LAST_QUEUED_TRANSACTION_START_QUEUE_TIMESTAMP: 0000-00-00 00:00:00.000000
LAST_QUEUED_TRANSACTION_END_QUEUE_TIMESTAMP: 0000-00-00 00:00:00.000000
QUEUEING_TRANSACTION:
QUEUEING_TRANSACTION_ORIGINAL_COMMIT_TIMESTAMP: 0000-00-00 00:00:00.000000
QUEUEING_TRANSACTION_IMMEDIATE_COMMIT_TIMESTAMP: 0000-00-00 00:00:00.000000
QUEUEING_TRANSACTION_START_QUEUE_TIMESTAMP: 0000-00-00 00:00:00.000000
*************************** 2. row ***************************
CHANNEL_NAME: source_2
GROUP_NAME:
SOURCE_UUID: 42f223db-eb20-11ed-a7a4-000c2986525b
THREAD_ID: 229
SERVICE_STATE: ON
COUNT_RECEIVED_HEARTBEATS: 14
LAST_HEARTBEAT_TIMESTAMP: 2023-05-09 22:57:26.637502
RECEIVED_TRANSACTION_SET:
LAST_ERROR_NUMBER: 0
LAST_ERROR_MESSAGE:
LAST_ERROR_TIMESTAMP: 0000-00-00 00:00:00.000000
LAST_QUEUED_TRANSACTION:
LAST_QUEUED_TRANSACTION_ORIGINAL_COMMIT_TIMESTAMP: 0000-00-00 00:00:00.000000
LAST_QUEUED_TRANSACTION_IMMEDIATE_COMMIT_TIMESTAMP: 0000-00-00 00:00:00.000000
LAST_QUEUED_TRANSACTION_START_QUEUE_TIMESTAMP: 0000-00-00 00:00:00.000000
LAST_QUEUED_TRANSACTION_END_QUEUE_TIMESTAMP: 0000-00-00 00:00:00.000000
QUEUEING_TRANSACTION:
QUEUEING_TRANSACTION_ORIGINAL_COMMIT_TIMESTAMP: 0000-00-00 00:00:00.000000
QUEUEING_TRANSACTION_IMMEDIATE_COMMIT_TIMESTAMP: 0000-00-00 00:00:00.000000
QUEUEING_TRANSACTION_START_QUEUE_TIMESTAMP: 0000-00-00 00:00:00.000000
2 rows in set (0.00 sec)
Common Replication Administration Tasks
本节介绍如何检查复制状态、如何暂停复制以及如何跳过副本库上的失败事务。
Checking Replication Status
在副本库上执行 SHOW REPLICA STATUS
语句获取复制状态信息。
[(none)]> SHOW REPLICA STATUS\G
*************************** 1. row ***************************
Replica_IO_State: Waiting for source to send event
Source_Host: 192.168.44.135
Source_User: repl
Source_Port: 3306
Connect_Retry: 60
Source_Log_File: binlog.000004
Read_Source_Log_Pos: 157
Relay_Log_File: relay-binlog.000002
Relay_Log_Pos: 367
Relay_Source_Log_File: binlog.000004
Replica_IO_Running: Yes
Replica_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_Source_Log_Pos: 157
Relay_Log_Space: 574
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Source_SSL_Allowed: No
Source_SSL_CA_File:
Source_SSL_CA_Path:
Source_SSL_Cert:
Source_SSL_Cipher:
Source_SSL_Key:
Seconds_Behind_Source: 0
Source_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Source_Server_Id: 44135
Source_UUID: f84c4937-eb10-11ed-a2ff-000c294b702c
Source_Info_File: mysql.slave_master_info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Replica_SQL_Running_State: Replica has read all relay log; waiting for more updates
Source_Retry_Count: 86400
Source_Bind:
Last_IO_Error_Timestamp:
Last_SQL_Error_Timestamp:
Source_SSL_Crl:
Source_SSL_Crlpath:
Retrieved_Gtid_Set:
Executed_Gtid_Set:
Auto_Position: 1
Replicate_Rewrite_DB:
Channel_Name:
Source_TLS_Version:
Source_public_key_path:
Get_Source_public_key: 0
Network_Namespace:
1 row in set (0.00 sec)
其中:
Replica_IO_State
:当前复制状态。Replica_IO_Running
:读取源库二进制日志的 I/O 线程是否正在运行,正常情况下为Yes
。Replica_SQL_Running
:执行中继日志中事件的 SQL 线程是否正在运行,正常情况下为Yes
。Last_IO_Error
,Last_SQL_Error
:处理中继日志时,I/O 线程和 SQL 线程的报错,正常情况下应该为空白。Seconds_Behind_Source
:副本库落后源库的秒数,为0
表示副本库已经追上源库数据。Source_Log_File
,Read_Source_Log_Pos
:源库二进制日志位置,表示副本库 I/O 线程读取事件的对应位置。Relay_Source_Log_File
,Exec_Source_Log_Pos
:源库二进制日志位置,表示副本库 SQL 线程执行事件的对应位置。Relay_Log_File
,Relay_Log_Pos
:副本库中继日志位置,表示副本库 SQL 线程执行事件对应中继日志的位置。
在源库,使用 SHOW PROCESSLIST
查看连接到副本库线程的状态。
[(none)]> SHOW PROCESSLIST\G
*************************** 2. row ***************************
Id: 8
User: repl
Host: 192.168.44.137:60996
db: NULL
Command: Binlog Dump GTID
Time: 4173
State: Source has sent all binlog to replica; waiting for more updates
在源库,使用 SHOW REPLICAS
查看副本库的信息。
[(none)]> SHOW REPLICAS;
+-----------+------+------+-----------+--------------------------------------+
| Server_Id | Host | Port | Source_Id | Replica_UUID |
+-----------+------+------+-----------+--------------------------------------+
| 44137 | | 3306 | 44135 | fe074cfd-ebe0-11ed-9b23-000c29c21d3a |
+-----------+------+------+-----------+--------------------------------------+
1 row in set (0.00 sec)
[(none)]> SHOW REPLICAS;
+-----------+------+------+-----------+--------------------------------------+
| Server_Id | Host | Port | Source_Id | Replica_UUID |
+-----------+------+------+-----------+--------------------------------------+
| 44137 | | 3306 | 44136 | fe074cfd-ebe0-11ed-9b23-000c29c21d3a |
+-----------+------+------+-----------+--------------------------------------+
1 row in set (0.00 sec)
Pausing Replication on the Replica
在副本库使用 STOP REPLICA
和 START REPLICA
语句停止和启动复制。
停止复制:
[(none)]> STOP REPLICA;
Query OK, 0 rows affected, 2 warnings (0.01 sec)
停止复制后,I/O 线程停止从源库二进制日志读取事件写入到中继日志,SQL 线程停止从中继日志中读取事件并执行。建议在停止停止 MySQL Server 之前,先使用 STOP REPLICA
停止复制。
单独停止 I/O 线程和 SQL 线程:
[(none)]> STOP REPLICA IO_THREAD;
Query OK, 0 rows affected (0.02 sec)
[(none)]> STOP REPLICA SQL_THREAD;
Query OK, 0 rows affected (0.03 sec)
启动复制:
[(none)]> START REPLICA;
Query OK, 0 rows affected (0.10 sec)
单独启动 I/O 线程和 SQL 线程:
[(none)]> START REPLICA IO_THREAD;
Query OK, 0 rows affected (0.01 sec)
[(none)]> START REPLICA SQL_THREAD;
Query OK, 0 rows affected (0.09 sec)
可以根据需要只启动 I/O 线程或者 SQL 线程。
Skipping Transactions
如果由于事务问题导致复制停止,则可以跳过失败的事务来恢复复制。在跳过事务之前,需要确保 I/O 线程和 SQL 线程都已停止。
首先需要确定导致错误的事务,可以从 performance_schema.replication_applier_status_by_worker
表中获取错误和上次成功应用的事务的详细信息。
[(none)]> SELECT * FROM performance_schema.replication_applier_status_by_worker WHERE CHANNEL_NAME='source_1' AND WORKER_ID=1\G
*************************** 1. row ***************************
CHANNEL_NAME: source_1
WORKER_ID: 1
THREAD_ID: 124
SERVICE_STATE: ON
LAST_ERROR_NUMBER: 0
LAST_ERROR_MESSAGE:
LAST_ERROR_TIMESTAMP: 0000-00-00 00:00:00.000000
LAST_APPLIED_TRANSACTION:
LAST_APPLIED_TRANSACTION_ORIGINAL_COMMIT_TIMESTAMP: 0000-00-00 00:00:00.000000
LAST_APPLIED_TRANSACTION_IMMEDIATE_COMMIT_TIMESTAMP: 0000-00-00 00:00:00.000000
LAST_APPLIED_TRANSACTION_START_APPLY_TIMESTAMP: 0000-00-00 00:00:00.000000
LAST_APPLIED_TRANSACTION_END_APPLY_TIMESTAMP: 0000-00-00 00:00:00.000000
APPLYING_TRANSACTION:
APPLYING_TRANSACTION_ORIGINAL_COMMIT_TIMESTAMP: 0000-00-00 00:00:00.000000
APPLYING_TRANSACTION_IMMEDIATE_COMMIT_TIMESTAMP: 0000-00-00 00:00:00.000000
APPLYING_TRANSACTION_START_APPLY_TIMESTAMP: 0000-00-00 00:00:00.000000
LAST_APPLIED_TRANSACTION_RETRIES_COUNT: 0
LAST_APPLIED_TRANSACTION_LAST_TRANSIENT_ERROR_NUMBER: 0
LAST_APPLIED_TRANSACTION_LAST_TRANSIENT_ERROR_MESSAGE:
LAST_APPLIED_TRANSACTION_LAST_TRANSIENT_ERROR_TIMESTAMP: 0000-00-00 00:00:00.000000
APPLYING_TRANSACTION_RETRIES_COUNT: 0
APPLYING_TRANSACTION_LAST_TRANSIENT_ERROR_NUMBER: 0
APPLYING_TRANSACTION_LAST_TRANSIENT_ERROR_MESSAGE:
APPLYING_TRANSACTION_LAST_TRANSIENT_ERROR_TIMESTAMP: 0000-00-00 00:00:00.000000
1 row in set (0.00 sec)
还可以使用 mysqlbinlog 检索和显示错误发生时记录的事件。另外,可以在副本库上使用 SHOW RELAYLOG EVENTS
或者在源库上使用 SHOW BINLOG EVENTS
获取信息。
源库:
[(none)]> SHOW BINLOG EVENTS;
+---------------+------+----------------+-----------+-------------+-------------------------------------------------------------------+
| Log_name | Pos | Event_type | Server_id | End_log_pos | Info |
+---------------+------+----------------+-----------+-------------+-------------------------------------------------------------------+
| binlog.000001 | 4 | Format_desc | 44135 | 126 | Server ver: 8.0.32, Binlog ver: 4 |
| binlog.000001 | 126 | Previous_gtids | 44135 | 157 | |
| binlog.000001 | 157 | Gtid | 44135 | 234 | SET @@SESSION.GTID_NEXT= 'f84c4937-eb10-11ed-a2ff-000c294b702c:1' |
| binlog.000001 | 234 | Query | 44135 | 339 | create database db1 /* xid=24 */ |
| binlog.000001 | 339 | Gtid | 44135 | 416 | SET @@SESSION.GTID_NEXT= 'f84c4937-eb10-11ed-a2ff-000c294b702c:2' |
| binlog.000001 | 416 | Query | 44135 | 525 | use `db1`; create table t1(id int) /* xid=27 */ |
| binlog.000001 | 525 | Gtid | 44135 | 604 | SET @@SESSION.GTID_NEXT= 'f84c4937-eb10-11ed-a2ff-000c294b702c:3' |
| binlog.000001 | 604 | Query | 44135 | 678 | BEGIN |
| binlog.000001 | 678 | Table_map | 44135 | 725 | table_id: 101 (db1.t1) |
| binlog.000001 | 725 | Write_rows | 44135 | 765 | table_id: 101 flags: STMT_END_F |
| binlog.000001 | 765 | Xid | 44135 | 796 | COMMIT /* xid=28 */ |
| binlog.000001 | 796 | Gtid | 44135 | 873 | SET @@SESSION.GTID_NEXT= 'f84c4937-eb10-11ed-a2ff-000c294b702c:4' |
| binlog.000001 | 873 | Query | 44135 | 951 | FLUSH TABLES |
| binlog.000001 | 951 | Gtid | 44135 | 1028 | SET @@SESSION.GTID_NEXT= 'f84c4937-eb10-11ed-a2ff-000c294b702c:5' |
| binlog.000001 | 1028 | Query | 44135 | 1106 | FLUSH TABLES |
| binlog.000001 | 1106 | Stop | 44135 | 1129 | |
+---------------+------+----------------+-----------+-------------+-------------------------------------------------------------------+
16 rows in set (0.00 sec)
副本库:
[(none)]> SHOW RELAYLOG EVENTS FOR CHANNEL'source_1';
+------------------------------+-----+----------------+-----------+-------------+------------------------------------+
| Log_name | Pos | Event_type | Server_id | End_log_pos | Info |
+------------------------------+-----+----------------+-----------+-------------+------------------------------------+
| relay-binlog-source_1.000005 | 4 | Format_desc | 44137 | 126 | Server ver: 8.0.32, Binlog ver: 4 |
| relay-binlog-source_1.000005 | 126 | Previous_gtids | 44137 | 157 | |
| relay-binlog-source_1.000005 | 157 | Rotate | 44135 | 0 | binlog.000002;pos=4 |
| relay-binlog-source_1.000005 | 201 | Format_desc | 44135 | 126 | Server ver: 8.0.32, Binlog ver: 4 |
| relay-binlog-source_1.000005 | 323 | Rotate | 0 | 0 | binlog.000002;pos=197 |
| relay-binlog-source_1.000005 | 367 | Rotate | 44137 | 426 | relay-binlog-source_1.000006;pos=4 |
+------------------------------+-----+----------------+-----------+-------------+------------------------------------+
6 rows in set (0.00 sec)
在跳过事务,重启复制前,需要确认:
- 停止复制的事务是否来自未知或不受信任的源库。
- 停止复制的事务是否需要应用于副本库。
- 停止复制的事务是否需要应用于源库。
这里只考虑使用 GTID 进行复制的环境。当使用 GTID(gtid_mode=ON
)时,即使事务的内容被过滤掉,已提交事务的 GTID 也会保留在副本库上。此功能可防止副本库在使用 GTID 自动定位重新连接到源库时检索之前过滤掉的事务。还可以在副本库上使用提交空事务替换失败事务的方法来跳过事务。
此方法不适用于在 CHANGE REPLICATION SOURCE TO
语句中使用 ASSIGN_GTIDS_TO_ANONYMOUS_TRANSACTIONS
选项配置的复制通道。
如果失败事务在工作线程中产生一个错误,则可以直接从 performance_schema.replication_applier_status_by_worker
表的 APPLYING_TRANSACTION
字段获取 GTID,再使用此 GITD,在副本库上使用 SHOW RELAYLOG EVENTS
或者在源库上使用 SHOW BINLOG EVENTS
查询具体事务。
使用以上方法确定失败事务后,就可以在副本库上提交一个有相同 GTID 的空事务替换失败的事务,例如:
SET GTID_NEXT='aaa-bbb-ccc-ddd:N';
BEGIN;
COMMIT;
SET GTID_NEXT='AUTOMATIC';
副本库上的这个空事务意味着当使用 START REPLICA
语句重启复制时,会使用自动跳过函数来忽略对应的失败事务,因为此时副本库认为此 GTID 的事务已经被应用过了。
Replication Implementation
复制基于源库记录二进制日志中对数据库的所有更改。MySQL Server 启动后,会将修改数据库结构或内容的所有事件写入到二进制日志。
Replication Formats
复制格式对应于二进制日志格式,二进制日志格式有:
- Statement-Based:基于语句的二进制日志格式,记录的是 SQL 语句。
- Row-Based:基于行的二进制日志格式,默认格式,记录的是受影响的行数据,如果使用 InnoDB 表且事务隔离级别为
READ COMMITTED
则只能使用此格式。 - Mixed:混合日志格式,默认采用 Statement-Based,在某些情况会使用 Row-Based。
在配置文件中使用参数 binlog_format
指定二进制日志格式,默认为 row
。
[mysqld]
binlog_format=row
建议不要在运行时调整参数 binlog_format
。
注意:
从 MySQL 8.0.34 开始将废弃参数
binlog_format
,只能使用基于行的二进制日志格式。
Replication Channels
在多个源库的复制环境,副本库可以打开多个复制通道,每个通道对应一个源库。每个通道有一个 I/O 线程,一个或多个 SQL 线程及其中继日志。当通道的 I/O 线程接收到来自源库的事务后,事务将被写入到通道的中继日志并传递给通道的 SQL 线程。
副本库上最多可配置 255 个通道,通道的名称需唯一,不超过 64 个字符,不区分大小写。
使用参数 replica_parallel_workers
(从 MySQL 8.0.26 起)或 slave_parallel_workers
为每个通道配置多线程复制,包括多个 SQL 线程及一个协调线程。
从 MySQL 8.0 开始,可以在指定复制通道上配置过滤。对于使用 GTID 的复制,如果副本库可能从多个源库获取相同事务,则必须确保所有通道的过滤配置相同。
为了之前版本兼容,MySQL Server 自动创建一个默认通道,其名称为空字符串("")。此通道始终存在,不能创建或删除。如果未创建其他通道,则使用默认通道。
Commands for Operations on a Single Channel
以下语句可以使用 FOR CHANNEL channel
子句配置复制通道:
CHANGE REPLICATION SOURCE TO
CHANGE MASTER TO
START REPLICA
(MySQL 8.0.22 前,START SLAVE
)STOP REPLICA
(MySQL 8.0.22 前,STOP SLAVE
)SHOW RELAYLOG EVENTS
FLUSH RELAY LOGS
SHOW REPLICA STATUS
(MySQL 8.0.22 前,SHOW SLAVE STATUS
)RESET REPLICA
(MySQL 8.0.22 前,RESET SLAVE
)
以下函数有 channel
参数:
MASTER_POS_WAIT()
SOURCE_POS_WAIT()
以下语句不能用于 group_replication_recovery
通道:
START REPLICA
STOP REPLICA
以下语句不能用于 group_replication_applier
通道:
START REPLICA
STOP REPLICA
SHOW REPLICA STATUS
Compatibility with Previous Replication Statements
当副本库有多个通道,以下语句不使用 FOR CHANNEL channel
子句时:
START REPLICA
启动所有通道的复制线程,除了group_replication_recovery
和group_replication_applier
通道。STOP REPLICA
停止所有通道的复制线程,除了group_replication_recovery
和group_replication_applier
通道。SHOW REPLICA STATUS
报告所有通道的状态,除了group_replication_applier
通道。RESET REPLICA
重置所有通道。
警告:
谨慎使用
RESET REPLICA
语句,该语句会删除所有通道及其中继日志,并只重建默认通道。
在有多个通道的副本库,以下语句需要指定通道:
SHOW RELAYLOG EVENTS
CHANGE REPLICATION SOURCE TO
CHANGE MASTER TO
MASTER_POS_WAIT()
SOURCE_POS_WAIT()
否则会报如下错误:
ERROR 3079 (HY000): Multiple channels exist on the slave. Please provide channel name as an argument.
Startup Options and Replication Channels
对于所有通道:
log_replica_updates
:指定副本库是否将接收到的事务写入到二进制日志,默认为ON
。relay_log_purge
:指定是否自动删除不再需要的中继日志,默认为ON
。replica_transaction_retries
:指定 SQL 线程对失败事务的最大自动重试次数,默认为 10,设置为 0 表示禁用自动重试。表performance_schema.replication_applier_status
的COUNT_TRANSACTIONS_RETRIES
字段显示各个通道的事务重试次数,表performance_schema.replication_applier_status_by_worker
显示事务重试的详细信息及错误。skip_replica_start
:指定在副本库启动时是否不启动 I/O 线程和 SQL 线程,默认为OFF
。replica_skip_errors
:指定当 SQL 线程执行的语句返回错误时是否跳过错误继续处理,默认为OFF
。
对于每个通道:
max_relay_log_size
:指定每个通道对应的每个中继日志文件的最大值,默认值为 0 表示使用参数max_binlog_size
的值,该参数默认值为 1GB。relay_log_space_limit
:指定每个通道对应的所有中继日志文件的最大值,默认值为 0 表示无限制。replica_parallel_workers
:指定每个通道的 SQL 线程数量,从 MySQL 8.0.27 开始,默认值为 4。replica_checkpoint_group
:在执行检查点操作前,多线程复制可以处理的最大事务数量,默认值为 512。relay_log_index
:指定每个通道中继日志索引文件名的前缀。relay_log
:指定每个通道中继日志文件名的前缀。replica_net_timeout
:指定副本库等待源库数据的超时时间,默认为 60 秒。--replica-skip-counter=N
:指定每个通道可以跳过的事件。
Replication Channel Naming Conventions
复制通道的名称唯一,不超过 64 个字符,不区分大小写。
不能使用 group_replication_applier
和 group_replication_recovery
作为复制通道名称。
命名规则为 relay_log_basename-channel.xxxxxx
,其中 relay_log_basename
由参数 relay_log
指定,channel
为通道名称。
[(none)]> SHOW VARIABLES LIKE 'relay_log';
+---------------+--------------+
| Variable_name | Value |
+---------------+--------------+
| relay_log | relay-binlog |
+---------------+--------------+
1 row in set (0.00 sec)
[(none)]> SHOW VARIABLES LIKE 'relay_log_index';
+-----------------+--------------------------------+
| Variable_name | Value |
+-----------------+--------------------------------+
| relay_log_index | /data/mysql/relay-binlog.index |
+-----------------+--------------------------------+
1 row in set (0.01 sec)
Replication Threads
MySQL 复制使用三个主线程实现,包括一个源库线程和两个副本库线程:
- Binary log dump thread:副本库连接到源库时,源库创建的线程,发送二进制日志内容到副本库。
- Replication I/O receiver thread:副本库执行
START REPLICA
语句后,创建的 I/O (接收)线程,连接到源库请求其发送二进制日志的更新记录。该线程读取源库Binlog Dump
线程发送的更新,拷贝到中继日志。 - Replication SQL applier thread:副本库创建的 SQL(应用)线程,读取接收线程写入的中继日志并执行其中的事务。
Monitoring Replication Main Threads
在源库使用 SHOW PROCESSLIST
命令查看线程:
[(none)]> SHOW PROCESSLIST\G
*************************** 2. row ***************************
Id: 9
User: repl
Host: 192.168.44.137:56628
db: NULL
Command: Binlog Dump GTID
Time: 3285
State: Source has sent all binlog to replica; waiting for more updates
以上表示线程 9 为 Binlog Dump GTID
线程,当前 State
的信息表示所有的更改都已经发送到了副本库。
在副本库使用 SHOW PROCESSLIST
命令查看线程:
[(none)]> SHOW PROCESSLIST\G
*************************** 1. row ***************************
Id: 5
User: system user
Host: connecting host
db: NULL
Command: Connect
Time: 103
State: Waiting for source to send event
Info: NULL
*************************** 2. row ***************************
Id: 6
User: system user
Host:
db: NULL
Command: Query
Time: 103
State: Replica has read all relay log; waiting for more updates
Info: NULL
线程 5 的 State
的信息表示其为 I/O 线程,线程 6 的 State
的信息表示其为 SQL 线程。
Relay Log and Replication Metadata Repositories
副本库用于复制过程的信息存储库有:
- Relay Log:中继日志,由 I/O 线程写入,包含从源库二进制日志读取的事务。
- Connection Metadata Repository:包含 I/O 线程连接到源库及从源库二进制日志获取事务所需的信息,写入
mysql.slave_master_info
表。 - Applier Metadata Repository:包含 SQL 线程从中继日志中读取和应用事务所需的信息,写入
mysql.slave_relay_log_info
表。
The Relay Log
与二进制日志类似,中继日志包含了描述数据库更改的事件,包括中继日志文件和中继日志索引文件,位于数据目录下。
[root@replica ~]# ll /data/mysql/relay-binlog*
-rw-r----- 1 mysql mysql 180 May 9 22:50 /data/mysql/relay-binlog.000001
-rw-r----- 1 mysql mysql 22 May 9 22:50 /data/mysql/relay-binlog.index
-rw-r----- 1 mysql mysql 216 May 12 11:25 /data/mysql/relay-binlog-source_1.000011
-rw-r----- 1 mysql mysql 367 May 12 11:25 /data/mysql/relay-binlog-source_1.000012
-rw-r----- 1 mysql mysql 62 May 12 11:25 /data/mysql/relay-binlog-source_1.index
-rw-r----- 1 mysql mysql 216 May 12 11:25 /data/mysql/relay-binlog-source_2.000011
-rw-r----- 1 mysql mysql 367 May 12 11:25 /data/mysql/relay-binlog-source_2.000012
-rw-r----- 1 mysql mysql 62 May 12 11:25 /data/mysql/relay-binlog-source_2.index
副本库在以下情况会创建新的中继日志文件:
- I/O 线程启动。
- 使用
FLUSH LOGS
或者mysqladmin flush-logs
刷新日志。 - 达到参数
max_relay_log_size
设定的值,如果该参数为默认值 0,则为参数max_binlog_size
的值 。
SQL 线程执行完中继日志文件中的事件后会自动将其删除。
Replication Metadata Repositories
副本库创建两个复制元数据存储库:
- 连接元数据存储库(Connection Metadata Repository):包含 I/O 线程连接到源库及从源库二进制日志获取事务所需的信息,写入
mysql.slave_master_info
表。 - 应用元数据存储库(Applier Metadata Repository):包含 SQL 线程从中继日志中读取和应用事务所需的信息,写入
mysql.slave_relay_log_info
表。
如果使用基于二进制日志文件位置的复制,当重新启动复制时,会读取这两个存储库以确定之前从源库读取二进制日志的位置和处理中继日志的位置。
如果使用基于 GTID 的复制,则副本库不需要使用复制元数据存储库来确定日志位置,但需要复制元数据存储库的其他信息。
重要:
不要手动更新或插入
mysql.slave_master_info
和mysql.slave_relay_log_info
表。由于表
mysql.slave_master_info
包含连接到源库的用户账户和密码,需限制其访问权限。
使用 RESET REPLICA
语句清除复制元数据存储库,但保留复制连接参数。
在 MySQL 8.0 之前,必须指定参数 master_info_repository=TABLE
和 relay_log_info_repository=TABLE
才能将复制元数据存储库创建为表,否则创建为数据目录下名为 master.info
和 relay-log.info
的文件。从 MySQL 8.0 开始,默认创建复制元数据存储库为表
当备份副本库或传输快照来创建新的副本库,需确保包括了表 mysql.slave_master_info
和 mysql.slave_relay_log_info
。
另外还有一个内部使用的存储库:Applier Worker Metadata Repository,存储多线程复制环境中工作线程的状态信息,包括每个工作线程对应的中继日志文件名称和位置及源库二进制日志文件名称和位置,存储到表 mysql.slave_worker_info
中。可以访问 performance_schema.replication_applier_status_by_worker
表获取工作线程的状态信息。
复制元数据存储库包含的信息与 SHOW REPLICA STATUS
语句输出类似。下表显示连接元数据存储库对应的 mysql.slave_master_info
表与 SHOW REPLICA STATUS
语句输出的对比:
slave_master_info Table Column | SHOW REPLICA STATUS Column | Description |
---|---|---|
Number_of_lines | [None] | Number of columns in the table (or lines in the file) |
Master_log_name | Source_Log_File | The name of the binary log currently being read from the source |
Master_log_pos | Read_Source_Log_Pos | The current position within the binary log that has been read from the source |
Host | Source_Host | The host name of the replication source server |
User_name | Source_User | The replication user account name used to connect to the source |
User_password | Password (not shown by SHOW REPLICA STATUS ) | The replication user account password used to connect to the source |
Port | Source_Port | The network port used to connect to the replication source server |
Connect_retry | Connect_Retry | The period (in seconds) that the replica waits before trying to reconnect to the source |
Enabled_ssl | Source_SSL_Allowed | Whether the replica supports SSL connections |
Ssl_ca | Source_SSL_CA_File | The file used for the Certificate Authority (CA) certificate |
Ssl_capath | Source_SSL_CA_Path | The path to the Certificate Authority (CA) certificate |
Ssl_cert | Source_SSL_Cert | The name of the SSL certificate file |
Ssl_cipher | Source_SSL_Cipher | The list of possible ciphers used in the handshake for the SSL connection |
Ssl_key | Source_SSL_Key | The name of the SSL key file |
Ssl_verify_server_cert | Source_SSL_Verify_Server_Cert | Whether to verify the server certificate |
Heartbeat | [None] | Interval between replication heartbeats, in seconds |
Bind | Source_Bind | Which of the replica's network interfaces should be used for connecting to the source |
Ignored_server_ids | Replicate_Ignore_Server_Ids | The list of server IDs to be ignored. Note that for Ignored_server_ids the list of server IDs is preceded by the total number of server IDs to ignore. |
Uuid | Source_UUID | The source's unique ID |
Retry_count | Source_Retry_Count | Maximum number of reconnection attempts permitted |
Ssl_crl | [None] | Path to an SSL certificate revocation-list file |
Ssl_crlpath | [None] | Path to a directory containing SSL certificate revocation-list files |
Enabled_auto_position | Auto_position | Whether GTID auto-positioning is in use or not |
Channel_name | Channel_name | The name of the replication channel |
Tls_version | Source_TLS_Version | TLS version on the source |
Public_key_path | Source_public_key_path | Name of the RSA public key file |
Get_public_key | Get_source_public_key | Whether to request RSA public key from source |
Network_namespace | Network_namespace | Network namespace |
Master_compression_algorithm | [None] | Permitted compression algorithms for the connection to the source |
Master_zstd_compression_level | [None] | zstd compression level |
Tls_ciphersuites | [None] | Permitted ciphersuites for TLSv1.3 |
Source_connection_auto_failover | [None] | Whether the asynchronous connection failover mechanism is activated |
Gtid_only | [None] | Whether the channel uses only GTIDs and does not persist positions |
下表显示应用元数据存储库对应的 mysql.slave_relay_log_info
表与 SHOW REPLICA STATUS
语句输出的对比:
slave_relay_log_info Table Column | SHOW REPLICA STATUS Column | Description |
---|---|---|
Number_of_lines | [None] | Number of columns in the table or lines in the file |
Relay_log_name | Relay_Log_File | The name of the current relay log file |
Relay_log_pos | Relay_Log_Pos | The current position within the relay log file; events up to this position have been executed on the replica database |
Master_log_name | Relay_Source_Log_File | The name of the source's binary log file from which the events in the relay log file were read |
Master_log_pos | Exec_Source_Log_Pos | The equivalent position within the source's binary log file of the events that have been executed on the replica |
Sql_delay | SQL_Delay | The number of seconds that the replica must lag the source |
Number_of_workers | [None] | The number of worker threads for applying replication transactions in parallel |
Id | [None] | ID used for internal purposes; currently this is always 1 |
Channel_name | Channel_name | The name of the replication channel |
Privilege_checks_username | [None] | The user name for the PRIVILEGE_CHECKS_USER account for the channel |
Privilege_checks_hostname | [None] | The host name for the PRIVILEGE_CHECKS_USER account for the channel |
Require_row_format | [None] | Whether the channel accepts only row-based events |
Require_table_primary_key_check | [None] | The channel's policy on whether tables must have primary keys for CREATE TABLE and ALTER TABLE operations |
Assign_gtids_to_anonymous_transactions_type | [None] | If the channel assigns a GTID to replicated transactions that do not already have one, using the replica's local UUID, this value is LOCAL ; if the channel does so using instead a UUID which has been set manually, the value is UUID . If the channel does not assign a GTID in such cases, the value is OFF . |
Assign_gtids_to_anonymous_transactions_value | [None] | The UUID used in the GTIDs assigned to anonymous transactions |
How Servers Evaluate Replication Filtering Rules
本节介绍在使用基于行的二进制日志格式时,如何配置复制过滤规则。建议在副本库上配置过滤规则。
Evaluation of Database-Level Replication and Binary Logging Options
使用基于行的二进制日志格式,在副本库配置数据库级的过滤规则如下:
- 是否配置参数
replicate-do-db
指定需要复制的数据库?
- Yes:是否有匹配的数据库?
- Yes:继续到第 3 步。
- No:忽略更新并退出。
- No:继续到第 2 步。
- 是否配置参数
replicate-ignore-db
指定需要忽略的数据库?
- Yes:是否有匹配的数据库?
- Yes:忽略更新并退出。
- No:继续到第 3 步。
- No:继续到第 3 步。
- 继续检查表级的过滤规则。
Evaluation of Table-Level Replication Options
使用基于行的二进制日志格式,在副本库配置表级的过滤规则如下:
- 是否配置参数
replicate-do-table
指定需要复制的表?
- Yes:是否有匹配的表?
- Yes:执行更新并退出。
- No:继续到第 2 步。
- No:继续到第 2 步。
- 是否配置参数
replicate-ignore-table
指定需要忽略的表?
- Yes:是否有匹配的表?
- Yes:忽略更新并退出。
- No:继续到第 3 步。
- No:继续到第 3 步。
- 是否配置参数
replicate-wild-do-table
指定需要复制的表?
- Yes:是否有匹配的表?
- Yes:执行更新并退出。
- No:继续到第 4 步。
- No:继续到第 4 步。
- 是否配置参数
replicate-wild-ignore-table
指定需要忽略的表?
- Yes:是否有匹配的表?
- Yes:忽略更新并退出。
- No:继续到第 5 步。
- No:继续到第 5 步。
- 是否需要测试其他表?
- Yes:回到第 1 步。
- No:继续到第 6 步。
- 是否有其他
replicate-do-table
或replicate-wild-do-table
参数?
- Yes:忽略更新并退出。
- No:执行更新并退出。
Replication Channel Based Filters
当副本库上有多个复制通道时,从 MySQL 8.0 开始,既可以全局配置,也可以为通道配置复制过滤。
Changing Channel Specific Replication Filters Online
使用 CHANGE REPLICATION FILTER
语句在线配置复制过滤,需要先关闭 SQL 线程。使用 FOR CHANNEL channel
子句指定通道,例如:
CHANGE REPLICATION FILTER REPLICATE_DO_DB=(db1) FOR CHANNEL channel_1;
如果不指定通道,则全局为所有通道配置复制过滤。
Removing Channel Specific Replication Filters
通过指定空的过滤类型,移除某种过滤:
CHANGE REPLICATION FILTER REPLICATE_REWRITE_DB=() FOR CHANNEL channel_1;
Replication Solutions
本节介绍复制的使用场景。
Using Replication for Backups
Backing Up a Replica Using mysqldump
如果需要备份的数据量比较小,则可以使用 mysqldump 从副本库导出数据,步骤如下:
- 停止复制。
[root@replica ~]# mysqladmin stop-replica
Replication stopped
在比较繁忙的系统,建议只停止 SQL 线程:
[root@replica ~]# mysql -e 'STOP REPLICA SQL_THREAD;'
- 使用 mysqldump 从副本库导出数据。
[root@replica ~]# mysqldump --single-transaction --all-databases --triggers --routines --events > fulldb.dump
- 启动复制。
[root@replica ~]# mysqladmin start-replica
Replication started
Backing Up Raw Data from a Replica
可以关闭副本库,拷贝数据文件创建一致备份,步骤如下:
- 关闭副本库。
[root@replica ~]# mysqladmin stop-replica
Replication stopped
[root@replica ~]# systemctl stop mysqld.service
- 拷贝数据文件。
[root@replica ~]# tar -cvzf mysql.tar.gz /data/mysql/
- 启动副本库。
[root@replica ~]# systemctl start mysqld.service
Backing Up a Source or Replica by Making It Read Only
可以通过获取全局读锁并使用参数 read_only
指定副本库为只读状态,以便备份:
- 将副本库置为只读,只能查询和块更新。
[(none)]> FLUSH TABLE WITH READ LOCK;
Query OK, 0 rows affected (0.01 sec)
[(none)]> SET GLOBAL read_only=ON;
Query OK, 0 rows affected (0.00 sec)
[(none)]> SHOW VARIABLES LIKE 'read_only';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| read_only | ON |
+---------------+-------+
1 row in set (0.10 sec)
执行备份,例如使用 mysqldump。
备份完成后,将副本库置为读写。
[(none)]> SET GLOBAL read_only=OFF;
Query OK, 0 rows affected (0.00 sec)
[(none)]> SHOW VARIABLES LIKE 'read_only';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| read_only | OFF |
+---------------+-------+
1 row in set (0.00 sec)
[(none)]> UNLOCK TABLES;
Query OK, 0 rows affected (0.00 sec)
Handling an Unexpected Halt of a Replica
对于服务器意外停机,副本库应使用如下最佳配置:
- 设置参数
gtid_mode=ON
,使用 GITD 配置复制,到源库的连接使用 GTID 自动定位可以自动定位和获取丢失的事务。 - 从 MySQL 8.0.27 起,当设置
gtid_mode=ON
,使用 GITD 配置复制时,可以在CHANGE REPLICATION SOURCE TO
语句中指定GTID_ONLY=1
,使副本库在恢复过程中仅使用 GTID,并停止将二进制日志和中继日志文件名和文件位置保存到复制元数据存储库。 - 设置参数
sync_relay_log=1
(默认为 10000),表示 I/O 线程将收到的每个事务写入中继日志后将其同步到磁盘。尽管这是最安全的设置,但需要大量的磁盘 I/O,也是最慢的配置。对于多线程复制,建议配置。 - 设置参数
innodb_flush_log_at_trx_commit=1
(默认为 1),在每次事务提交时将 InnoDB 重做日志数据写入和刷新到磁盘。结合参数sync_relay_log=1
,进一步确保了 InnoDB 表和 InnoDB 重做日志与中继日志一致。 - 设置参数
relay_log_info_repository = TABLE
(默认为 TABLE)。 - 设置参数
relay_log_recovery = ON
(默认为 OFF),在 MySQL Server 启动时立即启用自动中继日志恢复,如果现有的中继日志被损坏或不一致,则忽略现有的中继日志,创建新的中继日志文件,从副本库应用元数据存储库中记录的 SQL 线程位置开始,向源库获取事务。
Monitoring Row-based Replication
使用 Performance Schema 监控三种基于行的复制事件类型(Write,Update,Delete):
- 启用
stage/sql/Applying batch of row changes%
Instruments:
[(none)]> UPDATE performance_schema.setup_instruments SET ENABLED = 'YES'
WHERE NAME LIKE 'stage/sql/Applying batch of row changes%';
Query OK, 0 rows affected (0.14 sec)
Rows matched: 3 Changed: 0 Warnings: 0
- SQL 线程应用了一些事件后,查询表
performance_schema.events_stages_current
查看处理进度:
[(none)]> SELECT WORK_COMPLETED, WORK_ESTIMATED FROM performance_schema.events_stages_current
WHERE EVENT_NAME LIKE 'stage/sql/Applying batch of row changes%';
- 如果启用参数
binlog_rows_query_log_events
(默认为 OFF),查询信息会被存储到二进制日志,查询performance_schema.threads
查看触发事件的原始查询:
[(none)]> SELECT processlist_db, processlist_state, processlist_info FROM performance_schema.threads
WHERE processlist_state LIKE 'stage/sql/Applying batch of row changes%';
Improving Replication Performance
如果要为源库配置多个副本库,建议使用级联方式,减少对源库 I/O 和网络的负载,提高整体性能。
级联拓扑如下:
- Source 1 为源库,处理业务请求。
- Source 2 为源库的副本库。
- Replica 1,Replica 2 和 Replica 3 是 Source 2 的副本库。
要加快副本库的复制,可以进行如下配置:
- 使用参数
relay_log
将中继日志放在与数据文件不同的磁盘上。 - 增大参数
rpl_read_size
,此参数控制从二进制日志文件和中继日志文件读取的最小数据量,当操作系统当前未缓存文件数据时,增大此参数可能会减少 I/O。
Switching Sources During Failover
在源库出现问题时,可以将副本库切换为源库。
故障前系统拓扑如下图:
Replica 1,Replica 2 和 Replica 3 为副本库,默认启用二进制日志(log_bin=ON
)。副本库需设置参数 log_replica_updates
为 OFF 指定副本库从源库接收到的更新不写入到副本库自身的二进制日志,则副本库上的二进制日志初始为空。如果源库不可用,可以选择一个副本库作为新的源库。假如选择了 Replica 2,则 Web Clients 重定向到 Replica 2,Replica 2 会将更新写入到二进制日志,Replica 1 和 Replica 3 从 Replica 2 复制数据。
副本库设置参数 log_replica_updates
为 OFF 的原因是如果设置为 ON(默认值),会将从源库接收到的更新写入到二进制日志,当 Replica 1 修改源库为 Replica 2 后,则 Replica 1 有可能会从 Replica 2 接收到从之前的源库已经接收到的更新。
需要确保副本库已经处理完成中继日志中的所有语句。在每个副本库,执行 STOP REPLICA IO_THREAD
,然后检查 SHOW PROCESSLIST
输出,直到出现 Replica has read all relay log
,才能进行在 Replica 2 执行 STOP REPLICA
和 RESET MASTER
进行重新配置。
在副本库 Replica 1 和 Replica 3,使用 STOP REPLICA
和 CHANGE REPLICATION SOURCE TO SOURCE_HOST='Replica1'
指定 Replica 2 为新的源库,执行 START REPLICA
启动复制。
故障后系统拓扑如下图:
创建故障前的复制环境,简单起见,只为源库配置了两个副本库。
- 参数配置。
源库参数配置:
[root@source ~]# vi /etc/my.cnf
[mysqld]
server_id=44135
gtid_mode=on
enforce_gtid_consistency=on
副本库 1 参数配置:
[root@replica1 ~]# vi /etc/my.cnf
[mysqld]
server_id=44136
gtid_mode=on
enforce_gtid_consistency=on
event_scheduler=OFF
relay_log=relay-binlog
relay_log_index=/data/mysql/relay-binlog.index
log_replica_updates=OFF
副本库 2 参数配置:
[root@replica1 ~]# vi /etc/my.cnf
[mysqld]
server_id=44137
gtid_mode=on
enforce_gtid_consistency=on
event_scheduler=OFF
relay_log=relay-binlog
relay_log_index=/data/mysql/relay-binlog.index
log_replica_updates=OFF
- 初始化数据。
源库导出数据:
[root@source ~]# mysqldump --single-transaction --triggers --routines --set-gtid-purged=COMMENTED --all-databases > dbdump.sql
副本库 1 导入数据:
[root@replica1 ~]# mysql < dbdump.sql
副本库 2 导入数据:
[root@replica2 ~]# mysql < dbdump.sql
- 配置复制。
副本库 1 配置复制:
[(none)]> CHANGE REPLICATION SOURCE TO
SOURCE_HOST='192.168.44.135',
SOURCE_PORT = 3306,
SOURCE_USER='repl',
SOURCE_PASSWORD='pUrEv!2rAx',
SOURCE_AUTO_POSITION = 1;
Query OK, 0 rows affected, 2 warnings (0.02 sec)
[(none)]> START REPLICA;
Query OK, 0 rows affected (0.12 sec)
[(none)]> SHOW REPLICA STATUS\G
*************************** 1. row ***************************
Replica_IO_State: Waiting for source to send event
Source_Host: 192.168.44.135
Source_User: repl
Source_Port: 3306
Connect_Retry: 60
Source_Log_File: binlog.000001
Read_Source_Log_Pos: 312
Relay_Log_File: relay-binlog.000002
Relay_Log_Pos: 522
Relay_Source_Log_File: binlog.000001
Replica_IO_Running: Yes
Replica_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_Source_Log_Pos: 312
Relay_Log_Space: 729
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Source_SSL_Allowed: No
Source_SSL_CA_File:
Source_SSL_CA_Path:
Source_SSL_Cert:
Source_SSL_Cipher:
Source_SSL_Key:
Seconds_Behind_Source: 0
Source_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Source_Server_Id: 44135
Source_UUID: f84c4937-eb10-11ed-a2ff-000c294b702c
Source_Info_File: mysql.slave_master_info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Replica_SQL_Running_State: Replica has read all relay log; waiting for more updates
Source_Retry_Count: 86400
Source_Bind:
Last_IO_Error_Timestamp:
Last_SQL_Error_Timestamp:
Source_SSL_Crl:
Source_SSL_Crlpath:
Retrieved_Gtid_Set: f84c4937-eb10-11ed-a2ff-000c294b702c:1
Executed_Gtid_Set: f84c4937-eb10-11ed-a2ff-000c294b702c:1
Auto_Position: 1
Replicate_Rewrite_DB:
Channel_Name:
Source_TLS_Version:
Source_public_key_path:
Get_Source_public_key: 0
Network_Namespace:
1 row in set (0.00 sec)
副本库 2 配置复制:
[(none)]> CHANGE REPLICATION SOURCE TO
SOURCE_HOST='192.168.44.135',
SOURCE_PORT = 3306,
SOURCE_USER='repl',
SOURCE_PASSWORD='pUrEv!2rAx',
SOURCE_AUTO_POSITION = 1;
Query OK, 0 rows affected, 2 warnings (0.02 sec)
[(none)]> START REPLICA;
Query OK, 0 rows affected (0.01 sec)
[(none)]> SHOW REPLICA STATUS\G
*************************** 1. row ***************************
Replica_IO_State: Waiting for source to send event
Source_Host: 192.168.44.135
Source_User: repl
Source_Port: 3306
Connect_Retry: 60
Source_Log_File: binlog.000001
Read_Source_Log_Pos: 312
Relay_Log_File: relay-binlog.000002
Relay_Log_Pos: 522
Relay_Source_Log_File: binlog.000001
Replica_IO_Running: Yes
Replica_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_Source_Log_Pos: 312
Relay_Log_Space: 729
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Source_SSL_Allowed: No
Source_SSL_CA_File:
Source_SSL_CA_Path:
Source_SSL_Cert:
Source_SSL_Cipher:
Source_SSL_Key:
Seconds_Behind_Source: 0
Source_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Source_Server_Id: 44135
Source_UUID: f84c4937-eb10-11ed-a2ff-000c294b702c
Source_Info_File: mysql.slave_master_info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Replica_SQL_Running_State: Replica has read all relay log; waiting for more updates
Source_Retry_Count: 86400
Source_Bind:
Last_IO_Error_Timestamp:
Last_SQL_Error_Timestamp:
Source_SSL_Crl:
Source_SSL_Crlpath:
Retrieved_Gtid_Set: f84c4937-eb10-11ed-a2ff-000c294b702c:1
Executed_Gtid_Set: f84c4937-eb10-11ed-a2ff-000c294b702c:1
Auto_Position: 1
Replicate_Rewrite_DB:
Channel_Name:
Source_TLS_Version:
Source_public_key_path:
Get_Source_public_key: 0
Network_Namespace:
1 row in set (0.00 sec)
- 关闭源库主机,模拟故障。
[root@source ~]# init 0
- 检查副本库是否已经处理完成中继日志中的所有语句。
副本库 1:
[(none)]> STOP REPLICA IO_THREAD;
Query OK, 0 rows affected (0.01 sec)
[(none)]> SHOW PROCESSLIST\G
*************************** 3. row ***************************
Id: 11
User: system user
Host:
db: NULL
Command: Query
Time: 252
State: Replica has read all relay log; waiting for more updates
Info: NULL
副本库 2:
[(none)]> STOP REPLICA IO_THREAD;
Query OK, 0 rows affected (0.01 sec)
[(none)]> SHOW PROCESSLIST\G
*************************** 3. row ***************************
Id: 11
User: system user
Host:
db: NULL
Command: Query
Time: 303
State: Replica has read all relay log; waiting for more updates
Info: NULL
都有 Replica has read all relay log
,表示已经处理完成中继日志中的所有语句。
- 重置副本库 2,使其为源库。
[(none)]> STOP REPLICA;
Query OK, 0 rows affected (0.01 sec)
[(none)]> RESET MASTER;
Query OK, 0 rows affected (0.03 sec)
- 在副本库 1 配置新的复制,指定源库为副本库 2。
[(none)]> STOP REPLICA;
Query OK, 0 rows affected (0.01 sec)
[(none)]> CHANGE REPLICATION SOURCE TO
-> SOURCE_HOST='192.168.44.137',
-> SOURCE_PORT = 3306,
-> SOURCE_USER='repl',
-> SOURCE_PASSWORD='pUrEv!2rAx',
-> SOURCE_AUTO_POSITION = 1;
Query OK, 0 rows affected, 2 warnings (0.02 sec)
[(none)]> START REPLICA;
Query OK, 0 rows affected (0.05 sec)
[(none)]> SHOW REPLICA STATUS\G
*************************** 1. row ***************************
Replica_IO_State: Waiting for source to send event
Source_Host: 192.168.44.137
Source_User: repl
Source_Port: 3306
Connect_Retry: 60
Source_Log_File: binlog.000001
Read_Source_Log_Pos: 157
Relay_Log_File: relay-binlog.000002
Relay_Log_Pos: 367
Relay_Source_Log_File: binlog.000001
Replica_IO_Running: Yes
Replica_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_Source_Log_Pos: 157
Relay_Log_Space: 574
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Source_SSL_Allowed: No
Source_SSL_CA_File:
Source_SSL_CA_Path:
Source_SSL_Cert:
Source_SSL_Cipher:
Source_SSL_Key:
Seconds_Behind_Source: 0
Source_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Source_Server_Id: 44137
Source_UUID: fe074cfd-ebe0-11ed-9b23-000c29c21d3a
Source_Info_File: mysql.slave_master_info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Replica_SQL_Running_State: Replica has read all relay log; waiting for more updates
Source_Retry_Count: 86400
Source_Bind:
Last_IO_Error_Timestamp:
Last_SQL_Error_Timestamp:
Source_SSL_Crl:
Source_SSL_Crlpath:
Retrieved_Gtid_Set:
Executed_Gtid_Set: f84c4937-eb10-11ed-a2ff-000c294b702c:1-3
Auto_Position: 1
Replicate_Rewrite_DB:
Channel_Name:
Source_TLS_Version:
Source_public_key_path:
Get_Source_public_key: 0
Network_Namespace:
1 row in set (0.00 sec)
Semisynchronous Replication
除了内置的异步复制外,MySQL 8.0 还支持通过插件实现半同步复制。本节讨论什么是半同步复制以及如何工作,包括半同步复制的管理接口以及安装、配置和监控半同步复制。
MySQL 复制默认是异步的。源库将事件写入其二进制日志,副本库在事件准备就绪时请求它们。源库不知道副本库是否或何时检索和处理了事务,也不能保证事件都会到达副本库。使用异步复制,如果源库崩溃,它提交的事务可能不会传输到任何副本库。在这种情况下,从源库到副本库的故障切换可能会导致故障切换到缺少相对于源库的事务的服务器。
当使用完全同步复制时,当源库提交事务完成前,所有副本库需要先完成该事务的提交。完全同步复制意味着源库和所有副本库数据任何时刻都完全一致,可以随时从源库故障切换到任何副本库。完全同步复制的缺点是源库完成事务可能会有较大延迟,影响性能,生产环境一般不会使用。
半同步复制介于异步复制和完全同步复制之间。源库会等到至少一个副本库接收并记录事件(所需的副本库数量是可配置的),然后才提交事务。源库只需要等待一个副本库的接收确认,而不需要等待事件在所有副本库完全执行和提交。因此,半同步复制可以保证如果源库崩溃,它提交的所有事务都已传输到至少一个副本库。
与异步复制相比,半同步复制进一步保证了数据完整性,因为当提交返回成功时,数据至少存在于两个位置。在半同步源库收到来自所需数量的副本库的确认之前,事务处于暂停状态,不会提交。
与完全同步复制相比,半同步复制速度更快,无需等待所有副本库完成事务提交。
与异步复制相比,半同步复制提高了数据完整性,但增加了事务提交时间,降低了系统性能。增加的时间至少是将提交信息发送到副本库并等待副本库接收确认的 TCP/IP 往返时间。这意味着半同步复制最适合高带宽,低延迟的局域网环境,不适合低带宽,高延迟的广域网环境。
源库与其副本库之间的半同步复制按如下方式运行:
副本库在连接到源库时表明是否支持半同步。
如果在源库启用了半同步复制,并且至少有一个半同步副本库,则在源库执行事务提交的线程将等待至少一个半同步副本库确认已收到事务的所有事件,或者直到发生超时。
只有在将事件写入到中继日志并刷新到磁盘后,副本库才会确认收到事务的事件。
如果发生超时,没有任何副本库确认收到事务,则源库将转换为异步复制。当至少一个半同步副本库追上源库时,源库将回到半同步复制。
必须在源库和副本库都启用半同步复制。如果在源库上禁用了半同步复制,或者在源库上启用了半同步复制,但没有在副本库上启用,则源库将使用异步复制。
Installing Semisynchronous Replication
半同步复制通过插件实现,安装在源库和副本库上。
要使用半同步复制,必须满足以下要求:
- 确保参数
have_dynamic_loading
为 YES(保持默认值)。 - 已经配置了复制且正在运行。
- 不能配置多个复制通道,半同步复制仅与默认复制通道兼容。
源库安装步骤如下:
- 确认参数
plugin_dir
指定的插件目录下有半同步插件。
[root@source ~]# mysql -e "SHOW VARIABLES LIKE 'plugin_dir';"
+---------------+--------------------------+
| Variable_name | Value |
+---------------+--------------------------+
| plugin_dir | /usr/lib64/mysql/plugin/ |
+---------------+--------------------------+
[root@source ~]# ll /usr/lib64/mysql/plugin/semisync_source.so
-rwxr-xr-x 1 root root 93544 Dec 17 01:30 /usr/lib64/mysql/plugin/semisync_source.so
- 安装源库的半同步插件并查看。
[(none)]> INSTALL PLUGIN rpl_semi_sync_source SONAME 'semisync_source.so';
Query OK, 0 rows affected (0.02 sec)
[(none)]> SELECT PLUGIN_NAME, PLUGIN_STATUS
FROM INFORMATION_SCHEMA.PLUGINS
WHERE PLUGIN_NAME LIKE '%semi%';
+----------------------+---------------+
| PLUGIN_NAME | PLUGIN_STATUS |
+----------------------+---------------+
| rpl_semi_sync_source | ACTIVE |
+----------------------+---------------+
1 row in set (0.01 sec)
- 安装半同步插件后,默认是禁用的,配置参数启用。
[(none)]> SET GLOBAL rpl_semi_sync_source_enabled = 1;
Query OK, 0 rows affected (0.00 sec)
写入到参数文件中,以便重启后也生效。
[root@source ~]# vi /etc/my.cnf
[mysqld]
rpl_semi_sync_source_enabled=1
副本库安装步骤如下:
- 确认参数
plugin_dir
指定的插件目录下有半同步插件。
[root@replica ~]# mysql -e "SHOW VARIABLES LIKE 'plugin_dir';"
+---------------+--------------------------+
| Variable_name | Value |
+---------------+--------------------------+
| plugin_dir | /usr/lib64/mysql/plugin/ |
+---------------+--------------------------+
[root@replica ~]# ll /usr/lib64/mysql/plugin/semisync_replica.so
-rwxr-xr-x 1 root root 37464 Dec 17 01:30 /usr/lib64/mysql/plugin/semisync_replica.so
- 安装副本库的半同步插件并查看。
[(none)]> INSTALL PLUGIN rpl_semi_sync_replica SONAME 'semisync_replica.so';
Query OK, 0 rows affected (0.02 sec)
[(none)]> SELECT PLUGIN_NAME, PLUGIN_STATUS
FROM INFORMATION_SCHEMA.PLUGINS
WHERE PLUGIN_NAME LIKE '%semi%';
+-----------------------+---------------+
| PLUGIN_NAME | PLUGIN_STATUS |
+-----------------------+---------------+
| rpl_semi_sync_replica | ACTIVE |
+-----------------------+---------------+
1 row in set (0.00 sec)
- 安装半同步插件后,默认是禁用的,配置参数启用。
[(none)]> SET GLOBAL rpl_semi_sync_replica_enabled = 1;
Query OK, 0 rows affected (0.00 sec)
写入到参数文件中,以便重启后也生效。
[root@replica ~]# vi /etc/my.cnf
[mysqld]
rpl_semi_sync_replica_enabled=1
- 重启 I/O 线程,注册半同步复制到源库。
[(none)]> STOP REPLICA IO_THREAD;
Query OK, 0 rows affected (0.01 sec)
[(none)]> START REPLICA IO_THREAD;
Query OK, 0 rows affected (0.00 sec)
[(none)]> SHOW REPLICA STATUS\G
*************************** 1. row ***************************
Replica_IO_State: Waiting for source to send event
Source_Host: 192.168.44.137
Source_User: repl
Source_Port: 3306
Connect_Retry: 60
Source_Log_File: binlog.000001
Read_Source_Log_Pos: 614
Relay_Log_File: relay-binlog.000003
Relay_Log_Pos: 451
Relay_Source_Log_File: binlog.000001
Replica_IO_Running: Yes
Replica_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_Source_Log_Pos: 614
Relay_Log_Space: 1325
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Source_SSL_Allowed: No
Source_SSL_CA_File:
Source_SSL_CA_Path:
Source_SSL_Cert:
Source_SSL_Cipher:
Source_SSL_Key:
Seconds_Behind_Source: 0
Source_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Source_Server_Id: 44137
Source_UUID: fe074cfd-ebe0-11ed-9b23-000c29c21d3a
Source_Info_File: mysql.slave_master_info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Replica_SQL_Running_State: Replica has read all relay log; waiting for more updates
Source_Retry_Count: 86400
Source_Bind:
Last_IO_Error_Timestamp:
Last_SQL_Error_Timestamp:
Source_SSL_Crl:
Source_SSL_Crlpath:
Retrieved_Gtid_Set: fe074cfd-ebe0-11ed-9b23-000c29c21d3a:1-2
Executed_Gtid_Set: f84c4937-eb10-11ed-a2ff-000c294b702c:1-3,
fe074cfd-ebe0-11ed-9b23-000c29c21d3a:1-2
Auto_Position: 1
Replicate_Rewrite_DB:
Channel_Name:
Source_TLS_Version:
Source_public_key_path:
Get_Source_public_key: 0
Network_Namespace:
1 row in set (0.00 sec)
Configuring Semisynchronous Replication
安装半同步插件后,源库有以下参数:
[(none)]> SHOW VARIABLES LIKE 'rpl_semi_sync%';
+---------------------------------------------+------------+
| Variable_name | Value |
+---------------------------------------------+------------+
| rpl_semi_sync_source_enabled | ON |
| rpl_semi_sync_source_timeout | 10000 |
| rpl_semi_sync_source_trace_level | 32 |
| rpl_semi_sync_source_wait_for_replica_count | 1 |
| rpl_semi_sync_source_wait_no_replica | ON |
| rpl_semi_sync_source_wait_point | AFTER_SYNC |
+---------------------------------------------+------------+
6 rows in set (0.00 sec)
副本库有以下参数:
[(none)]> SHOW VARIABLES LIKE 'rpl_semi_sync%';
+-----------------------------------+-------+
| Variable_name | Value |
+-----------------------------------+-------+
| rpl_semi_sync_replica_enabled | ON |
| rpl_semi_sync_replica_trace_level | 32 |
+-----------------------------------+-------+
2 rows in set (0.00 sec)
rpl_semi_sync_source_enabled
:指定源库是否启用半同步复制。
rpl_semi_sync_replica_enabled
:指定副本库是否启用半同步复制。
rpl_semi_sync_source_timeout
:指定源库等待副本库提交确认的超时时间,以毫秒为单位,默认为 10000(10 秒),超时后将转换为异步复制。
rpl_semi_sync_source_wait_for_replica_count
:指定源库在返回到会话之前必须为每个事务接收的副本库确认数,默认值为 1,表示源库仅等待一个副本库确认收到事务的事件。
rpl_semi_sync_source_wait_point
:指定源库在哪个位置等待副本库的事务接收确认,有以下选项:
AFTER_SYNC
:默认值,源库将每个事务写入其二进制日志和副本库,并同步二进制日志到磁盘。源库在同步之后等待副本库的事务接收确认。收到确认后,源库将事务提交到存储引擎,并将结果返回给客户端。所有客户端都会在同一时间看到提交的事务。如果源库发生故障,在源库上提交的所有事务都已复制到副本库(保存到其中继日志中)。源库意外退出并故障转移到副本库是不会丢失数据的。AFTER_COMMIT
:源库将每个事务写入其二进制日志和副本库,同步二进制日志到磁盘,并提交事务到存储引擎。源库在提交后等待副本库事务接收确认。收到确认后,源库将结果返回给客户端。发出事务的客户端只有在事务提交到存储引擎并收到副本库确认后才会获得返回状态,但是在提交之后和副本库确认之前,其他客户端可以在提交客户端之前看到已提交的事务。如果出现问题导致副本库没有处理事务,则在源库意外退出并故障转移到副本库的情况下,可能会有数据丢失。
从 MySQL 8.0.23 开始,可以通过启用参数 replication_sender_observe_commit_only
限制回调,启用参数 replication_optimize_for_static_plugin_config
增加共享锁避免不必要的锁来提高半同步复制的性能。
Semisynchronous Replication Monitoring
可以使用状态变量监控半同步复制:
源库:
[(none)]> SHOW STATUS LIKE 'Rpl_semi_sync%';
+--------------------------------------------+-------+
| Variable_name | Value |
+--------------------------------------------+-------+
| Rpl_semi_sync_source_clients | 1 |
| Rpl_semi_sync_source_net_avg_wait_time | 0 |
| Rpl_semi_sync_source_net_wait_time | 0 |
| Rpl_semi_sync_source_net_waits | 0 |
| Rpl_semi_sync_source_no_times | 0 |
| Rpl_semi_sync_source_no_tx | 0 |
| Rpl_semi_sync_source_status | ON |
| Rpl_semi_sync_source_timefunc_failures | 0 |
| Rpl_semi_sync_source_tx_avg_wait_time | 0 |
| Rpl_semi_sync_source_tx_wait_time | 0 |
| Rpl_semi_sync_source_tx_waits | 0 |
| Rpl_semi_sync_source_wait_pos_backtraverse | 0 |
| Rpl_semi_sync_source_wait_sessions | 0 |
| Rpl_semi_sync_source_yes_tx | 0 |
+--------------------------------------------+-------+
14 rows in set (0.01 sec)
副本库:
[(none)]> SHOW STATUS LIKE 'Rpl_semi_sync%';
+------------------------------+-------+
| Variable_name | Value |
+------------------------------+-------+
| Rpl_semi_sync_replica_status | ON |
+------------------------------+-------+
1 row in set (0.01 sec)
Rpl_semi_sync_source_clients
:连接到源库的半同步副本库数量。
Rpl_semi_sync_source_status
:源库半同步复制状态。
Rpl_semi_sync_source_no_tx
:没有被副本库成功确认的提交数量。
Rpl_semi_sync_source_yes_tx
:副本库成功确认的提交数量。
Rpl_semi_sync_replica_status
:副本库半同步复制状态。
Delayed Replication
MySQL 支持延迟复制,指定副本库比源库晚多久执行事务。本节介绍如何在副本库上配置复制延迟,以及如何监控复制延迟。
默认的复制延迟为 0 ,使用 CHANGE REPLICATION SOURCE TO SOURCE_DELAY=N
语句设置延迟 N
秒,表示从源库接收到的事务在源库提交 N
秒后才在副本库执行。
[(none)]> STOP SLAVE SQL_THREAD;
Query OK, 0 rows affected, 1 warning (0.01 sec)
[(none)]> CHANGE REPLICATION SOURCE TO SOURCE_DELAY=30;
Query OK, 0 rows affected (0.01 sec)
[(none)]> START SLAVE SQL_THREAD;
Query OK, 0 rows affected, 1 warning (0.05 sec)
[(none)]> SHOW REPLICA STATUS\G
*************************** 1. row ***************************
Replica_IO_State: Waiting for source to send event
Source_Host: 192.168.44.137
Source_User: repl
Source_Port: 3306
Connect_Retry: 60
Source_Log_File: binlog.000001
Read_Source_Log_Pos: 1071
Relay_Log_File: relay-binlog.000003
Relay_Log_Pos: 908
Relay_Source_Log_File: binlog.000001
Replica_IO_Running: Yes
Replica_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_Source_Log_Pos: 1071
Relay_Log_Space: 1782
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Source_SSL_Allowed: No
Source_SSL_CA_File:
Source_SSL_CA_Path:
Source_SSL_Cert:
Source_SSL_Cipher:
Source_SSL_Key:
Seconds_Behind_Source: 0
Source_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Source_Server_Id: 44137
Source_UUID: fe074cfd-ebe0-11ed-9b23-000c29c21d3a
Source_Info_File: mysql.slave_master_info
SQL_Delay: 30
SQL_Remaining_Delay: NULL
Replica_SQL_Running_State: Replica has read all relay log; waiting for more updates
Source_Retry_Count: 86400
Source_Bind:
Last_IO_Error_Timestamp:
Last_SQL_Error_Timestamp:
Source_SSL_Crl:
Source_SSL_Crlpath:
Retrieved_Gtid_Set: fe074cfd-ebe0-11ed-9b23-000c29c21d3a:1-4
Executed_Gtid_Set: f84c4937-eb10-11ed-a2ff-000c294b702c:1-3,
fe074cfd-ebe0-11ed-9b23-000c29c21d3a:1-4
Auto_Position: 1
Replicate_Rewrite_DB:
Channel_Name:
Source_TLS_Version:
Source_public_key_path:
Get_Source_public_key: 0
Network_Namespace:
1 row in set (0.00 sec)
注意:
START REPLICA
和STOP REPLICA
忽略延迟设置,立即生效;RESET REPLICA
重置延迟为 0。
表 performance_schema.replication_applier_configuration
中的 DESIRED_DELAY
列显示延迟配置。
[(none)]> SELECT DESIRED_DELAY FROM performance_schema.replication_applier_configuration;
+---------------+
| DESIRED_DELAY |
+---------------+
| 30 |
+---------------+
1 row in set (0.01 sec)
表 performance_schema.replication_applier_status
中的 REMAINING_DELAY
列显示剩余延迟秒数。
[(none)]> SELECT REMAINING_DELAY FROM performance_schema.replication_applier_status;
+-----------------+
| REMAINING_DELAY |
+-----------------+
| 16 |
+-----------------+
1 row in set (0.00 sec)
Replication Delay Timestamps
对于使用了 GTID 的事务,MySQL 8.0 使用以下与 GTID 关联的时间戳在复制拓扑中度量延迟。
original_commit_timestamp
:事务在源库写入(提交) 到二进制日志的时间戳。immediate_commit_timestamp
:事务在副本库写入(提交) 到二进制日志的时间戳。
original_commit_timestamp
在所有副本库上都相同。在源库的二进制日志和副本库的中继日志中,original_commit_timestamp
和 immediate_commit_timestamp
相同。而在副本库的二进制日志中,immediate_commit_timestamp
为副本库执行该事务的时间戳。
Monitoring Replication Delay
在之前版本中,监控复制延迟最常用的方法是查看 SHOW REPLICA STATUS
输出的 Seconds_Behind_Master
字段值,但不适用于更复杂的复制拓扑,比如组复制。使用 MySQL 8.0 提供的 immediate_commit_timestamp
和 original_commit_timestamp
可以更精确度量延迟。推荐使用以下性能模式表监控复制延迟:
replication_connection_status
:到源库连接的当前状态。提供有关连接线程排队进入中继日志的最后一个事务和当前事务的信息。
[(none)]> desc performance_schema.replication_connection_status;
+----------------------------------------------------+-------------------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------------------------------------------------+-------------------------------+------+-----+---------+-------+
| CHANNEL_NAME | char(64) | NO | PRI | NULL | |
| GROUP_NAME | char(36) | NO | | NULL | |
| SOURCE_UUID | char(36) | NO | | NULL | |
| THREAD_ID | bigint unsigned | YES | MUL | NULL | |
| SERVICE_STATE | enum('ON','OFF','CONNECTING') | NO | | NULL | |
| COUNT_RECEIVED_HEARTBEATS | bigint unsigned | NO | | 0 | |
| LAST_HEARTBEAT_TIMESTAMP | timestamp(6) | NO | | NULL | |
| RECEIVED_TRANSACTION_SET | longtext | NO | | NULL | |
| LAST_ERROR_NUMBER | int | NO | | NULL | |
| LAST_ERROR_MESSAGE | varchar(1024) | NO | | NULL | |
| LAST_ERROR_TIMESTAMP | timestamp(6) | NO | | NULL | |
| LAST_QUEUED_TRANSACTION | char(57) | YES | | NULL | |
| LAST_QUEUED_TRANSACTION_ORIGINAL_COMMIT_TIMESTAMP | timestamp(6) | NO | | NULL | |
| LAST_QUEUED_TRANSACTION_IMMEDIATE_COMMIT_TIMESTAMP | timestamp(6) | NO | | NULL | |
| LAST_QUEUED_TRANSACTION_START_QUEUE_TIMESTAMP | timestamp(6) | NO | | NULL | |
| LAST_QUEUED_TRANSACTION_END_QUEUE_TIMESTAMP | timestamp(6) | NO | | NULL | |
| QUEUEING_TRANSACTION | char(57) | YES | | NULL | |
| QUEUEING_TRANSACTION_ORIGINAL_COMMIT_TIMESTAMP | timestamp(6) | NO | | NULL | |
| QUEUEING_TRANSACTION_IMMEDIATE_COMMIT_TIMESTAMP | timestamp(6) | NO | | NULL | |
| QUEUEING_TRANSACTION_START_QUEUE_TIMESTAMP | timestamp(6) | NO | | NULL | |
+----------------------------------------------------+-------------------------------+------+-----+---------+-------+
20 rows in set (0.00 sec)
[(none)]> SELECT
SERVICE_STATE,
LAST_QUEUED_TRANSACTION,
LAST_QUEUED_TRANSACTION_ORIGINAL_COMMIT_TIMESTAMP,
LAST_QUEUED_TRANSACTION_IMMEDIATE_COMMIT_TIMESTAMP,
QUEUEING_TRANSACTION,
QUEUEING_TRANSACTION_ORIGINAL_COMMIT_TIMESTAMP,
QUEUEING_TRANSACTION_IMMEDIATE_COMMIT_TIMESTAMP,
QUEUEING_TRANSACTION_START_QUEUE_TIMESTAMP
FROM performance_schema.replication_connection_status\G
*************************** 1. row ***************************
SERVICE_STATE: ON
LAST_QUEUED_TRANSACTION: fe074cfd-ebe0-11ed-9b23-000c29c21d3a:4
LAST_QUEUED_TRANSACTION_ORIGINAL_COMMIT_TIMESTAMP: 2023-05-14 13:24:20.254865
LAST_QUEUED_TRANSACTION_IMMEDIATE_COMMIT_TIMESTAMP: 2023-05-14 13:24:20.254865
QUEUEING_TRANSACTION:
QUEUEING_TRANSACTION_ORIGINAL_COMMIT_TIMESTAMP: 0000-00-00 00:00:00.000000
QUEUEING_TRANSACTION_IMMEDIATE_COMMIT_TIMESTAMP: 0000-00-00 00:00:00.000000
QUEUEING_TRANSACTION_START_QUEUE_TIMESTAMP: 0000-00-00 00:00:00.000000
1 row in set (0.00 sec)
replication_applier_status_by_coordinator
:协调线程的当前状态,仅在使用多线程副本库时显示信息,提供有关协调线程缓冲到工作线程队列的最后一个事务的信息,以及当前正在缓冲的事务。
[(none)]> desc performance_schema.replication_applier_status_by_coordinator;
+-------------------------------------------------------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------------------------------------------------+------------------+------+-----+---------+-------+
| CHANNEL_NAME | char(64) | NO | PRI | NULL | |
| THREAD_ID | bigint unsigned | YES | MUL | NULL | |
| SERVICE_STATE | enum('ON','OFF') | NO | | NULL | |
| LAST_ERROR_NUMBER | int | NO | | NULL | |
| LAST_ERROR_MESSAGE | varchar(1024) | NO | | NULL | |
| LAST_ERROR_TIMESTAMP | timestamp(6) | NO | | NULL | |
| LAST_PROCESSED_TRANSACTION | char(57) | YES | | NULL | |
| LAST_PROCESSED_TRANSACTION_ORIGINAL_COMMIT_TIMESTAMP | timestamp(6) | NO | | NULL | |
| LAST_PROCESSED_TRANSACTION_IMMEDIATE_COMMIT_TIMESTAMP | timestamp(6) | NO | | NULL | |
| LAST_PROCESSED_TRANSACTION_START_BUFFER_TIMESTAMP | timestamp(6) | NO | | NULL | |
| LAST_PROCESSED_TRANSACTION_END_BUFFER_TIMESTAMP | timestamp(6) | NO | | NULL | |
| PROCESSING_TRANSACTION | char(57) | YES | | NULL | |
| PROCESSING_TRANSACTION_ORIGINAL_COMMIT_TIMESTAMP | timestamp(6) | NO | | NULL | |
| PROCESSING_TRANSACTION_IMMEDIATE_COMMIT_TIMESTAMP | timestamp(6) | NO | | NULL | |
| PROCESSING_TRANSACTION_START_BUFFER_TIMESTAMP | timestamp(6) | NO | | NULL | |
+-------------------------------------------------------+------------------+------+-----+---------+-------+
15 rows in set (0.01 sec)
[(none)]> SELECT
SERVICE_STATE,
LAST_PROCESSED_TRANSACTION,
LAST_PROCESSED_TRANSACTION_ORIGINAL_COMMIT_TIMESTAMP,
LAST_PROCESSED_TRANSACTION_IMMEDIATE_COMMIT_TIMESTAMP,
PROCESSING_TRANSACTION,
PROCESSING_TRANSACTION_ORIGINAL_COMMIT_TIMESTAMP,
PROCESSING_TRANSACTION_IMMEDIATE_COMMIT_TIMESTAMP,
PROCESSING_TRANSACTION_START_BUFFER_TIMESTAMP
FROM performance_schema.replication_applier_status_by_coordinator\G
*************************** 1. row ***************************
SERVICE_STATE: ON
LAST_PROCESSED_TRANSACTION: fe074cfd-ebe0-11ed-9b23-000c29c21d3a:4
LAST_PROCESSED_TRANSACTION_ORIGINAL_COMMIT_TIMESTAMP: 2023-05-14 13:24:20.254865
LAST_PROCESSED_TRANSACTION_IMMEDIATE_COMMIT_TIMESTAMP: 2023-05-14 13:24:20.254865
PROCESSING_TRANSACTION:
PROCESSING_TRANSACTION_ORIGINAL_COMMIT_TIMESTAMP: 0000-00-00 00:00:00.000000
PROCESSING_TRANSACTION_IMMEDIATE_COMMIT_TIMESTAMP: 0000-00-00 00:00:00.000000
PROCESSING_TRANSACTION_START_BUFFER_TIMESTAMP: 0000-00-00 00:00:00.000000
1 row in set (0.00 sec)
replication_applier_status_by_worker
:应用从源库接收的事务的线程的当前状态,在使用多线程副本库时,提供有关 SQL 线程或每个工作线程应用事务的信息。
[(none)]> desc performance_schema.replication_applier_status_by_worker;
+---------------------------------------------------------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------------------------------------------------------+------------------+------+-----+---------+-------+
| CHANNEL_NAME | char(64) | NO | PRI | NULL | |
| WORKER_ID | bigint unsigned | NO | PRI | NULL | |
| THREAD_ID | bigint unsigned | YES | MUL | NULL | |
| SERVICE_STATE | enum('ON','OFF') | NO | | NULL | |
| LAST_ERROR_NUMBER | int | NO | | NULL | |
| LAST_ERROR_MESSAGE | varchar(1024) | NO | | NULL | |
| LAST_ERROR_TIMESTAMP | timestamp(6) | NO | | NULL | |
| LAST_APPLIED_TRANSACTION | char(57) | YES | | NULL | |
| LAST_APPLIED_TRANSACTION_ORIGINAL_COMMIT_TIMESTAMP | timestamp(6) | NO | | NULL | |
| LAST_APPLIED_TRANSACTION_IMMEDIATE_COMMIT_TIMESTAMP | timestamp(6) | NO | | NULL | |
| LAST_APPLIED_TRANSACTION_START_APPLY_TIMESTAMP | timestamp(6) | NO | | NULL | |
| LAST_APPLIED_TRANSACTION_END_APPLY_TIMESTAMP | timestamp(6) | NO | | NULL | |
| APPLYING_TRANSACTION | char(57) | YES | | NULL | |
| APPLYING_TRANSACTION_ORIGINAL_COMMIT_TIMESTAMP | timestamp(6) | NO | | NULL | |
| APPLYING_TRANSACTION_IMMEDIATE_COMMIT_TIMESTAMP | timestamp(6) | NO | | NULL | |
| APPLYING_TRANSACTION_START_APPLY_TIMESTAMP | timestamp(6) | NO | | NULL | |
| LAST_APPLIED_TRANSACTION_RETRIES_COUNT | bigint unsigned | NO | | NULL | |
| LAST_APPLIED_TRANSACTION_LAST_TRANSIENT_ERROR_NUMBER | int | NO | | NULL | |
| LAST_APPLIED_TRANSACTION_LAST_TRANSIENT_ERROR_MESSAGE | varchar(1024) | YES | | NULL | |
| LAST_APPLIED_TRANSACTION_LAST_TRANSIENT_ERROR_TIMESTAMP | timestamp(6) | NO | | NULL | |
| APPLYING_TRANSACTION_RETRIES_COUNT | bigint unsigned | NO | | NULL | |
| APPLYING_TRANSACTION_LAST_TRANSIENT_ERROR_NUMBER | int | NO | | NULL | |
| APPLYING_TRANSACTION_LAST_TRANSIENT_ERROR_MESSAGE | varchar(1024) | YES | | NULL | |
| APPLYING_TRANSACTION_LAST_TRANSIENT_ERROR_TIMESTAMP | timestamp(6) | NO | | NULL | |
+---------------------------------------------------------+------------------+------+-----+---------+-------+
24 rows in set (0.00 sec)
[(none)]> SELECT
SERVICE_STATE,
LAST_APPLIED_TRANSACTION,
LAST_APPLIED_TRANSACTION_ORIGINAL_COMMIT_TIMESTAMP,
LAST_APPLIED_TRANSACTION_IMMEDIATE_COMMIT_TIMESTAMP,
APPLYING_TRANSACTION,
APPLYING_TRANSACTION_ORIGINAL_COMMIT_TIMESTAMP,
APPLYING_TRANSACTION_IMMEDIATE_COMMIT_TIMESTAMP,
APPLYING_TRANSACTION_START_APPLY_TIMESTAMP
FROM performance_schema.replication_applier_status_by_worker
WHERE WORKER_ID=1\G
*************************** 1. row ***************************
SERVICE_STATE: ON
LAST_APPLIED_TRANSACTION: fe074cfd-ebe0-11ed-9b23-000c29c21d3a:4
LAST_APPLIED_TRANSACTION_ORIGINAL_COMMIT_TIMESTAMP: 2023-05-14 13:24:20.254865
LAST_APPLIED_TRANSACTION_IMMEDIATE_COMMIT_TIMESTAMP: 2023-05-14 13:24:20.254865
APPLYING_TRANSACTION:
APPLYING_TRANSACTION_ORIGINAL_COMMIT_TIMESTAMP: 0000-00-00 00:00:00.000000
APPLYING_TRANSACTION_IMMEDIATE_COMMIT_TIMESTAMP: 0000-00-00 00:00:00.000000
APPLYING_TRANSACTION_START_APPLY_TIMESTAMP: 0000-00-00 00:00:00.000000
1 row in set (0.00 sec)
除了上面的性能模式表,还可以使用 SHOW REPLICA STATUS
输出的下面三个字段:
SQL_Delay
:显示由CHANGE REPLICATION SOURCE TO SOURCE_DELAY=N
配置的复制延迟。Replica_SQL_Running_State
:SQL 线程的状态,与使用SHOW PROCESSLIST
显示的 SQL 线程的State
值一样。SQL_Remaining_Delay
:当Replica_SQL_Running_State
为Waiting until SOURCE_DELAY seconds after source executed event
时,表示延迟剩余秒数。
Replication Notes and Tips
Troubleshooting Replication
如果复制设置没有生效,则首先要做的是检查错误日志中的信息。
如果无法从错误日志中判断出问题所在,尝试以下方法:
- 在源库使用
SHOW MASTER STATUS
语句查看是否启用了二进制日志。二进制日志是默认启用的,如果是启用状态,则输出的Position
字段的值为非零值。 - 查看源库和副本库的
server_id
参数是否是不同的值。 - 在副本库使用
SHOW REPLICA STATUS
语句Replica_IO_Running
和Replica_SQL_Running
的值是否为Yes
。如果不是,使用对应的语句启动 I/O 线程或 SQL 线程。 - 在副本库使用
SHOW PROCESSLIST
语句查看是否建立了到源库的连接,查看State
字段中 I/O 线程和 SQL 线程的状态。如果连接有问题,需要确认源库主机地址和端口是否正确,是否启用了skip_networking
参数,是否配置了防火墙。
如果源库语句执行成功,但是副本库语句执行失败,此时不想删掉副本库,再次全量同步源库来重建副本库,可以尝试以下方法:
- 查看副本库的表是否与源库的表一致,如果不同,则修改为一致后执行
START REPLICA
启动复制。 - 如果启动复制还是失败,查看是否可以手动进行更新。
- 手动更新后,使用以下语句忽略掉后续语句:
mysql> SET GLOBAL sql_replica_skip_counter = N;
mysql> START REPLICA;
如果后续语句没有使用 AUTO_INCREMENT
或者 LAST_INSERT_ID()
,则 N
值为 1,否则为 2。原因是源库在使用 AUTO_INCREMENT
或者 LAST_INSERT_ID()
时会写入二进制日志 2 个 Events。
The Clone Plugin
前面提到在进行大数据量的复制初始化时,可以使用克隆的方式,也可以使用克隆来进行备份恢复。本节就来介绍 MySQL 的克隆。
从 MySQL 8.0.17 引入的克隆插件,可以从本地或者远程 MySQL Server 实例克隆数据。克隆的数据是存储在 InnoDB 中数据的物理快照,包括模式,表,表空间及数据字典中的数据。不会克隆二进制日志文件和参数文件。
克隆可以分为:
- 本地克隆:源库数据目录和副本库数据目录在同一主机。
- 远程克隆:源库数据目录和副本库数据目录在不同主机。默认情况下,远程克隆操作会在克隆前将副本库数据目录下用户创建的数据和二进制日志删除,也可以指定克隆数据到其他目录。
官方文档中将源库称为 Donor(捐赠者),副本库称为 Recipient(接收者),为方便理解,保持本文档上下文一致,还是称为源库和副本库。
Installing the Clone Plugin
本节介绍如何安装和配置克隆插件。对于远程克隆操作,源库和副本库都需要克隆插件。
- 确认参数
plugin_dir
指定的插件目录下有克隆插件。
[root@source ~]# mysql -e "SHOW VARIABLES LIKE 'plugin_dir';"
+---------------+--------------------------+
| Variable_name | Value |
+---------------+--------------------------+
| plugin_dir | /usr/lib64/mysql/plugin/ |
+---------------+--------------------------+
[root@source ~]# ll /usr/lib64/mysql/plugin/mysql_clone.so
-rwxr-xr-x 1 root root 239088 Dec 17 01:30 /usr/lib64/mysql/plugin/mysql_clone.so
- 安装克隆插件并查看。
[(none)]> INSTALL PLUGIN clone SONAME 'mysql_clone.so';
Query OK, 0 rows affected (0.04 sec)
[(none)]> SELECT PLUGIN_NAME, PLUGIN_STATUS
FROM INFORMATION_SCHEMA.PLUGINS
WHERE PLUGIN_NAME = 'clone';
+-------------+---------------+
| PLUGIN_NAME | PLUGIN_STATUS |
+-------------+---------------+
| clone | ACTIVE |
+-------------+---------------+
1 row in set (0.00 sec)
Cloning Data Locally
本地克隆语法:
CLONE LOCAL DATA DIRECTORY [=] 'clone_dir';
目录使用绝对路径,其中,/path/to
目录需要提前创建,而 clone_dir
目录不能存在。进行克隆的用户需要有 BACKUP_ADMIN
权限:
GRANT BACKUP_ADMIN ON *.* TO 'clone_user';
例子:本地克隆
[(none)]> CLONE LOCAL DATA DIRECTORY = '/data/clone';
Query OK, 0 rows affected (1.45 sec)
查看克隆的目录文件,可以看到不会克隆二进制日志文件:
[root@replica ~]# ll /data/clone/
total 70664
drwxr-x--- 2 mysql mysql 89 May 21 13:31 #clone
drwxr-x--- 2 mysql mysql 76 May 21 13:31 db1
drwxr-x--- 2 mysql mysql 20 May 21 13:31 db2
-rw-r----- 1 mysql mysql 4926 May 21 13:31 ib_buffer_pool
-rw-r----- 1 mysql mysql 12582912 May 21 13:31 ibdata1
drwxr-x--- 2 mysql mysql 23 May 21 13:31 #innodb_redo
drwxr-x--- 2 mysql mysql 91 May 21 13:31 menagerie
drwxr-x--- 2 mysql mysql 6 May 21 13:31 mysql
-rw-r----- 1 mysql mysql 26214400 May 21 13:31 mysql.ibd
drwxr-x--- 2 mysql mysql 28 May 21 13:31 sys
-rw-r----- 1 mysql mysql 16777216 May 21 13:31 undo_001
-rw-r----- 1 mysql mysql 16777216 May 21 13:31 undo_002
Cloning Remote Data
远程克隆语法:
CLONE INSTANCE FROM 'user'@'host':port
IDENTIFIED BY 'password'
[DATA DIRECTORY [=] 'clone_dir']
[REQUIRE [NO] SSL];
user
:源库用户名。password
:user
的密码。host
:源库主机地址。port
:源库端口。DATA DIRECTORY [=] 'clone_dir'
:可选子句,副本库上的克隆目录。如果不想删除副本库上现有用户数据和二进制日志,则可以使用该子句指定绝对路径为克隆的目录。目录不能先创建,且 MySQL Server 需要有创建该目录的权限。如果不指定该子句,克隆操作会删除副本库现有用户数据和二进制日志,将源库数据克隆到副本库数据目录并自动重启 MySQL Server。REQUIRE [NO] SSL
:当通过网络传输克隆数据时,是否需要对源库和副本库的网络连接进行加密。内网一般不需要加密。如果显示使用了该子句,不满足加密条件则返回错误。如果没有指定,默认使用加密连接,如果失败则使用非安全连接。当克隆加密数据时,不论是否指定了该子句,都需要安全连接。
Remote Cloning Prerequisites
执行远程克隆,需要在源库和副本库上都安装克隆插件。
对于 MySQL 用户:
- 在源库,克隆用户需要有
BACKUP_ADMIN
权限。 - 在副本库,克隆用户需要有
CLONE_ADMIN
权限。
执行 CLONE INSTANCE
语句前会进行如下检查:
- 源库和副本库的 MySQL Server 版本需一致,且需为 MYSQL 8.0.17 及以上。
- 源库和副本库所在的操作系统需一致。
- 副本库需确保足够的存储空间。
- 源库激活的插件,副本库也同样需要激活。
- 源库和副本库的字符集和比较规则需一致。
- 源库和副本库的
innodb_page_size
和innodb_data_file_path
参数需一致。 - 如果克隆加密或者压缩数据,源库和副本库的文件系统块大小需一致。
- 如果克隆加密数据,则需要安全连接。
- 副本库的
clone_valid_donor_list
参数值必须包含源库的主机地址,副本库只能从该参数指定的主机克隆。 - 同一时间只能允许运行一个克隆操作,查询
clone_status
表查看克隆操作是否在运行。 - 源库和副本库的参数
max_allowed_packet
(默认 64M)至少需要 2M。
[(none)]> SHOW VARIABLES LIKE 'max_allowed_packet';
+--------------------+----------+
| Variable_name | Value |
+--------------------+----------+
| max_allowed_packet | 67108864 |
+--------------------+----------+
1 row in set (0.00 sec)
- 源库的 UNDO 表空间文件名需唯一,查询
INFORMATION_SCHEMA.FILES
表查看 UNDO 表空间文件名。因为无论源库的 UNDO 表空间文件在哪个位置,都会克隆到副本库innodb_undo_directory
参数指定的目录或者DATA DIRECTORY [=] 'clone_dir'
子句指定的位置。从 MySQL 8.0.18 开始,如果文件名相同,则会报错。
[(none)]> SELECT TABLESPACE_NAME, FILE_NAME FROM INFORMATION_SCHEMA.FILES WHERE FILE_TYPE LIKE 'UNDO LOG';
+-----------------+------------+
| TABLESPACE_NAME | FILE_NAME |
+-----------------+------------+
| innodb_undo_001 | ./undo_001 |
| innodb_undo_002 | ./undo_002 |
+-----------------+------------+
2 rows in set (0.02 sec)
Cloning Remote Data
例子:远程克隆,覆盖现有数据目录
- 源库创建用户并授权,安装克隆插件。
[(none)]> CREATE USER 'source_clone'@'%' IDENTIFIED BY 'Source123#';
Query OK, 0 rows affected (10.03 sec)
[(none)]> GRANT BACKUP_ADMIN on *.* to 'source_clone'@'%';
Query OK, 0 rows affected (0.01 sec)
[(none)]> INSTALL PLUGIN clone SONAME 'mysql_clone.so';
Query OK, 0 rows affected (0.04 sec)
- 副本库创建用户并授权,安装克隆插件及源库安装的其他插件(这里源库安装了半同步插件,故副本库也需要安装),增加源库主机地址到参数
clone_valid_donor_list
。
[(none)]> CREATE USER 'replica_clone'@'%' IDENTIFIED BY 'Replica123#';
Query OK, 0 rows affected (0.03 sec)
[(none)]> GRANT CLONE_ADMIN on *.* to 'replica_clone'@'%';
Query OK, 0 rows affected (0.00 sec)
[(none)]> INSTALL PLUGIN clone SONAME 'mysql_clone.so';
Query OK, 0 rows affected (0.04 sec)
[(none)]> INSTALL PLUGIN rpl_semi_sync_source SONAME 'semisync_source.so';
Query OK, 0 rows affected (0.01 sec)
[(none)]> SET GLOBAL clone_valid_donor_list = '192.168.44.137:3306';
Query OK, 0 rows affected (0.00 sec)
- 使用上一步创建的用户登录到副本库进行克隆。
[root@replica ~]# mysql -ureplica_clone -pReplica123#
[(none)]> CLONE INSTANCE FROM 'source_clone'@'192.168.44.137':3306 IDENTIFIED BY 'Source123#';
Query OK, 0 rows affected (2.00 sec)
Cloning to a Named Directory
例子:远程克隆,保留副本库现有的数据目录,克隆数据到其他目录
- 源库创建用户并授权,安装克隆插件。
[(none)]> CREATE USER 'source_clone'@'%' IDENTIFIED BY 'Source123#';
Query OK, 0 rows affected (10.03 sec)
[(none)]> GRANT BACKUP_ADMIN on *.* to 'source_clone'@'%';
Query OK, 0 rows affected (0.01 sec)
[(none)]> INSTALL PLUGIN clone SONAME 'mysql_clone.so';
Query OK, 0 rows affected (0.04 sec)
- 副本库创建用户并授权,安装克隆插件及源库安装的其他插件(这里源库安装了半同步插件,故副本库也需要安装),增加源库主机地址到参数
clone_valid_donor_list
。
[(none)]> CREATE USER 'replica_clone'@'%' IDENTIFIED BY 'Replica123#';
Query OK, 0 rows affected (0.03 sec)
[(none)]> GRANT CLONE_ADMIN on *.* to 'replica_clone'@'%';
Query OK, 0 rows affected (0.00 sec)
[(none)]> INSTALL PLUGIN clone SONAME 'mysql_clone.so';
Query OK, 0 rows affected (0.04 sec)
[(none)]> INSTALL PLUGIN rpl_semi_sync_source SONAME 'semisync_source.so';
Query OK, 0 rows affected (0.01 sec)
[(none)]> SET GLOBAL clone_valid_donor_list = '192.168.44.137:3306';
Query OK, 0 rows affected (0.00 sec)
- 使用上一步创建的用户登录到副本库进行克隆。
[root@replica ~]# chown mysql:mysql /data/
[root@replica ~]# mysql -ureplica_clone -pReplica123#
[(none)]> CLONE INSTANCE FROM 'source_clone'@'192.168.44.137':3306 IDENTIFIED BY 'Source123#' DATA DIRECTORY = '/data/clone';
Query OK, 0 rows affected (1.16 sec)
完成后,需要调整参数文件的相关目录,再启动。
[root@replica ~]# vi /etc/my.cnf
datadir=/data/clone
socket=/data/clone/mysql.sock
relay_log_index=/data/clone/relay-binlog.index
[root@replica ~]# systemctl restart mysqld.service
Cloning and Concurrent DDL
在 MySQL 8.0.27之前,在克隆操作期间不允许对源库和副本库执行 DDL 操作,包括 TRUNCATE TABLE
。
为了防止克隆操作期间的并发 DDL,会在源库和副本库上获取独占备份锁(Exclusive Backup Lock)。参数 clone_ddl_timeout
指定克隆操作等待备份锁的的时间(以秒为单位),默认为 300 秒。如果没有在指定的时间内获取备份锁,则克隆操作将失败并显示错误。
[(none)]> SHOW VARIABLES LIKE 'clone_ddl_timeout';
+-------------------+-------+
| Variable_name | Value |
+-------------------+-------+
| clone_ddl_timeout | 300 |
+-------------------+-------+
1 row in set (0.02 sec)
从 MySQL 8.0.27 开始,可以使用参数 clone_block_ddl
指定源库是否允许并发 DDL,默认为 OFF
,表示允许并发 DDL,可以使用 SET
语句动态设置。
[(none)]> SHOW VARIABLES LIKE 'clone_block_ddl';
+-----------------+-------+
| Variable_name | Value |
+-----------------+-------+
| clone_block_ddl | OFF |
+-----------------+-------+
1 row in set (0.00 sec)
是否克隆并发 DDL 操作取决于 DDL 操作是否在克隆操作进行动态快照之前完成。
即使参数 clone_block_ddl
为 OFF
,在克隆操作期间也不允许以下 DDL 操作:
ALTER TABLE tbl_name DISCARD TABLESPACE;
ALTER TABLE tbl_name IMPORT TABLESPACE;
ALTER INSTANCE DISABLE INNODB REDO_LOG;
Cloning for Replication
克隆插件支持复制。在克隆操作期间,会从源库获取二进制日志位置和 gtid_executed
GTID 集和,传输到副本库。由于克隆不会将二进制日志和中继日志从源库传输到副本库,若要启动复制,则源库不能删除克隆期间的二进制日志。如果所需的二进制日志不可用,则会报复制握手错误。
在源库查询发送到副本库的二进制日志位置:
mysql> SELECT BINLOG_FILE, BINLOG_POSITION FROM performance_schema.clone_status;
在源库查询发送到副本库的 gtid_executed
GTID 集合:
mysql> SELECT @@GLOBAL.GTID_EXECUTED;
例子:使用克隆配置复制
- 确认源库的参数配置。
[root@mysql ~]# vi /etc/my.cnf
[mysqld]
server_id=44137
gtid_mode=on
enforce_gtid_consistency=on
- 源库创建用户并授权,安装克隆插件。
[(none)]> CREATE USER 'source_clone'@'%' IDENTIFIED BY 'Source123#';
Query OK, 0 rows affected (10.03 sec)
[(none)]> GRANT BACKUP_ADMIN on *.* to 'source_clone'@'%';
Query OK, 0 rows affected (0.01 sec)
[(none)]> INSTALL PLUGIN clone SONAME 'mysql_clone.so';
Query OK, 0 rows affected (0.04 sec)
- 副本库创建用户并授权,安装克隆插件及源库安装的其他插件(这里源库安装了半同步插件,故副本库也需要安装),增加源库主机地址到参数
clone_valid_donor_list
。
[(none)]> CREATE USER 'replica_clone'@'%' IDENTIFIED BY 'Replica123#';
Query OK, 0 rows affected (0.03 sec)
[(none)]> GRANT CLONE_ADMIN on *.* to 'replica_clone'@'%';
Query OK, 0 rows affected (0.00 sec)
[(none)]> INSTALL PLUGIN clone SONAME 'mysql_clone.so';
Query OK, 0 rows affected (0.04 sec)
[(none)]> INSTALL PLUGIN rpl_semi_sync_source SONAME 'semisync_source.so';
Query OK, 0 rows affected (0.01 sec)
[(none)]> SET GLOBAL clone_valid_donor_list = '192.168.44.137:3306';
Query OK, 0 rows affected (0.00 sec)
- 使用上一步创建的用户登录到副本库进行克隆。
[root@replica ~]# mysql -ureplica_clone -pReplica123#
[(none)]> CLONE INSTANCE FROM 'source_clone'@'192.168.44.137':3306 IDENTIFIED BY 'Source123#';
Query OK, 0 rows affected (2.00 sec)
- 调整副本库的参数并重命名
/data/mysql/auto.cnf
文件。
[root@replica1 ~]# vi /etc/my.cnf
[mysqld]
server_id=44136
gtid_mode=on
enforce_gtid_consistency=on
event_scheduler=OFF
relay_log=relay-binlog
relay_log_index=/data/mysql/relay-binlog.index
[root@replica ~]# mv /data/mysql/auto.cnf /data/mysql/auto.cnf.bak
[root@replica1 ~]# systemctl start mysqld.service
源库必须启用二进制日志(默认启用),副本库最好也启用二进制日志。
- 源库创建复制用户并授予权限,以便副本库连接。
[(none)]> CREATE USER 'repl'@'%' IDENTIFIED WITH mysql_native_password BY 'pUrEv!2rAx';
Query OK, 0 rows affected (0.01 sec)
[(none)]> GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
Query OK, 0 rows affected (0.01 sec)
- 配置复制。
[(none)]> CHANGE REPLICATION SOURCE TO
SOURCE_HOST='192.168.44.137',
SOURCE_PORT = 3306,
SOURCE_USER='repl',
SOURCE_PASSWORD='pUrEv!2rAx',
SOURCE_AUTO_POSITION = 1;
Query OK, 0 rows affected, 2 warnings (0.04 sec)
[(none)]> START REPLICA;
Query OK, 0 rows affected (0.14 sec)
[(none)]> SHOW REPLICA STATUS\G
*************************** 1. row ***************************
Replica_IO_State: Waiting for source to send event
Source_Host: 192.168.44.137
Source_User: repl
Source_Port: 3306
Connect_Retry: 60
Source_Log_File: binlog.000006
Read_Source_Log_Pos: 1409
Relay_Log_File: relay-binlog.000003
Relay_Log_Pos: 411
Relay_Source_Log_File: binlog.000006
Replica_IO_Running: Yes
Replica_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_Source_Log_Pos: 1409
Relay_Log_Space: 798
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Source_SSL_Allowed: No
Source_SSL_CA_File:
Source_SSL_CA_Path:
Source_SSL_Cert:
Source_SSL_Cipher:
Source_SSL_Key:
Seconds_Behind_Source: 0
Source_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Source_Server_Id: 44137
Source_UUID: fe074cfd-ebe0-11ed-9b23-000c29c21d3a
Source_Info_File: mysql.slave_master_info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Replica_SQL_Running_State: Replica has read all relay log; waiting for more updates
Source_Retry_Count: 86400
Source_Bind:
Last_IO_Error_Timestamp:
Last_SQL_Error_Timestamp:
Source_SSL_Crl:
Source_SSL_Crlpath:
Retrieved_Gtid_Set:
Executed_Gtid_Set: f84c4937-eb10-11ed-a2ff-000c294b702c:1,
fe074cfd-ebe0-11ed-9b23-000c29c21d3a:1-18
Auto_Position: 1
Replicate_Rewrite_DB:
Channel_Name:
Source_TLS_Version:
Source_public_key_path:
Get_Source_public_key: 0
Network_Namespace:
1 row in set (0.00 sec)
Monitoring Cloning Operations
Monitoring Cloning Operations using Performance Schema Clone Tables
可以在副本库使用 performance_schema.clone_status
和 performance_schema.clone_progress
查看克隆操作的状态和进度。
clone_status
:显示克隆操作当前和先前的执行状态。克隆操作有四种状态:Not Started
,In Progress
,Completed
和Failed
。clone_progress
:显示克隆操作当前和先前的执行进度。克隆操作包括DROP DATA
,FILE COPY
,PAGE_COPY
,REDO_COPY
,FILE_SYNC
,RESTART
和RECOVERY
这几个阶段。
例子:查看克隆操作状态
[(none)]> SELECT STATE, ERROR_NO, ERROR_MESSAGE FROM performance_schema.clone_status;
+-----------+----------+---------------+
| STATE | ERROR_NO | ERROR_MESSAGE |
+-----------+----------+---------------+
| Completed | 0 | |
+-----------+----------+---------------+
1 row in set (0.00 sec)
例子:查看克隆操作各个阶段的详细信息
[(none)]> SELECT STAGE, STATE, END_TIME FROM performance_schema.clone_progress;
+-----------+-----------+----------------------------+
| STAGE | STATE | END_TIME |
+-----------+-----------+----------------------------+
| DROP DATA | Completed | 2023-05-21 20:38:21.011652 |
| FILE COPY | Completed | 2023-05-21 20:38:21.587669 |
| PAGE COPY | Completed | 2023-05-21 20:38:21.611053 |
| REDO COPY | Completed | 2023-05-21 20:38:21.619765 |
| FILE SYNC | Completed | 2023-05-21 20:38:22.124470 |
| RESTART | Completed | 2023-05-21 20:38:26.044059 |
| RECOVERY | Completed | 2023-05-21 20:38:27.396399 |
+-----------+-----------+----------------------------+
7 rows in set (0.00 sec)
Monitoring Cloning Operations Using Performance Schema Stage Events
可以在源库或副本库使用 3 个 Stage Event 监控克隆操作进度,分别是:
stage/innodb/clone (file copy)
:克隆操作中文件拷贝阶段的进度,其中WORK_ESTIMATED
和WORK_COMPLETED
的单位是文件块。WORK_ESTIMATED
根据要拷贝的文件数量估算,每个文件块发送后会更新WORK_COMPLETED
。stage/innodb/clone (page copy)
:克隆操作中变化页拷贝阶段的进度,其中WORK_ESTIMATED
和WORK_COMPLETED
的单位是页。开始文件拷贝前,会启动 Page Tracking,记录变化的页;完成文件拷贝后,计算出前面文件拷贝阶段产生的变化页数量,设置为WORK_ESTIMATED
,每个页发送后会更新WORK_COMPLETED
。stage/innodb/clone (redo copy)
:克隆操作中重做拷贝阶段的进度,其中WORK_ESTIMATED
和WORK_COMPLETED
的单位是重做块。开始页拷贝前,会启动 Redo Archiving,停止 Page Tracking,进行日志归档;完成页拷贝后,停止 Redo Archiving,计算出页拷贝阶段产生的重做块数量,设置为WORK_ESTIMATED
,每个重做块发送后会更新WORK_COMPLETED
。
例子:启用以上 Stage Event 的 Instruments 及相关 Consumer 表监控克隆操作
- 启用
stage/innodb/clone%
Instruments,采集信息
[(none)]> UPDATE performance_schema.setup_instruments SET ENABLED = 'YES'
WHERE NAME LIKE 'stage/innodb/clone%';
Query OK, 0 rows affected (0.01 sec)
Rows matched: 3 Changed: 0 Warnings: 0
- 启用 Stage Event 使用者(Consumer)表,保存信息,包括
events_stages_current
,events_stages_history
和events_stages_history_long
[(none)]> UPDATE performance_schema.setup_consumers SET ENABLED = 'YES'
WHERE NAME LIKE '%stages%';
Query OK, 3 rows affected (0.00 sec)
Rows matched: 3 Changed: 3 Warnings: 0
- 执行克隆操作
[(none)]> CLONE LOCAL DATA DIRECTORY = '/data/clone';
- 查询
performance_schema.events_stages_current
查看克隆操作进度
[(none)]> SELECT EVENT_NAME, WORK_COMPLETED, WORK_ESTIMATED FROM performance_schema.events_stages_current
WHERE EVENT_NAME LIKE 'stage/innodb/clone%';
+--------------------------------+----------------+----------------+
| EVENT_NAME | WORK_COMPLETED | WORK_ESTIMATED |
+--------------------------------+----------------+----------------+
| stage/innodb/clone (redo copy) | 1 | 1 |
+--------------------------------+----------------+----------------+
1 row in set (0.01 sec)
如果克隆操作完成,performance_schema.events_stages_current
返回空,此时可以查询 performance_schema.events_stages_history
查看各阶段数据。
[(none)]> SELECT EVENT_NAME, WORK_COMPLETED, WORK_ESTIMATED FROM performance_schema.events_stages_history
-> WHERE EVENT_NAME LIKE 'stage/innodb/clone%';
+--------------------------------+----------------+----------------+
| EVENT_NAME | WORK_COMPLETED | WORK_ESTIMATED |
+--------------------------------+----------------+----------------+
| stage/innodb/clone (file copy) | 70 | 70 |
| stage/innodb/clone (page copy) | 0 | 0 |
| stage/innodb/clone (redo copy) | 1 | 1 |
+--------------------------------+----------------+----------------+
3 rows in set (0.01 sec)
Monitoring Cloning Operations Using Performance Schema Clone Instrumentation
查看可用的 Clone Instrumentation:
[(none)]> SELECT NAME,ENABLED FROM performance_schema.setup_instruments
WHERE NAME LIKE '%clone%';
+----------------------------------------------+---------+
| NAME | ENABLED |
+----------------------------------------------+---------+
| wait/synch/mutex/innodb/clone_snapshot_mutex | NO |
| wait/synch/mutex/innodb/clone_sys_mutex | NO |
| wait/synch/mutex/innodb/clone_task_mutex | NO |
| wait/io/file/innodb/innodb_clone_file | YES |
| stage/innodb/clone (file copy) | YES |
| stage/innodb/clone (redo copy) | YES |
| stage/innodb/clone (page copy) | YES |
| statement/abstract/clone | YES |
| statement/clone/local | YES |
| statement/clone/client | YES |
| statement/clone/server | YES |
| memory/innodb/clone | YES |
| memory/clone/data | YES |
+----------------------------------------------+---------+
13 rows in set (0.01 sec)
可以分为:
- Wait Instruments
wait/synch/mutex/innodb/clone_snapshot_mutex
:跟踪 Clone Snapshot Mutex 等待事件。wait/synch/mutex/innodb/clone_sys_mutex
:跟踪 Clone Sys Mutex 等待事件。wait/synch/mutex/innodb/clone_task_mutex
:跟踪 Clone Task Mutex 等待事件。wait/io/file/innodb/innodb_clone_file
:跟踪克隆操作的文件的所有 I/O 等待操作。
- Stage Instruments
stage/innodb/clone (file copy)
:克隆操作中文件拷贝阶段的进度。stage/innodb/clone (page copy)
:克隆操作中变化页拷贝阶段的进度。stage/innodb/clone (redo copy)
:克隆操作中重做拷贝阶段的进度。
- Statement Instruments
statement/abstract/clone
:在将任何克隆操作分类为本地、客户端或服务器操作类型之前跟踪该操作的语句事件。statement/clone/local
:跟踪本地克隆操作的克隆语句事件,在执行CLONE LOCAL
语句时生成。statement/clone/client
:跟踪发生在副本库的远程克隆语句事件,在副本库执行CLONE INSTANCE
语句时生成。statement/clone/server
:跟踪发生在源库的远程克隆语句事件,在副本库执行CLONE INSTANCE
语句时生成。
- Memory Instruments
memory/innodb/clone
:跟踪 InnoDB 为动态快照分配的内存。memory/clone/data
:跟踪克隆操作期间克隆插件分配的内存。
Stopping a Cloning Operation
可以使用 KILL QUERY processlist_id
语句停止克隆操作。
在副本库,查询 performance_schema.clone_statu
表的 PID
列获取克隆操作的 Processlist Identifier(PID)。
[(none)]> SELECT * FROM performance_schema.clone_status\G
*************************** 1. row ***************************
ID: 1
PID: 27
STATE: In Progress
BEGIN_TIME: 2023-05-22 12:31:26.227
END_TIME: NULL
SOURCE: LOCAL INSTANCE
DESTINATION: /data/clone/
ERROR_NO: 0
ERROR_MESSAGE:
BINLOG_FILE:
BINLOG_POSITION: 0
GTID_EXECUTED:
1 row in set (0.00 sec)