我正在参加「掘金·启航计划」
在数据量剧增的今天,单一 MySQL 服务器已经无法满足用户需要,容易出现宕机、数据丢失、不可扩展等问题,所以多台 MySQL 服务器以主从模式为应用程序提供服务成为一种主流。
一、主从复制是什么?
“主从”是指多台 MySQL 服务器关系上的主从关系,一台 MySQL 服务器作为主服务器负责客户端写数据的请求,其他多台服务器作为从服务器为客户端提供读数据的请求。主从复制就是指主服务器更新数据后,其他从服务器从主服务器上复制数据,达到同步数据的效果。
主从模式的优点
- 数据更安全:做了数据冗余,不会因为单台服务器的宕机而丢失数据
- 性能大大提升:一主多从,不同用户从不同数据库读取,性能提升
- 扩展性更优:流量增大时,可以方便的增加从服务器,不影响系统使用
- 负载均衡:一主多从相当于分担了主机任务,做了负载均衡
二、主从复制的工作流程
MySQL 的主从复制依赖于 binlog ,也就是记录 MySQL 上的所有变化并以二进制形式保存在磁盘上。复制的过程就是将 binlog 中的数据从主库传输到从库上,关于bin log 可以看这篇文章MySQL之日志 - 掘金 (juejin.cn)。
- 第一步:主数据库将变更操作记录到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地址 |
|---|---|
| Master | 192.168.2.8 |
| Slave | 192.168.2.11 |
| 开放防火墙3306端口 |
sudo firewall-cmd --zone=public --add-port=3306/tcp --permanen
sudo firewall-cmd --permanent --list-ports
启动MySQL
systemctl start mysql
2.主库配置
(1)修改MySQL数据库的配置文件/etc/my.cnf
在最下面增加配置:
log-bin=mysql-bin #启用二进制日志
server-id=200 #服务器唯一id(唯一即可)
(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;
执行后保持现在状态,不要执行其他操作。
3.从库配置
(1)修改MySQL数据库的配置文件/etc/my.cnf
server-id=201 #服务器id
(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度变成纵向。
通过状态信息中的 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中是否将数据同步过去即可。
在master中创建数据库hong,可以看到slave中也同步创建了数据库hong。
在master中的数据库hong中创建表bjut,可以看到slave中也同步创建了表bjut。