MySQL之主从复制

154 阅读7分钟

我正在参加「掘金·启航计划」

在数据量剧增的今天,单一 MySQL 服务器已经无法满足用户需要,容易出现宕机、数据丢失、不可扩展等问题,所以多台 MySQL 服务器以主从模式为应用程序提供服务成为一种主流。

一、主从复制是什么?

“主从”是指多台 MySQL 服务器关系上的主从关系,一台 MySQL 服务器作为主服务器负责客户端写数据的请求,其他多台服务器作为从服务器为客户端提供读数据的请求。主从复制就是指主服务器更新数据后,其他从服务器从主服务器上复制数据,达到同步数据的效果。

主从模式的优点

  • 数据更安全:做了数据冗余,不会因为单台服务器的宕机而丢失数据
  • 性能大大提升:一主多从,不同用户从不同数据库读取,性能提升
  • 扩展性更优:流量增大时,可以方便的增加从服务器,不影响系统使用
  • 负载均衡:一主多从相当于分担了主机任务,做了负载均衡

二、主从复制的工作流程

MySQL 的主从复制依赖于 binlog ,也就是记录 MySQL 上的所有变化并以二进制形式保存在磁盘上。复制的过程就是将 binlog 中的数据从主库传输到从库上,关于bin log 可以看这篇文章MySQL之日志 - 掘金 (juejin.cn)

主从复制工作流程.png

  • 第一步:主数据库将变更操作记录到bin log
  • 第二步:从库的I/O线程读取主库中的bin log并写入自己的relay log(中继日志)
  • 第三步:从库的SQL线程读取relay log,在从库中进行replay,更新数据库数据

在上述三个过程中,涉及了Master的BinlogDump Thread和Slave的I/O Thread、SQL Thread,它们的作用如下:

  • Master服务器对数据库更改操作记录在bin log中,bin log dump Thread接到写入请求后,读取 bin log信息推送给Slave的I/O Thread。
  • Slave的I/O Thread将读取到的bin log信息写入到本地relay Log中。
  • Slave的SQL Thread检测到relay Log的变更请求,解析relay log中内容在从库上执行。 上述过程都是异步操作,俗称异步复制,存在数据延迟现象。

三、主从复制模型

这样的工作流程存在着两个问题:

  • 第一,过于依赖Master节点,会出现常见的Master宕机,从库还没得及复制,导致数据丢失。
  • 第二,数据量大时,主库写压力也会剧增,导致服务延时。

关于这两个问题,主从模式设置了四种模型:

  • 同步复制:MySQL 主库提交事务的线程要等待所有从库的复制成功响应,才返回客户端结果。这种方式在实际项目中,基本上没法用,原因有两个:一是性能很差,因为要复制到所有节点才返回响应;二是可用性也很差,主库和所有从库任何一个数据库出问题,都会影响业务。
  • 异步复制(默认模型):MySQL 主库提交事务的线程并不会等待 binlog 同步到各从库,就返回客户端结果。这种模式一旦主库宕机,数据就会发生丢失。
  • 半同步复制:MySQL 5.7 版本之后增加的一种复制方式,介于两者之间,事务线程不用等待所有的从库复制成功响应,只要一部分复制成功响应回来就行,比如一主二从的集群,只要数据成功复制到任意一个从库上,主库的事务线程就可以返回给客户端。这种半同步复制的方式,兼顾了异步复制和同步复制的优点,即使出现主库宕机,至少还有一个从库有最新的数据,不存在数据丢失的风险
  • 并行复制:不同版本的并行复制是不一样的,MySQL并行复制功能是从5.6版本开始追加的,目的是改善复制延迟问题。到MySQL5.7实现了基于组提交的并行复制,从库的并行复制跟master库的是一致的。MySQL8.0实现基于write-set的并行复制,MySQL会有一个集合变量用来存储事务修改的记录信息(主键哈希值),当新的修改提交时,会进行判断是否冲突,不冲突即可合并,这样的并行颗粒度达到row级别,并行复制速度更快。并行复制主要解决的就是从库复制延迟的问题。

四、主从复制实现

1.环境配置:

虚拟机:两台相同配置的centos7系统
MySQL版本:5.7.25

