1.做数据的热备,将从库作为后备数据库,主数据库服务器故障后,可切换到从数据库继续工作,避免数据丢失。
2.满足业务需求,当业务量越来越大,O/I频率越来越高,单个主机已经无法满足需求,增添架构,可以分担业务量,提升O/I性能,也就是所谓的负载均衡。
3.为MySQL其他架构做基础,例如:读写分离,高可用。
通过字面上来看,最起码要有两台数据库,并且他们的关系是主与从。MySQL主从复制就是将数据库群中一台或多台服务器作为主(master)数据库,其他数据库作为从(slave)数据库,然后指向主库,实时同步主库中的数据;当主库数据发生变化时,会将变化的数据实时同步到一个或多个从库。
其中涉及到了三个线程和两个日志:
Binary log(二进制日志)和Binary log Jump Thread(二进制日志线程)属于主数据库。
I/OThread(输入/输出线程),Relay Log(中继日志)和SQL Thread(SQL线程)属于从数据库。
对于日志就不用多说了,不管是二进制日志还是中继日志,其中存放的都是SQL语句。
线程解释:
Binary log dump 线程
当从节点连接主节点后,主节点会创建一个log dump线程,用于发送binlog日志中的内容。
I/O线程
当从节点执行"start slave"命令后,从节点会创建一个I/O线程用来连接主节点,请求主库更新的binlog日志。I/O线程接收到主节点log dump线程发来的更新数据之后,保存到本地的relay log日志。
SQL线程
SQL线程读取relay log日志中的内容,然后解析成具体的SQL语句并执行,最终完成数据同步。
主从复制过程:
1)主节点数据更新,随后将具体的更新语句写到binlog日志中。
2)从节点开启主从复制功能,创建一个I/O线程,连接主节点。
3)主节点接收到从节点的连接后,创建一个binary log dump线程,把binlog日志中更新的内容发送到从节点。
4)从节点的I/O线程读取主节点发送的binlog日志,并写入到relay log中。
5)从库创建SQL线程,读取relay log日志中的内容,并解析执行,完成数据同步。
以上描述是一主一从架构,若是其他架构,其原理也是一样的,只不过细节上稍微有一点不一样。例如:一主多从架构,在主从复制时,主节点会分别为每个从节点创建一个binary log dump线程传递更新数据,而从节点使用各自的I/O线程和SQL线程。
MySQL的三种复制方式:
基于SQL语句复制(statement-based replication,简称SBR)
基于行的复制(row-based replication,简称RBR)
混合模式复制(mixed-based replication,简称MBR)
根据不同的方式,binlog日志的格式也有三种,分别是:STATEMENT(基于SQL语句复制),ROW(基于行的复制),MIXED (混合模式复制)。
STATEMENT模式(SBR)
会将数据修改的SQL语句写到binlog日志中,无需记录每行数据变化,减少了日志量,但有些数据无法保存,不能保证数据的一致性。
ROW模式(RBR)
此模式为默认。
仅记录数据被修改,修改成什么样子,不记录SQL语句信息,很大程度上保证了数据的一致性,但会产生大量的日志。
MIXED模式(MBR)
结合STATEMENT模式和ROW模式使用,优先使用STATEMENT模式保存binlog,对于STATEMENT模式无法保存的数据,则使用ROW模式进行保存。对于STATEMENT模式是否能够保存数据,由MySQL自行判断。
全同步模式
主库执行完一个事务后,所有从库也执行该事务,当所有从库都执行完该事务后才返回给客户端。
优点:确保数据的一致性
缺点:性能影响严重
异步复制
此模式为默认。
主库执行完一个事务后,立即将更新数据发送给从库,并不关心从库是否接收。
优点:减少部分资源消耗
缺点:无法确认从库是否复制成功
半同步模式
相当于异步复制的改良版,主库执行完事务后,至少一个从库接收并写入到relay log中才返回给客户端。
优点:确保从库复制成功
缺点:这个过程需要花费一部分时间
一主多从
提升负载均衡,可用于高可用和读写分离,但主节点I/O压力较大。
注:有人说这个架构可以提供负载均衡,我个人认为对的,但是每当有一个库数据更新,另一个库都需要消耗一部分资源来进行同步数据,架构还不如使用一主一从。
对于二进制日志的保存操作,默认的ROW格式并不是一个很好的选择,其会产生大量的日志数据,对后续的主从复制效率不高。
查看binlog格式
mysql> show variables like "binlog_format";
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| binlog_format | ROW |
+---------------+-------+
其实不管是主从架构,还是单纯的保存binlog日志,ROW格式都不是最好的选择,建议使用MIXED格式,其结合STATEMENT模式和ROW模式保存数据,即能减少日志的大小,又能确保数据的完整。
直接编辑/etc/my.cnf配置文件,在其中指定binlog日志格式即可。
binlog-format=MIXED
随后重启数据库,刷新配置。
/etc/init.d/mysql.server restart
再次进入到数据库中查看binlog日志格式
mysql> show variables like "binlog_format";
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| binlog_format | MIXED |
+---------------+-------+
已成功更改为MIXED模式。
以一主一从为例,列举了MySQL架构的搭建过程。
系统版本/MySQL版本 | 主机名 | IP地址 | 角色 | 准备 |
---|---|---|---|---|
CentOS7.7/MySQL8.0.13 | linux.node1 | 192.168.1.123 | master | 关闭防火墙,selinux |
CentOS7.7/MySQL8.0.13 | linux.node2 | 192.168.1.123 | slave | 关闭防火墙,selinux |
1)搭建时间同步服务
对于数据的实时同步,若两台服务器的时间都对不上,又谈何而来的实时同步呢?
主节点安装NTP服务
yum install -y ntp
修改ntp服务的配置文件,路径位于 /etc/ntp.conf ,并添加以下两项
server 127.127.1.0 #权威NTP不可用时,本机时间作为时间服务
fudge 127.127.1.0 stratum 8 #NTP服务的阶级层数,同步上层服务器的stratum 大小不能超过或等于16。
开启服务
systemctl start ntpd
查看端口
netstat -anpu | grep ntpd
udp 0 0 192.168.122.1:123 0.0.0.0:* 2726/ntpd
udp 0 0 192.168.1.123:123 0.0.0.0:* 2726/ntpd
udp 0 0 127.0.0.1:123 0.0.0.0:* 2726/ntpd
udp 0 0 0.0.0.0:123 0.0.0.0:* 2726/ntpd
udp6 0 0 fe80::8c62:89:ad82::123 :::* 2726/ntpd
udp6 0 0 ::1:123 :::* 2726/ntpd
udp6 0 0 :::123 :::* 2726/ntpd
从节点安装ntp客户端
yum install -y ntpdate
与主节点同步时间
ntpdate 192.168.1.123
19 Jun 16:31:27 ntpdate[61266]: adjust time server 192.168.1.123 offset 0.459178 sec
显示将时间偏移了0.459178秒,时间同步成功。
注:以下为主节点配置
2)创建测试数据
mysql> create database replication;
mysql> use replication;
mysql> create table test(id int,name varchar(233));
mysql> insert into test values(1,'一主一从');
3)创建主从复制授权用户
mysql> create user 'slave'@'192.168.1.%' identified by '123456';
mysql> grant replication slave on *.* to 'slave'@'192.168.1.%';
mysql> flush privileges;
4)修改my.cnf文件
以下为添加配置项
server-id=1
binlog-format=MIXED
log-bin=/data/mysql/log/mysql-bin-master
binlog-do-db=replication
#binlog-ignore-db=mysql
server-id: mysql的同步的数据中是包含server-id的,用于标识该语句最初是从哪个server写入,不同节点的server-id不能相同。
binlog-format:binlog日志格式
log-bin:binlog日志存放路径
binlog-do-db:指定binlog日志保存哪个库的数据记录,不添加为全库。
binlog-ignore-db:指定binlog日志不保存哪个库的数据记录,不添加为全部不保存。(若有binlog-do-db配置项,则只保存其指定的库)
重启数据库,刷新配置
/etc/init.d/mysql.server restart
5)查看生成的二进制日志
ls /data/mysql/log/
mysql-bin-master.000001 mysql-bin-master.index mysqld.log
数据库中查看
mysql> show master status\G
*************************** 1. row ***************************
File: mysql-bin-master.000001
Position: 155
Binlog_Do_DB: replication
Binlog_Ignore_DB: mysql
Executed_Gtid_Set:
6)将主库的数据传入从库
mysqldump -uroot replication > db.sql
scp db.sql root@192.168.1.124:~
The authenticity of host '192.168.1.124 (192.168.1.124)' can't be established.
ECDSA key fingerprint is SHA256:dt6xhgOGH0g33XrYjk1qPbtD4C2hg62DlqfRMoUSK88.
ECDSA key fingerprint is MD5:9b:ef:79:5b:01:9e:63:0d:75:a7:c7:3e:62:a7:6a:04.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.1.124' (ECDSA) to the list of known hosts.
root@192.168.1.124's password:
db.sql 100% 1817 2.3MB/s 00:00
注:以下为从节点配置
7)从库将SQL脚本导入库中
mysql -uroot -e "create database replication;"
mysql replication < db.sql
查看数据是否导入成功
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| replication |
| sys |
+--------------------+
8)修改my.cnf文件
在原有基础上添加以下配置项
server-id=2
relay-log=/data/mysql/log/relay-log-bin
relay-log-index=/data/mysql/log/slave-relay-bin.index
#replicate_do_db=replication
server-id:服务器ID号
relay-log:relay-log日志存放路径
relay-log-index:relay-log日志的索引文件存放路径
replicate_do_db:指定从库复制的数据库
重启服务,刷新配置
/etc/init.d/mysql.server restart
9)测试授权用户是否可以登录主库
mysql -uslave -h192.168.1.123 -p123456
登录进去后,查看其中的数据库
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
+--------------------+
因为只有主从复制权限,其他权限没有开放,所以是看不到其他库的,但不影响查看数据库的命令执行。
10)从库使用授权用户连接主库
这里的授权用户是由主库创建的,本案例中的为slave。
数据库默认是开启主从复制的,先关闭
mysql> stop slave;
连接主库,具体参数根据实际情况指定
mysql> change master to master_host='192.168.1.123',master_user='slave',master_password='123456',master_log_file='mysql-bin-master.000001',master_log_pos=155;
以下为此案例中主库的binlog日志文件,用于理解命令
mysql> show master status\G
*************************** 1. row ***************************
File: mysql-bin-master.000001
Position: 155
Binlog_Do_DB: replication
Binlog_Ignore_DB: mysql
Executed_Gtid_Set:
解读:
master_host:主库IP地址
master_user:主库授权用户
master_password:主库授权用户密码
master_log_file:主库binlog日志文件名称
master_log_pos:主库binlog日志文件位置
开启主从复制功能
mysql> start slave;
11)分别在主库和从库中查看主从复制状态
从库中查看
mysql> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.1.123
Master_User: slave
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin-master.000001
Read_Master_Log_Pos: 155
Relay_Log_File: relay-log-bin.000002
Relay_Log_Pos: 329
Relay_Master_Log_File: mysql-bin-master.000001
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB: replication
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: 155
Relay_Log_Space: 535
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: 1
Master_UUID: 1b3423c4-b047-11ea-bfaa-000c29bbe2d8
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:
Auto_Position: 0
Replicate_Rewrite_DB:
Channel_Name:
Master_TLS_Version:
Master_public_key_path:
Get_master_public_key: 0
其中 Slave_IO_Running和Slave_SQL_Running线程为YES,表示主库连接成功,也就是说主从复制搭建成功了。有一个为Connecting,都表示主从复制没有搭建成功。
主库中查看
mysql> show processlist\G
...
*************************** 3. row ***************************
Id: 18
User: slave
Host: 192.168.1.124:43856
db: NULL
Command: Binlog Dump
Time: 716
State: Master has sent all binlog to slave; waiting for more updates
Info: NULL
可以看到binlog dump线程已经建立,连接的主机为192.168.1.124。
12)验证主从复制功能
主库现有数据
mysql> select * from replication.test;
+------+--------------+
| id | name |
+------+--------------+
| 1 | 一主一从 |
+------+--------------+
从库现有数据
mysql> select * from replication.test;
+------+--------------+
| id | name |
+------+--------------+
| 1 | 一主一从 |
+------+--------------+
在主库中插入数据
mysql> insert into replication.test values(2,'测试');
在从库中查看数据是否同步成功
mysql> select * from replication.test;
+------+--------------+
| id | name |
+------+--------------+
| 1 | 一主一从 |
| 2 | 测试 |
+------+--------------+
若是主从状态正常,但数据没有同步成功,那大概率就是主库的binlog日志位置( Position)变了,使用show master status\G重新查看主库的binlog日志位置,再次连接主库即可。
或者说删除binlog日志(reset master),重新创建并连接。