学习MySQL主从复制,从以下几个方面进行:
1. 什么是MySQL主从复制?
2. 为什么要使用主从复制?
3. 主从复制的原理?
4. 主从复制的劣势?
5. 主从切换
6. 实际操作
一、什么是MySQL主从复制?
顾名思义,MySQL主从复制指的是至少存在两台MySQL服务器(后续的描述中,以两台为例),一台为从机,一台为主机。从机会复制主机中的内容,从而达到主机跟从机数据一致的目的。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MFUxKnez-1660964331726)(https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/76feb57355d54cf49941dccb2b9dc45a~tplv-k3u1fbpfcp-watermark.image?)]
二、为什么要使用主从复制?
个人觉得使用MySQL主从复制的原因有以下几点:
1、容灾性
当MySQL主机宕机时,从机将成为主机,可以防止因为主机宕机而带来影响,保证服务高可用。因为从机中的数据和主机中的一致,因此也可以将从机看作是主机的备份,如果主机的数据丢失,可以使用从机的数据。
2、降低主机压力
使用MySQL主从复制,即便在不使用读写分离的情况下,将请求分摊到两台MySQL服务器上,也会大大减少主机的压力。而MySQL在一般的环境中,属于读多写少,因此可以进行读写分离,写在主机上进行,读在从机上进行,这样做可以提高从机的查询性能,也能减少主机的压力。
3、异地多活
这点跟容灾性差不多,将MySQL主从复制做成异地多活,如果主机服务器坏了,从而导致MySQL主机宕机,从机将会替代主机的工作,降低因为主机宕机所带来的影响。
三、主从复制的原理
MySQL主从复制核心在于MySQL主机的binlog日志。
1、binlog日志
MySQL的binlog是记录所有数据库表结构变更以及表数据修改(DDL、DML)的二进制日志,而对于show、select(DQL)等查询操作,binlog不会记录下来,因为这对数据并没有什么改变。
DDL:数据库定义语句,如创建库、表、修改库、表等操作。
DML:数据操作语句,如数据的增删改。
DQL:数据查询语句,如show、select之类。
binlog有三种格式,分别是:
- statement:基于SQL语句的模式,某些语句和函数如UUID、LOAD DATA INFILE等在复制的过程中可能导致数据不一致甚至出错。
- row:基于行的模式,记录的是行的变化,很安全。但是binlog会比其他两种模式大很多,在一些大表中清除大量数据时在binlog中会生成很多条语句,导致从库延迟变大。
- mixed:混合模式,根据语句来选择使用statement还是row模式。
2、主从复制原理
MySQL主从复制的过程:主机将binlog日志异步的方式进行记录并传输到从库上,从库通过IO线程将主库传输过来的binlog日志写入relay log日志中,再利用SQL线程来读取relay log日志中的内容,再进行执行,以做到主从数据的一致性。
详细过程如下:
- 主机更新DDL、DML操作语句到binlog日志中。
- 主机创建log dump线程来完成binlog日志的传输。
- 从机在连接上主机时,会创建一个IO线程。当binlog日志更新并传输过来时,IO线程会将接收到的binlog日志信息写入到relay log日志中。
- 从机通过SQL线程读取relay log日志中的内容,并进行执行,最终实现主从机数据的一致性。
四、主从复制的劣势
主从复制的优势在上面第二点为什么要使用主从复制中已经提到了。那主从复制有什么劣势呢?
1、劣势
个人认为,主从复制最大的劣势就是因为网络原因造成的消息延迟,从而引出了消息一致性的问题。因为网络的原因,主机在发送消息给从机时,会受到影响,从而消耗时间,当从机接收到消息时,已经是几秒之后了,如果对数据一致性要求较高的场景下,处理起来比较麻烦。MySQL主从复制消息一致性问题在网上有很多解决方法,可以通过搜索进行浏览。
还有一些问题就是,binlog开启row格式,在大数据的情况下,会产生很多数据,这些数据是持久化到磁盘的,因此会占用磁盘空间。
五、主从切换
在主从复制模式下,主机A一般负责写的业务,从机B一般负责读的业务。如果主机A发生意外宕机了,从机B则会成为主机B负责读写。当主机A修复完成之后,主机A则会变成从机A。
六、实际操作
在本文的实际操作中,MySQL是使用docker容器进行布置的,并且一台MySQL布置在一台服务器上。
1、主机配置
(1). 在docker中启动MySQL主机
docker run -d -p 3306:3306 --name mysql-master
-v /home/mysql/master/log:/var/log/mysql
-v /home/mysql/master/data:/var/lib/mysql
-v /home/mysql/master/conf:/etc/mysql
-v /home/mysql/master/mysql-files:/var/lib/mysql-files
-e MYSQL_ROOT_PASSWORD=root
--privileged=true mysql:8.0
注意:开启容器时挂在了四个数据卷,其中data为持久化时的存储位置;log为日志;conf为配置文件存放位置;mysql-files为必须指定。此为MySQL8.0版本,MySQL5版本可能存在差异。
(2). 编写配置文件
在/home/mysql/master/conf目录下编写: vim my.cnf
[mysqld]
## 设置server_id,同一局域网中需要唯一
server_id=1
## 指定不需要同步的数据库名称
binlog-ignore-db=mysql
## 开启binlog日志
log-bin=mysql-bin
(3). 重启mysql-master容器:docker restart mysql-master
(4). 创建数据同步用户
## 创建用户
CREATE USER 'slave'@'%' IDENTIFIED BY '123456';
## 授予权限
GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'slave'@'%';
(5). 进入mysql-master容器中,查看binlog日志信息
# 进入mysql-master容器
docker exec -it mysql-master bash
# 进入MySQL控制台
mysql -uroot -proot
# 查看binlog是否正确开启,ON为开启,OFF为关闭
show variables like 'log_bin';
# 打印binlog状态信息
show master status\G
注意:打印binlog状态信息时,其中的File、Position在配置从机时需要使用,需要记录下来。
2、从机配置
(1). 在docker中开启mysql从机
docker run -d -p 3306:3306 --name mysql-slave
-v /home/mysql/slave/log:/var/log/mysql
-v /home/mysql/slave/data:/var/lib/mysql
-v /home/mysql/slave/conf:/etc/mysql
-v /home/mysql/slave/mysql-files:/var/lib/mysql-files
-e MYSQL_ROOT_PASSWORD=root
--privileged=true mysql:8.0
(2). 在/home/mysql/slave/conf目录下:vim my.cnf
[mysqld]
## 设置server_id,同一局域网中需要唯一
server_id=2
(3). 重启mysql-slave容器:docker restart mysql-slave
(4). 进入mysql-slave容器,配置主从复制
# 进入mysql-master容器
docker exec -it mysql-slave bash
# 进入MySQL控制台
mysql -uroot -proot
# 配置主从复制信息
change master to
master_host='主机ip地址',
master_user='slave',
master_password='123456',
master_port=3306,
master_log_file='mysql-bin.000001',
master_log_pos=906,
master_connect_retry=30,
get_master_public_key=1;
# 配置主从复制信息详解
# master_host:主数据库的IP地址;
# master_port:主数据库的运行端口;
# master_user:在主数据库创建的用于同步数据的用户账号;
# master_password:在主数据库创建的用于同步数据的用户密码;
# master_log_file:指定从数据库要复制数据的日志文件,通过查看主数据的状态,获取File参数;
# master_log_pos:指定从数据库从哪个位置开始复制数据,通过查看主数据的状态,获取Position参数;
# master_connect_retry:连接失败重试的时间间隔,单位为秒。
# get_master_public_key:获取master主机的sha2密钥
注意:mysql8默认使用插件caching_sha2_password,需要拿到server的public key来加密password。添加参数get_master_public_key=1可以解决问题。
(5). 查看主从同步状态:show slave status\G
在显示的参数中,Slave_IO_Running、Slave_SQL_Running均为No,是因为还没开启主从同步。
(6). 开启同步状态:start slave;
注意:如果在同步时报 Slave failed to initialize relay log info structure from the repository 错误,通过 docker logs mysql-slave 可以查看出错日志,如果relay-bin.index文件的错误,通过命令 reset slave
重新设置即可解决。
(7). 查看主从同步状态:show slave status\G
注意:刚开启主从同步的时候,Slave_IO_State: Connecting to source、Slave_IO_Running: Connecting表示当前从机还在连接主机的状态中,需要等待。如果等待太久没有连接上,则可能是配置的时候出错了。
成功连接之后,显示Slave_IO_State:Waiting for source to send event;Slave_IO_Running:Yes;Slave_SQL_Running:Yes。
3、主从复制测试
create database test;
use test;
CREATE TABLE test_table (
id int NOT NULL COMMENT '序列id',
name varchar(255) DEFAULT NULL COMMENT '名称',
price double COMMENT '价格',
number int COMMENT '数量',
description varchar(1024) COMMENT '描述',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
在从机中查看,即可查看到从机中也出现了先对应的数据库表。
参考资料
微信公众号:楼仔《MySQL主从复制原理,你知道么?》