数据库ip地址
Master192.168.2.8
Slave192.168.2.11
开放防火墙3306端口
sudo firewall-cmd --zone=public --add-port=3306/tcp --permanen
sudo firewall-cmd --permanent --list-ports

Snipaste_2023-02-28_09-12-10.jpg

启动MySQL
systemctl start mysql

Snipaste_2023-02-28_09-13-35.jpg

2.主库配置

(1)修改MySQL数据库的配置文件/etc/my.cnf

在最下面增加配置:

log-bin=mysql-bin #启用二进制日志
server-id=200     #服务器唯一id(唯一即可)

Snipaste_2023-02-28_09-34-06.jpg

(2)重启MySQL服务

systemctl restart mysqld

(3)创建数据同步的用户并授权

GRANT REPLICATION SLAVE ON *.* to 'xiaohong'@'%' identified by 'Root@123456';
上面SQL的作用是创建一个用户xiaohong,密码为 Root@123456 ,并且给xiaohong用户授予REPLICATION SLAVE权限。常用于建立复制时所需要用到的用户权限,也就是slave必须被master授权具有该权限的用户,才能通过该用户复制。

(4)查看Master同步状态

show master status;

Snipaste_2023-02-28_09-43-36.jpg

执行后保持现在状态,不要执行其他操作。

3.从库配置

(1)修改MySQL数据库的配置文件/etc/my.cnf

server-id=201 #服务器id

Snipaste_2023-02-28_09-48-07.jpg

(2)重启MySQL服务

systemctl restart mysqld

(3)登录Mysql数据库,设置主库地址及同步位置

change master to master_host='192.168.2.8',master_user='root',master_password='123456',master_log_file='mysql-bin.000003',master_log_pos=154;

start slave;

参数说明:

  • master_host : 主库的IP地址
  • master_user : 访问主库进行主从复制的用户名(上面在主库创建的)
  • master_password : 访问主库进行主从复制的用户名对应的密码
  • master_log_file : 从哪个日志文件开始同步(上述查询master状态中展示的有)
  • master_log_pos : 从指定日志文件的哪个位置开始同步(上述查询master状态中展示的有)

(4)查看从库状态

mysql> show slave status\G;
在MySQL的sql语句后加上\G,表示将查询结果进行按列打印,可以使每个字段打印到单独的行。即将查到的结构旋转90度变成纵向。

Snipaste_2023-02-28_10-23-01.jpg
通过状态信息中的 Slave_IO_running 和 Slave_SQL_running 可以看出主从同步是否就绪,如果这两个参数全为Yes,表示主从同步已经配置完成。

(5)存在问题

我配置完后出现了
Slave_IO_Running: Connecting  # 出现错误,IO线程处于正在连接状态

通过在网上查找方法:有以下三种解决方法。
方法一:首先在从数据库链接登录主数据库,查看是否能够成功登录 。 mysql -uroot -proot -h192.168.2.8(主数据库分配的user和pwd以及主数据库的IP地址) 假如不能登录则需要关闭防火墙后重试

systemctl stop firewalld 关闭网络防火墙 
systemctl disable firewalld 关闭开机自启动(永久关闭)

方法二:由于测试是使用本地虚拟机实现,我的虚拟机是使用克隆出来的两个虚拟机,所以在文件夹/var/lib/mysql下面的auto.cnf文件中server-uuid=c7d66103-b6b1-11ed-810b-000c29d069aa ,两个虚拟机数据库的uuid相同,所以导致一直处于Slave_IO_Running: Connecting状态,将主从数据库中的auto.cnf文件删除后重新启动数据库后可以解决。

方法三:由于每次数据库重启后都会导致master status发生变化,所以需要根据当前的master status来修改从数据库中的SQL同步语句

5.测试验证

主从复制的环境已经搭建好了,接下来,我们可以通过Navicat连接上两台MySQL服务器,进行测试。测试时,我们只需要在主库master执行操作,查看从库slave中是否将数据同步过去即可。

Snipaste_2023-02-28_10-34-20.jpg

在master中创建数据库hong,可以看到slave中也同步创建了数据库hong。

Snipaste_2023-02-28_10-35-11.jpg

在master中的数据库hong中创建表bjut,可以看到slave中也同步创建了表bjut。

Snipaste_2023-02-28_10-36-27.jpg