MySQL主从复制(MySQL Replication)是指从一个MySQL主服务器(master)将数据拷贝到另一台或多台MySQL从服务器(slaves)的过程。将主数据库的DDL和DML操作通过二进制日志(binlog)传到从服务器(slave)上,然后在从服务器上对这些日志重新执行,从而使得主从服务器的数据保持同步。 MySQL从3.23版本开始提供复制的功能。
MySQL的Replication是一个多MySQL数据库做主从同步的方案,广泛用在各种对MySQL有更高性能、更高可靠性要求的场合。
主从复制有以下几方面的好处:
-- 设置主从的网络环境
docker pull mysql:5.7.30
docker network create --subnet=172.72.0.0/24 mysql-network
-- 删除之前的容器
docker rm -f MSS5730M33650 MSS5730S33651 MSS5730S33652
-- 创建参数文件路径
mkdir -p /lhrmysqltest3/master/conf.d
mkdir -p /lhrmysqltest3/slave1/conf.d
mkdir -p /lhrmysqltest3/slave2/conf.d
-- 申请主库环境
docker run -d --name MSS5730M33650 \
-h master -p 33650:3306 --net=mysql-network --ip 172.72.0.50 \
-v /lhrmysqltest3/master/conf.d:/etc/mysql/conf.d \
-e MYSQL_ROOT_PASSWORD=lhr \
mysql:5.7.30
-- 申请从库1环境
docker run -d --name MSS5730S33651 \
-h slave1 -p 33651:3306 --net=mysql-network --ip 172.72.0.51 \
-v /lhrmysqltest3/slave1/conf.d:/etc/mysql/conf.d \
-e MYSQL_ROOT_PASSWORD=lhr \
mysql:5.7.30
-- 申请从库2环境
docker run -d --name MSS5730S33652 \
-h slave2 -p 33652:3306 --net=mysql-network --ip 172.72.0.52 \
-v /lhrmysqltest3/slave2/conf.d:/etc/mysql/conf.d \
-e MYSQL_ROOT_PASSWORD=lhr \
mysql:5.7.30
-- 配置主库参数
cat > /lhrmysqltest3/master/conf.d/my.cnf <<"EOF"
[mysqld]
port=3306
character_set_server=utf8mb4
secure_file_priv=
server-id = 573033650
log-bin =
binlog_format=row
skip-name-resolve
gtid-mode=ON
enforce-gtid-consistency=on
report_host=172.72.0.50
default-time-zone = '+8:00'
log_timestamps = SYSTEM
log_slave_updates = 1
master_info_repository='table'
relay_log_info_repository='table'
relay_log_recovery=1
EOF
-- 配置从库1参数
cat > /lhrmysqltest3/slave1/conf.d/my.cnf <<"EOF"
[mysqld]
port=3306
character_set_server=utf8mb4
secure_file_priv=
server-id = 573033651
log-bin =
binlog_format=row
gtid-mode=ON
enforce-gtid-consistency=ON
skip_name_resolve
report_host=172.72.0.51
default-time-zone = '+8:00'
log_timestamps = SYSTEM
log_slave_updates = 1
master_info_repository='table'
relay_log_info_repository='table'
relay_log_recovery=1
EOF
-- 配置从库2参数
cat > /lhrmysqltest3/slave2/conf.d/my.cnf <<"EOF"
[mysqld]
user=mysql
port=3306
character_set_server=utf8mb4
secure_file_priv=
server-id = 573033652
log-bin =
binlog_format=row
gtid-mode=ON
enforce-gtid-consistency=ON
skip_name_resolve
report_host=172.72.0.52
default-time-zone = '+8:00'
log_timestamps = SYSTEM
log_slave_updates = 1
master_info_repository='table'
relay_log_info_repository='table'
relay_log_recovery=1
EOF
-- 重启3台环境
docker restart MSS5730M33650
docker restart MSS5730S33651
docker restart MSS5730S33652
docker ps
-- 登陆
docker exec -it MSS5730M33650 bash
docker exec -it MSS5730M33650 mysql -uroot -plhr
-- 查询
mysql -uroot -plhr -h192.168.66.35 -P33650 -e "select @@hostname,@@server_id,@@server_uuid"
mysql -uroot -plhr -h192.168.66.35 -P33651 -e "select @@hostname,@@server_id,@@server_uuid"
mysql -uroot -plhr -h192.168.66.35 -P33652 -e "select @@hostname,@@server_id,@@server_uuid"
-- 主库创建复制用户repl
mysql -uroot -plhr -h192.168.66.35 -P33650
grant replication slave on *.* to repl@'%' identified by 'lhr';
select user,host,grant_priv,password_last_changed,authentication_string from mysql.user;
create database lhrdb;
use lhrdb;
create table mytb1(id int,name varchar(30));
insert into mytb1 values(1,'a'),(2,'b');
select * from mytb1;
-- 导出时不能加--set-gtid-purged=off参数
mysqldump -uroot -plhr -h192.168.66.35 -P33650 --single-transaction --hex-blob --routines --events --triggers \
--master-data=2 --databases lhrdb --default-character-set=utf8 --max_allowed_packet=512M > /tmp/salve.sql
-- 查询
show master status ;
show slave hosts;
select @@hostname,@@server_id,@@server_uuid;
执行过程:
MySQL [lhrdb]> show master status ;
+-------------------+----------+--------------+------------------+------------------------------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+-------------------+----------+--------------+------------------+------------------------------------------+
| master-bin.000004 | 1085 | | | 1bc15639-bc5b-11eb-b1eb-0242ac480032:1-9 |
+-------------------+----------+--------------+------------------+------------------------------------------+
1 row in set (0.06 sec)
MySQL [lhrdb]> show slave hosts;
Empty set (0.06 sec)
MySQL [lhrdb]> select @@hostname,@@server_id,@@server_uuid;
+------------+-------------+--------------------------------------+
| @@hostname | @@server_id | @@server_uuid |
+------------+-------------+--------------------------------------+
| master | 573033650 | 1bc15639-bc5b-11eb-b1eb-0242ac480032 |
+------------+-------------+--------------------------------------+
1 row in set (0.05 sec)
-- 从库1导入数据
mysql -uroot -plhr -h192.168.66.35 -P33651
-- 重置master,否则执行导入脚本时报错:ERROR 1840 (HY000) at line 24: @@GLOBAL.GTID_PURGED can only be set when @@GLOBAL.GTID_EXECUTED is empty.
reset master;
mysql -uroot -plhr -h192.168.66.35 -P33651 < /tmp/salve.sql
-- 配置同步
change master to
master_host='172.72.0.50',
master_port=3306,
master_user='repl',
master_password='lhr',
master_auto_position=1;
-- 启动复制进程
start slave;
show slave status \G;
SELECT * FROM lhrdb.mytb1;
-- 主库:
insert into mytb1 values(3,'c'),(4,'d');
-- S2
mysql -uroot -plhr -h192.168.66.35 -P33652
-- 修改参数,配置同步
change master to master_host='172.72.0.50',
master_port=3306,
master_user='repl',
master_password='lhr',
master_auto_position=1;
start slave;
show slave status \G;
SELECT * FROM lhrdb.mytb1;
-- 测试同步
insert into mytb1 values(5,'e'),(6,'f');
-- 主库
show slave hosts;
show master status;
-- 从库
show slave status;
-- 线程查询
SELECT *
FROM performance_schema.threads a
WHERE a.`NAME` IN ( 'thread/sql/slave_IO', 'thread/sql/slave_sql' ) or a.PROCESSLIST_COMMAND in ('Binlog Dump','Binlog Dump GTID') ;
SELECT * FROM information_schema.`PROCESSLIST` a where a.USER='system user' or a.command in ('Binlog Dump','Binlog Dump GTID') ;
MySQL [(none)]> show slave status \G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 172.72.0.50
Master_User: repl
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: master-bin.000004
Read_Master_Log_Pos: 1085
Relay_Log_File: slave1-relay-bin.000002
Relay_Log_Pos: 417
Relay_Master_Log_File: master-bin.000004
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Master_Log_Pos: 1085
Relay_Log_Space: 625
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Master_SSL_Allowed: No
Master_SSL_CA_File:
Master_SSL_CA_Path:
Master_SSL_Cert:
Master_SSL_Cipher:
Master_SSL_Key:
Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Master_Server_Id: 573033650
Master_UUID: 1bc15639-bc5b-11eb-b1eb-0242ac480032
Master_Info_File: mysql.slave_master_info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
Master_Retry_Count: 86400
Master_Bind:
Last_IO_Error_Timestamp:
Last_SQL_Error_Timestamp:
Master_SSL_Crl:
Master_SSL_Crlpath:
Retrieved_Gtid_Set:
Executed_Gtid_Set: 1bc15639-bc5b-11eb-b1eb-0242ac480032:1-9
Auto_Position: 1
Replicate_Rewrite_DB:
Channel_Name:
Master_TLS_Version:
SHOW SLAVE STATUS会返回以下字段:
SHOW PROCESSLIST输出的State字段的拷贝。SHOW PROCESSLIST用于从属I/O线程。如果线程正在试图连接到主服务器,正在等待来自主服务器的时间或正在连接到主服务器等,本语句会通知您 slave I/O线程的状态,有以下几种: 1) waiting for master update 这是connecting to master状态之前的状态 2) connecting to master I/O线程正尝试连接到master 3) checking master version 在与master建立连接后,会出现该状态。该状态出现的时间非常短暂。 4) registering slave on master 在与master建立连接后,会出现该状态。该状态出现的时间非常短暂。 5) requesting binlog dump 在与master建立连接后,会出现该状态。该状态出现的时间非常短暂。在这个状态下,I/O线程向master发送请求,请求binlog,位置从指定的binglog 名字和binglog的position位置开始。 6) waiting to reconnect after a failed binlog dump request 如果因为连接断开,导致binglog的请求失败,I/O线程会进入睡眠状态。然后定期尝试重连。尝试重连的时间间隔,可以使用命令"change master to master_connect_trt=X;"改变。 7) reconnecting after a failed binglog dump request I/O进程正在尝试连接master 8) waiting for master to send event 说明,已经成功连接到master,正等待二进制日志时间的到达。如果master 空闲,这个状态会持续很长时间。如果等待的时间超过了slave_net_timeout(单位是秒)的值,会出现连接超时。在这种状态下,I/O线程会人为连接失败,并开始尝试重连 9) queueing master event to the relay log 此时,I/O线程已经读取了一个event,并复制到了relay log 中。这样SQL 线程可以执行此event 10) waiting to reconnect after a failed master event read 读取时出现的错误(因为连接断开)。在尝试重连之前,I/O线程进入sleep状态,sleep的时间是master_connect_try的值(默认是60秒) 11) reconnecting after a failed master event read I/O线程正尝试重连master。如果连接建立,状态会变成"waiting for master to send event" 12) waiting for the slave sql thread to free enough relay log space 这是因为设置了relay_log_space_limit,并且relay log的大小已经整张到了最大值。I/O线程正在等待SQL线程通过删除一些relay log,来释放relay log的空间。 13) waiting for slave mutex on exit I/O线程停止时会出现的状态,出现的时间非常短。
被用于连接主服务器的当前用户。这个是master上面的一个用户。用来负责主从复制的用户,创建主从复制的时候建立的(具有reolication slave权限)。
当前的主服务器端口,master服务器的端口,一般是3306。
--master-connect-retry选项的当前值。连接中断后,重新尝试连接的时间间隔。默认值是60秒。
I/O线程当前正在读取的主服务器二进制日志文件的名称。
在当前的主服务器二进制日志中,I/O线程已经读取的位置。
SQL线程当前正在读取和执行的中继日志文件的名称。
在当前的中继日志中,SQL线程已读取和执行的位置。(Relay_Log_File下的Relay_Log_Pos其实一一对应着Relay_Master_Log_File的Exec_Master_Log_Pos。)
由SQL线程执行的包含多数近期事件的主服务器二进制日志文件的名称。当前slave SQL线程读取并执行的relay log的文件中多数近期事件,对应的主服务器二进制日志文件的名称。(说白点就是SQL线程从relay日志中读取的正在执行的sql语句,对应主库的sql语句记录在主库的哪个binlog日志中)
I/O线程是否被启动并成功地连接到主服务器上。
SQL线程是否被启动。
使用--replicate-do-db和--replicate-ignore-db选项指定的数据库清单。 Replicate_Do_Table,Replicate_Ignore_Table,Replicate_Wild_Do_Table,Replicate_Wild_Ignore_Table 使用--replicate-do-table,--replicate-ignore-table,--replicate-wild-do-table和--replicate-wild-ignore_table选项指定的表清单。
被多数最近被执行的查询返回的错误数量和错误消息。错误数量为0并且消息为空字符串意味着“没有错误”。如果Last_Error值不是空值,它也会在从属服务器的错误日志中作为消息显示。 举例说明: Last_Errno: 1051 Last_Error: error 'Unknown table 'z'' on query 'drop table z' 该消息指示,表z曾经存在于在主服务器中并已被取消了,但是它没有在从属服务器中存在过,因此对于从属服务器,DROP TABLE失败。(举例说明,在设置复制时,如果您忘记了把此表拷贝到从属服务器中,则这有可能发生。)
最近被使用的用于SQL_SLAVE_SKIP_COUNTER的值,用于设置跳过sql执行步数。
来自主服务器的二进制日志的由SQL线程执行的上一个时间的位置(Relay_Master_Log_File)。在主服务器的二进制日志中的(Relay_Master_Log_File,Exec_Master_Log_Pos)对应于在中继日志中的(Relay_Log_File,Relay_Log_Pos)。
所有原有的中继日志结合起来的总大小。
在START SLAVE语句的UNTIL子句中指定的值。 Until_Condition具有以下值: 如果没有指定UNTIL子句,则没有值 如果从属服务器正在读取,直到达到主服务器的二进制日志的给定位置为止,则值为Master 如果从属服务器正在读取,直到达到其中继日志的给定位置为止,则值为Relay Until_Log_File和Until_Log_Pos用于指示日志文件名和位置值。日志文件名和位置值定义了SQL线程在哪个点中止执行。
这些字段显示了被从属服务器使用的参数。这些参数用于连接主服务器。 Master_SSL_Allowed具有以下值: 如果允许对主服务器进行SSL连接,则值为Yes 如果不允许对主服务器进行SSL连接,则值为No 如果允许SSL连接,但是从属服务器没有让SSL支持被启用,则值为Ignored。 与SSL有关的字段的值对应于--master-ca,--master-capath,--master-cert,--master-cipher和--master-key选项的值。
本字段是从属服务器“落后”多少的一个指示。当从属SQL线程正在运行时(处理更新),本字段为在主服务器上由此线程执行的最近的一个事件的时间标记开始,已经过的秒数。当此线程被从属服务器I/O线程赶上,并进入闲置状态,等待来自I/O线程的更多的事件时,本字段为零。总之,本字段测量从属服务器SQL线程和从属服务器I/O线程之间的时间差距,单位以秒计。 如果主服务器和从属服务器之间的网络连接较快,则从属服务器I/O线程会非常接近主服务器,所以本字段能够十分近似地指示,从属服务器SQL线程比主服务器落后多少。如果网络较慢,则这种指示不准确;从属SQL线程经常会赶上读取速度较慢地从属服务器I/O线程,因此,Seconds_Behind_Master经常显示值为0。即使I/O线程落后于主服务器时,也是如此。换句话说,本列只对速度快的网络有用。 即使主服务器和从属服务器不具有相同的时钟,时间差计算也会起作用(当从属服务器I/O线程启动时,计算时间差。并假定从此时以后,时间差保持不变)。如果从属SQL线程不运行,或者如果从属服务器I/O线程不运行或未与主服务器连接,则Seconds_Behind_Master为NULL(意义为“未知”)。举例说明,如果在重新连接之前,从属服务器I/O线程休眠了master-connect-retry秒,则显示NULL,因为从属服务器不知道主服务器正在做什么,也不能有把握地说落后多少。
主从复制,从库忽略的主库服务器Id号。就是不以这些服务器Id为主库。
一个非负整数,表示秒数,Slave滞后多少秒于master。表示是否配置延迟从库。
当 Slave_SQL_Running_State 等待,直到MASTER_DELAY秒后,Master执行的事件,此字段包含一个整数,表示有多少秒左右的延迟。在其他时候,这个字段是NULL。
SQL线程运行状态: 1) Reading event from the relay log 线程已经从中继日志读取一个事件,可以对事件进行处理了。 2) Has read all relay log; waiting for the slave I/O thread to update it 线程已经处理了中继日志文件中的所有事件,现在正等待I/O线程将新事件写入中继日志。 3) Waiting for slave mutex on exit 线程停止时发生的一个很简单的状态。
连接主库失败最多的重试次数。
slave从库在多网络接口的情况下使用,以确定用哪一个slave网络接口连接到master。
主从复制状态查询:
可以对比以下2个值,是否一致:
Master_Log_File= Relay_Master_Log_File
Read_Master_Log_Pos= Exec_Master_Log_Pos
证明目前没有主从延迟状态。
另外也可以直接查询Seconds_Behind_Master字段:
Seconds_Behind_Master: 0 #从库的延迟
-- 在主库查询:
MySQL [lhrdb]> show slave hosts;
+-----------+-------------+------+-----------+--------------------------------------+
| Server_id | Host | Port | Master_id | Slave_UUID |
+-----------+-------------+------+-----------+--------------------------------------+
| 573033651 | 172.72.0.51 | 3306 | 573033650 | 41618dbd-7bea-11eb-9d95-0242ac480033 |
| 573033652 | 172.72.0.52 | 3306 | 573033650 | 43036dd9-7bea-11eb-8dcb-0242ac480034 |
+-----------+-------------+------+-----------+--------------------------------------+
2 rows in set (0.05 sec)
-- PROCESSLIST_COMMAND为Binlog Dump表示非GTID复制,Binlog Dump GTID表示MySQL 5.6.5版本新增的基于GTID复制
MySQL [lhrdb]> SELECT *
-> FROM performance_schema.threads a
-> WHERE a.`NAME` IN ( 'thread/sql/slave_IO', 'thread/sql/slave_sql' ) or a.PROCESSLIST_COMMAND in ('Binlog Dump','Binlog Dump GTID') ;
+-----------+---------------------------+------------+----------------+------------------+------------------+----------------+---------------------+------------------+---------------------------------------------------------------+---------------------------------------------------------+------------------+------+--------------+---------+-----------------+--------------+
| THREAD_ID | NAME | TYPE | PROCESSLIST_ID | PROCESSLIST_USER | PROCESSLIST_HOST | PROCESSLIST_DB | PROCESSLIST_COMMAND | PROCESSLIST_TIME | PROCESSLIST_STATE | PROCESSLIST_INFO | PARENT_THREAD_ID | ROLE | INSTRUMENTED | HISTORY | CONNECTION_TYPE | THREAD_OS_ID |
+-----------+---------------------------+------------+----------------+------------------+------------------+----------------+---------------------+------------------+---------------------------------------------------------------+---------------------------------------------------------+------------------+------+--------------+---------+-----------------+--------------+
| 28 | thread/sql/one_connection | FOREGROUND | 2 | repl | 172.72.0.51 | NULL | Binlog Dump GTID | 583 | Master has sent all binlog to slave; waiting for more updates | SET @slave_uuid= '41618dbd-7bea-11eb-9d95-0242ac480033' | 1 | NULL | YES | YES | TCP/IP | 76 |
| 29 | thread/sql/one_connection | FOREGROUND | 3 | repl | 172.72.0.52 | NULL | Binlog Dump GTID | 582 | Master has sent all binlog to slave; waiting for more updates | SET @slave_uuid= '43036dd9-7bea-11eb-8dcb-0242ac480034' | 1 | NULL | YES | YES | TCP/IP | 77 |
+-----------+---------------------------+------------+----------------+------------------+------------------+----------------+---------------------+------------------+---------------------------------------------------------------+---------------------------------------------------------+------------------+------+--------------+---------+-----------------+--------------+
2 rows in set (0.05 sec)
MySQL [lhrdb]> SELECT * FROM information_schema.`PROCESSLIST` a where a.USER='system user' or a.command in ('Binlog Dump','Binlog Dump GTID') ;
+----+------+-------------------+------+------------------+------+---------------------------------------------------------------+------+
| ID | USER | HOST | DB | COMMAND | TIME | STATE | INFO |
+----+------+-------------------+------+------------------+------+---------------------------------------------------------------+------+
| 3 | repl | 172.72.0.52:35566 | NULL | Binlog Dump GTID | 1340 | Master has sent all binlog to slave; waiting for more updates | NULL |
| 2 | repl | 172.72.0.51:34004 | NULL | Binlog Dump GTID | 1341 | Master has sent all binlog to slave; waiting for more updates | NULL |
+----+------+-------------------+------+------------------+------+---------------------------------------------------------------+------+
2 rows in set (0.05 sec)
-- 在从库查询:
MySQL [(none)]> SELECT *
-> FROM performance_schema.threads a
-> WHERE a.`NAME` IN ( 'thread/sql/slave_IO', 'thread/sql/slave_sql' ) or a.PROCESSLIST_COMMAND='Binlog Dump' ;
+-----------+----------------------+------------+----------------+------------------+------------------+----------------+---------------------+------------------+--------------------------------------------------------+------------------+------------------+------+--------------+---------+-----------------+--------------+
| THREAD_ID | NAME | TYPE | PROCESSLIST_ID | PROCESSLIST_USER | PROCESSLIST_HOST | PROCESSLIST_DB | PROCESSLIST_COMMAND | PROCESSLIST_TIME | PROCESSLIST_STATE | PROCESSLIST_INFO | PARENT_THREAD_ID | ROLE | INSTRUMENTED | HISTORY | CONNECTION_TYPE | THREAD_OS_ID |
+-----------+----------------------+------------+----------------+------------------+------------------+----------------+---------------------+------------------+--------------------------------------------------------+------------------+------------------+------+--------------+---------+-----------------+--------------+
| 26 | thread/sql/slave_io | FOREGROUND | 1 | NULL | NULL | NULL | Connect | 199 | Waiting for master to send event | NULL | 1 | NULL | YES | YES | NULL | 73 |
| 27 | thread/sql/slave_sql | FOREGROUND | 2 | NULL | NULL | NULL | Connect | 199 | Slave has read all relay log; waiting for more updates | NULL | 1 | NULL | YES | YES | NULL | 74 |
+-----------+----------------------+------------+----------------+------------------+------------------+----------------+---------------------+------------------+--------------------------------------------------------+------------------+------------------+------+--------------+---------+-----------------+--------------+
2 rows in set (0.06 sec)
MySQL [(none)]> SELECT * FROM information_schema.`PROCESSLIST` a where a.USER='system user' or a.command='Binlog Dump';
+----+-------------+------+------+---------+------+--------------------------------------------------------+------+
| ID | USER | HOST | DB | COMMAND | TIME | STATE | INFO |
+----+-------------+------+------+---------+------+--------------------------------------------------------+------+
| 2 | system user | | NULL | Connect | 312 | Slave has read all relay log; waiting for more updates | NULL |
| 1 | system user | | NULL | Connect | 312 | Waiting for master to send event | NULL |
+----+-------------+------+------+---------+------+--------------------------------------------------------+------+
2 rows in set (0.05 sec)
本文结束。