龙空技术网

MySQL主从复制,从原理到实践,确定不来看看?

秃头JAVA 339

前言:

此时朋友们对“usingmysql”可能比较关心,小伙伴们都需要分析一些“usingmysql”的相关内容。那么小编也在网上搜集了一些关于“usingmysql””的相关文章,希望兄弟们能喜欢,兄弟们快快来学习一下吧!

前言

MySQL相信大家都很熟悉了,单节点MySQL出现性能瓶颈的时候,大家首先想到的是优化SQL。但是单节点毕竟能力有限,所以在优化之后,还是无法满足性能要求时,就会想到部署MySQL读写分离,也就是主从复制。除了性能瓶颈之外,还有单节点故障、单节点容量等问题,都必须依靠集群才能解决。本篇主要讲解MySQL从单机到集群的原理和实践。

环境VMware Workstation 15CentOS Linux release 7.7.1908MySQL 5.7.30注意事项三个节点ip分别为192.168.1.101、192.168.1.102、192.168.1.103确保三个节点都能访问互联网,并且三个节点能够相互通信确保Linux的yum、wget等基础命令可用建议先关闭防火墙,Centos 7操作如下firewall-cmd --state ## 查看防火墙状态 not running表示已经关闭 systemctl stop firewalld.service ## 关闭防火墙 systemctl disable firewalld.service ## 禁止开机启动防火墙 123

需要搭建的主从复制集群如下

单机安装安装

整个过程请保持网络畅通

wget -i -c  -y install mysql57-community-release-el7-10.noarch.rpmyum -y install mysql-community-server123

到这一步,MySQL服务的安装已经完成

启动

启动MySQL

systemctl start  mysqld.service1

查看运行状态

systemctl status mysqld.service1

执行结果

● mysqld.service - MySQL Server   Loaded: loaded (/usr/lib/systemd/system/mysqld.service; enabled; vendor preset: disabled)   Active: active (running) since 二 2020-06-02 21:58:25 CST; 11s ago     Docs: man:mysqld(8)             Process: 2160 ExecStart=/usr/sbin/mysqld --daemonize --pid-file=/var/run/mysqld/mysqld.pid $MYSQLD_OPTS (code=exited, status=0/SUCCESS)  Process: 2111 ExecStartPre=/usr/bin/mysqld_pre_systemd (code=exited, status=0/SUCCESS) Main PID: 2163 (mysqld)   CGroup: /system.slice/mysqld.service           └─2163 /usr/sbin/mysqld --daemonize --pid-file=/var/run/mysqld/mysqld.pid6月 02 21:58:18 localhost.localdomain systemd[1]: Starting MySQL Server...6月 02 21:58:25 localhost.localdomain systemd[1]: Started MySQL Server.12345678910111213

根据日志可以看到MySQL Server已经成功启动

找到临时密码

在MySQL的启动日志中,会打印一个临时密码用于登录,用户名是root

cat /var/log/mysqld.log |grep password

执行结果

2020-06-02T13:58:21.946584Z 1 [Note] A temporary password is generated for root@localhost: cScTwtyMl4;*

可以看到我此处的临时密码是cScTwtyMl4;*用这个密码登录,登录之后需要修改密码,才能进行其他的操作,且密码要满足一定的复杂度。

alter user 'root'@'localhost' identified by 'your password';

因为安装了Yum Repository,以后每次yum操作都会自动更新,需要把这个卸载掉

yum -y remove mysql57-community-release-el7-10.noarch

至此,此时MySQL的单机安装已经完成。其余节点均可按照此方法安装。

异步复制原理

不仅是MySQL,几乎所有的主从复制集群,都是master\slave模式,也就是slave节点从master节点上同步数据。MySQL主从复制的整个过程如下图所示

整个过程可以分为三个步骤

master节点把对数据的修改记录到bin log中,所以master节点必须开启bin logslave节点会从指定的位置(logfile和偏移量pos)开始读取master的bin log,把读取到的日志写入自己的relay log中slave节点根据relay log中的日志进行重放(replay),slave节点可以配置是否需要写入自己的bin log

