MySQL主从复制原理

学习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有三种格式,分别是:

  1. statement:基于SQL语句的模式,某些语句和函数如UUID、LOAD DATA INFILE等在复制的过程中可能导致数据不一致甚至出错。
  2. row:基于行的模式,记录的是行的变化,很安全。但是binlog会比其他两种模式大很多,在一些大表中清除大量数据时在binlog中会生成很多条语句,导致从库延迟变大。
  3. mixed:混合模式,根据语句来选择使用statement还是row模式。

2、主从复制原理

MySQL主从复制的过程:主机将binlog日志异步的方式进行记录并传输到从库上,从库通过IO线程将主库传输过来的binlog日志写入relay log日志中,再利用SQL线程来读取relay log日志中的内容,再进行执行,以做到主从数据的一致性。

详细过程如下:

  1. 主机更新DDL、DML操作语句到binlog日志中。
  2. 主机创建log dump线程来完成binlog日志的传输。
  3. 从机在连接上主机时,会创建一个IO线程。当binlog日志更新并传输过来时,IO线程会将接收到的binlog日志信息写入到relay log日志中。
  4. 从机通过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主从复制原理,你知道么?》

你可能感兴趣的:(mysql,数据库,服务器)