了解了MySQL主从复制的基本原理,再来进行主从复制的搭建,就会容易理解很多。

异步复制缺点

为了了解异步复制的缺点,先看如下图

如图所示,描述了一主两从的异步复制集群,相信大家也很容易看出缺点。假设master节点commit之后就宕机了,而此时slave节点可能还没有读到master的全部bin log,就会导致数据丢失。

异步复制不仅不能保证master和slave之间的数据一致性,甚至不能保证slave与slave之间的数据一致性。

半同步复制

MySQL5.6对异步复制做了改进,引入半同步复制。

半同步复制过程如下

半同步复制在MySQL5.6中被引入,相比于异步复制,主要的改进就是在master写完bin log之后不会直接commit,而是收到slave节点的ACK之后才会commit,期间master的commit操作被阻塞。当然,为了防止部分slave节点故障导致master迟迟收到不ACK。master的commit操作可以设置超时时间,超时之后,半同步复制降级为异步复制。

有经验的同学应该可以看出来,这其实就是两阶段提交。master节点commit的时候,slave已经读取了master的完整bin log。即使此时master宕机,slave节点也能通过重放,实现和master节点的数据同步。

基于GTID复制

前文所讲的主从复制集群是依靠logfile + pos的方式实现,除了这种方式外,还有一种就是基于GTID的主从复制。GTID (Global Transaction ID)是全局事务ID。

GTID的结构如下:source_id:transaction_id,组成分成两个部分source_id和transaction_id,分别代表执行事务的主机UUID,和事务ID。事务ID是递增的,保证不重复。

master节点修改数据时,把GTID写入bin logslave读取master节点的bin log,写入到自己的relay logslave节点的sql_thread从relay log获取GTID,查找自己的bin log中是否有对应的记录如果有,说明该GTID的事务已经在slave上执行,slave会忽略该事务如果没有,slave就会从relay log中执行该事务,并记录到bin log

整个过程与logfile + pos方式几乎一致,只是获取执行偏移的方式不同。并且slave节点必须开启bin log。

基于GTID的复制和基于日志点的复制有什么区别?

基于日志点的复制是MySQL实现的第一种复制方式,几乎所有的MySQL分支版本都支持基于日志点的复制,slave请求master的增量日志依赖于日志偏移量基于日志点的复制配置复制链路时,需要指定master_log_file和master_log_pos参数,一旦master宕机,很难从新的master中找到正确的偏移量的值

优先选择基于GTID的复制,不能选择GTID的复制方式时,再使用基于日志点的复制。

实践异步复制开启bin log,使用如下命令查看bin log是否开启

show variables like '%log_bin%';+---------------------------------+-------+| Variable_name                   | Value |+---------------------------------+-------+| log_bin                         | OFF   || log_bin_basename                |       || log_bin_index                   |       || log_bin_trust_function_creators | OFF   || log_bin_use_v1_row_events       | OFF   || sql_log_bin                     | ON    |+---------------------------------+-------+6 rows in set (0.00 sec)

log_bin为OFF表示未开启,可以使用如下方式开启bin log

vim /etc/my.cnf

配置如下内容

## 开启bin loglog-bin=/var/lib/mysql/mysql-bin## 服务节点ID,每个节点不一样server-id=101## 开启GTID复制模式(如果只想用基于日志点复制,不需要配置这里)gtid-mode=onenforce-gtid-consistency=1

重启MySQL之后,再次查看bin log开启状态,可以看到bin log已经开启

show variables like '%log_bin%';+---------------------------------+--------------------------------+| Variable_name                   | Value                          |+---------------------------------+--------------------------------+| log_bin                         | ON                             || log_bin_basename                | /var/lib/mysql/mysql-bin       || log_bin_index                   | /var/lib/mysql/mysql-bin.index || log_bin_trust_function_creators | OFF                            || log_bin_use_v1_row_events       | OFF                            || sql_log_bin                     | ON                             |+---------------------------------+--------------------------------+6 rows in set (0.00 sec)

slave节点均按照此方式配置

master创建复制账号并授权

需要自己指定密码

create user repl@'192.168.1.%' identified by 'your password';grant replication slave on *.* to repl@'192.168.1.%';
备份master数据
mysqldump --single-transaction -uroot -p --routines --triggers --events --master-data=2 --all-databases > sicimike.sql

可以查看备份的文件中,有GTID和logfile:pos相关的信息

将备份的文件导入到slave节点的数据库。

在slave节点上配置复制链路

## MASTER_LOG_FILE和MASTER_LOG_POS的值在前一步中可以找到change master to master_host='192.168.1.101', MASTER_LOG_FILE='mysql-bin.000002', MASTER_LOG_POS=2615;

执行成功后,可以查看slave节点的状态

show slave status\G;*************************** 1. row ***************************               Slave_IO_State:                  Master_Host: 192.168.1.101                  Master_User:                  Master_Port: 3306                Connect_Retry: 60              Master_Log_File: mysql-bin.000002          Read_Master_Log_Pos: 2615               Relay_Log_File: localhost-relay-bin.000001                Relay_Log_Pos: 4        Relay_Master_Log_File: mysql-bin.000002             Slave_IO_Running: No            Slave_SQL_Running: No			......
启动复制链路
## 用户名和密码就是在master上配置的用户名和密码start slave user='repl' password= 'your password';

再次查看slave节点的状态

show slave status\G;*************************** 1. row ***************************               Slave_IO_State: Waiting for master to send event                  Master_Host: 192.168.1.101                  Master_User: repl                  Master_Port: 3306                Connect_Retry: 60              Master_Log_File: mysql-bin.000002          Read_Master_Log_Pos: 2615               Relay_Log_File: localhost-relay-bin.000002                Relay_Log_Pos: 320        Relay_Master_Log_File: mysql-bin.000002             Slave_IO_Running: Yes            Slave_SQL_Running: Yes			......
可以看到Slave_IO_Running和Slave_SQL_Running都变成了Yes状态,这两个线程就是前文主从复制原理图中io_thread和sql_thread其余的节点也是以同样的方式配置成slave节点。

至此,基于logfile:pos模式的异步复制已经配置完成。在master节点上进行数据的修改,马上就会同步到slave库。

可以在master节点上执行show slave hosts查看追随自己的所有slave节点

show slave hosts;+-----------+------+------+-----------+--------------------------------------+| Server_id | Host | Port | Master_id | Slave_UUID                           |+-----------+------+------+-----------+--------------------------------------+|       103 |      | 3306 |       101 | d6532e2a-a592-11ea-99c3-000c297f5b55 ||       102 |      | 3306 |       101 | 1dbd5375-a4d9-11ea-9eef-000c29cf4cca |+-----------+------+------+-----------+--------------------------------------+2 rows in set (0.00 sec)

接下来开始配置半同步复制。

半同步复制

首先查看master是否安装了半同步复制插件rpl_semi_sync_master,可以使用如下命令查看

show plugins;

如果没有安装的话,使用如下命令安装

install plugin rpl_semi_sync_master soname 'semisync_master.so';
配置master相关变量

首先查看半同步复制相关的变量

show variables like 'rpl%';+-------------------------------------------+------------+| Variable_name                             | Value      |+-------------------------------------------+------------+| rpl_semi_sync_master_enabled              | OFF        || rpl_semi_sync_master_timeout              | 10000      || rpl_semi_sync_master_trace_level          | 32         || rpl_semi_sync_master_wait_for_slave_count | 1          || rpl_semi_sync_master_wait_no_slave        | ON         || rpl_semi_sync_master_wait_point           | AFTER_SYNC || rpl_stop_slave_timeout                    | 31536000   |+-------------------------------------------+------------+7 rows in set (0.01 sec)

rpl_semi_sync_master_enabled变量需要改成ON

rpl_semi_sync_master_timeout表示半同步复制的超时时间,可以适当修改

依然是修改/etc/my.cof文件,配置如下内容

rpl_semi_sync_master_enabled=onrpl_semi_sync_master_timeout=500

配置完成后重启MySQL即可

查看slave是否安装了半同步复制插件rpl_semi_sync_slave可以使用如下命令

show plugins;

如果没有安装的话,使用如下命令安装

install plugin rpl_semi_sync_slave soname 'semisync_slave.so';
配置slave相关变量

首先查看半同步复制相关的变量

show variables like 'rpl%';+---------------------------------+----------+| Variable_name                   | Value    |+---------------------------------+----------+| rpl_semi_sync_slave_enabled     | OFF      || rpl_semi_sync_slave_trace_level | 32       || rpl_stop_slave_timeout          | 31536000 |+---------------------------------+----------+3 rows in set (0.01 sec)

rpl_semi_sync_slave_enabled变量需要改成ON,需要修改/etc/my.cof文件,配置如下内容

rpl_semi_sync_slave_enabled=on

slave完成配置,重启MySQL后,再次查看slave的状态

show slave status\G;*************************** 1. row ***************************               Slave_IO_State:                  Master_Host: 192.168.1.101                  Master_User:                  Master_Port: 3306                Connect_Retry: 60              Master_Log_File: mysql-bin.000003          Read_Master_Log_Pos: 194               Relay_Log_File: localhost-relay-bin.000005                Relay_Log_Pos: 4        Relay_Master_Log_File: mysql-bin.000003             Slave_IO_Running: No            Slave_SQL_Running: Yes			.....

可以看到,Slave_SQL_Running依然是Yes,只有Slave_IO_Running是NO,所以只需要重启slave的IO线程即可

start slave io_thread user='repl' password = 'your password';

启动完成后,基于logfile:pos模式的半同步复制也就配置完成。

GTID复制

由于上面的实验,我们已经启动了logfile + pos方式的复制链路,所以要改成GTID方式,先要停止slave,再重新配置复制链路

停止slave

在slave节点上执行如下命令

stop slave;
配置复制链路
change master to master_host='192.168.1.101', master_user='repl', master_password='your password', master_auto_position=1; 1
启动复制链路
start slave;

查看链路状态

show slave status \G;*************************** 1. row ***************************               Slave_IO_State: Waiting for master to send event                  Master_Host: 192.168.1.101                  Master_User: repl                  Master_Port: 3306                Connect_Retry: 60              Master_Log_File: mysql-bin.000003          Read_Master_Log_Pos: 811               Relay_Log_File: localhost-relay-bin.000002                Relay_Log_Pos: 414        Relay_Master_Log_File: mysql-bin.000003             Slave_IO_Running: Yes            Slave_SQL_Running: Yes              ......               Master_SSL_Crl:           Master_SSL_Crlpath:           Retrieved_Gtid_Set:            Executed_Gtid_Set: 1dbd5375-a4d9-11ea-9eef-000c29cf4cca:1,81502f9e-a592-11ea-b912-000c2928707c:1-11                Auto_Position: 1              ......

可以看到Auto_Position变成了1,说明启动了基于GTID方式的复制。

主从复制延迟

主从复制是一种异步复制模型,延迟自然是不可避免。只要延迟在业务能够接受的范围之内,都是可以容忍的。但是有时候主从复制的延迟会很大,可以总结为以下原因

master上执行了大事务,大事务是指耗时很长的事务。改进办法是把大事务转换成多个小事务。master和slave之间网络波动单个master节点下挂载的slave节点过多,可能会把master网卡带宽打满。改进办法就是减少单个master挂载slave的数量master节点会有多个线程同时写入,而slave节点进行replay的sql_thread只有一个。改进办法就是使用MySQL 5.7的多线程复制的方式、或者使用MGR复制架构。总结

本篇主要从理论到实践,完整的讲解了MySQL的几种主从模型。根据复制点的选取方式,可以分成基于日志点的方式和基于GTID的方式。根据master节点事务的提交方式可以分成异步复制和半同步复制。

作者:Sicimike

原文链接:

标签: #usingmysql