mysql主从复制、基于gtid的主从复制、并行复制、半同步

主从复制

主从复制过程存在三个线程,Master端的I/O线程,Slave的I/O线程与SQL线程。Master端需要开启binlog日志,Slave端需要开启relaylog。
1、Slave端的I/O读取master.info文件,获取binlog文件名和位置点,然后向Master端的I/O线程请求,该binlog文件名和位置点的binlog信息。
(master.info文件在配置主从复制时使用change master命令来指定生成)
2、Master端的I/O线程会根据Slave端的I/O线程请求的信息来读取Master的binlog日志信息与及读取到最新的binlog文件名和位置点一同返回给Slave的I/O线程。
3、Slave端的I/O线程会把获取到的binlog日志写入relaylog(中继日志)文件中,并且更新master.info文件信息。(把读取到Master最新的binlog日志文件名和位置点更新到master.info文件中,下一次当前位置去读取Master的binlog日志)
4、Slave端的SQL线程会定期读取relaylog,把二进制的日志解析成SQL语句,并执行这些SQL语句,同步数据到从库中。
图解:
在这里插入图片描述
在这里插入图片描述
主从复制用途以及条件:
实时灾备,用于故障切换
读写分离,提供查询服务
备份,避免影响业务
主从部署的必要条件:
主库开启binlog日志(设置log-bin参数)
主从server-id不同
从库服务器能连同主库
实验环境:
rhel7.3
firewalld stop
selinux disabled

主机 ip
server3(master) 172.25.5.3
server4(slave) 172.25.5.4

mysql版本mysql-5.7.24

配置

server3(master)配置:

[root@server3 mnt]# tar xf mysql-5.7.24-1.el7.x86_64.rpm-bundle.tar   ##解压安装包
[root@server3 mnt]# ls
[root@server3 mnt]# yum install -y mysql-community-client-5.7.24-1.el7.x86_64.rpm mysql-community-common-5.7.24-1.el7.x86_64.rpm mysql-community-libs-5.7.24-1.el7.x86_64.rpm mysql-community-libs-compat-5.7.24-1.el7.x86_64.rpm mysql-community-server-5.7.24-1.el7.x86_64.rpm  ##下载相关软件
[root@server3 mnt]# scp mysql-community-client-5.7.24-1.el7.x86_64.rpm mysql-community-common-5.7.24-1.el7.x86_64.rpm mysql-community-libs-5.7.24-1.el7.x86_64.rpm mysql-community-libs-compat-5.7.24-1.el7.x86_64.rpm mysql-community-server-5.7.24-1.el7.x86_64.rpm [email protected]:/mnt/ ##把安装包给slave发送过去以便4号slave主机安装
[root@server3 mnt]# vim /etc/my.cnf  ###编辑mysql的配置文件
server-id=1                 #必须为 1 到 232-1 之间的一个正整数值
log-bin=mysql-bin        #启动二进制日志系统
[root@server3 mnt]# systemctl start mysqld  ##启动数据库
[root@server3 mnt]# cat /var/log/mysqld.log |grep password   #查看初始密码
2019-02-24T00:41:34.247637Z 1 [Note] A temporary password is generated for root@localhost: 2ao/<n.e-uwW
[root@server3 mnt]# mysql_secure_installation    #数据库初始化
[root@server3 mnt]# mysql -p      ##登陆数据库
mysql> grant replication slave on *.* to westos@'172.25.5.%' identified by 'Asimov+123';  ##创建同步帐户,并给予权限
                                                              
mysql> show master status;    ##记录 File 和 Position 的值,配置slave时会用到
+------------------+----------+--------------+------------------+-------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000002 |     1004 |              |                  |                   |
+------------------+----------+--------------+------------------+-------------------+

server4(slave)配置:

[root@server4 mnt]# ls
[root@server4 mnt]# yum install * -y     ##下载数据库
[root@server4 mnt]# vim /etc/my.cnf    ##修改数据库配置文件
server-id=2     #从服务器 ID 号,不要和主 ID 相同,如果设置多个从服务器,每个从服务器必
须有一个唯一的 server-id 值,必须与主服务器的以及其它从服务器的不相同。
可以认为 server-id 值类似于 IP 地址:这些 ID 值能唯一识别复制服务器群集
中的每个服务器实例。
[root@server4 mnt]# systemctl start mysqld    ##启动数据库
[root@server4 mnt]# cat /var/log/mysqld.log |grep password  ##查看初始密码
2019-02-24T00:49:19.548891Z 1 [Note] A temporary password is generated for root@localhost: XClw>oZ3Xoj%
[root@server4 mnt]# mysql_secure_installation   ##数据库初始化
[root@server4 mnt]# mysql -p    ##登陆数据库
mysql>  change master to master_host='172.25.5.3',master_user='westos',master_password='Asimov+123',master_log_file='mysql-bin.000002',master_log_pos=1004;    ##登陆 mysql 指定要复制的 master,二进制日至文件和位置就是前面master的master的信息一致
Query OK, 0 rows affected, 2 warnings (0.01 sec)
mysql> start slave;  ##开启slave
mysql> show slave status\G;  ##查看slave的状态
Slave_IO_Running: Yes
Slave_SQL_Running: Yes       ##这两yes表示配置成功(io和sql)
##IO为no可能原因:日至文件,用户,网路防火墙
##SQL为no可能原因:本地问题,主从信息不一致

测试
在server3上创建库和表,在server4上会同步过来
sever3:

mysql> create database westos;
mysql> create table usertb (
    -> name varchar(10) not null,
    -> password varchar(10) not null);
mysql> desc usertb;
+----------+-------------+------+-----+---------+-------+
| Field    | Type        | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+-------+
| name     | varchar(10) | NO   |     | NULL    |       |
| password | varchar(10) | NO   |     | NULL    |       |
+----------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
mysql> insert into usertb values ('redhat','123');
mysql> select * from usertb;
+--------+----------+
| name   | password |
+--------+----------+
| redhat | 123      |
+--------+----------+

server4:

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
| westos             |
+--------------------+

基于gtid主从复制

GTID:
1)全局事务标识:global transaction identifiers。
2)GTID是一个事务一一对应,并且全局唯一ID。
3)一个GTID在一个服务器上只执行一次,避免重复执行导致数据混乱或者主从不一致。
4)GTID用来代替传统复制方法,不再使用MASTER_LOG_FILE+MASTER_LOG_POS开启复制。而是使用MASTER_AUTO_POSTION=1的方式开始复制。
5)MySQL-5.6.5开始支持的,MySQL-5.6.10后开始完善。
6)在传统的slave端,binlog是不用开启的,但是在GTID中slave端的binlog是必须开启的,目的是记录执行过的GTID(强制)。

组成:
1)GTID = source_id:transaction_id
2)source_id:用于鉴别原服务器,即mysql服务器唯一的的server_uuid,由于GTID会传递到slave,所以也可以理解为源ID。
3)transaction_id:为当前服务器上已提交事务的一个序列号,通常从1开始自增长的序列,一个数值对应一个事务。

原理:
1)master更新数据时,会在事务前产生GTID,一同记录到binlog日志中。
2)slave端的i/o 线程将变更的binlog,写入到本地的relay log中。
3)sql线程从relay log中获取GTID,然后对比slave端的binlog是否有记录。
4)如果有记录,说明该GTID的事务已经执行,slave会忽略。
5)如果没有记录,slave就会从relay log中执行该GTID的事务,并记录到binlog。
6)在解析过程中会判断是否有主键,如果没有就用二级索引,如果没有就用全部扫描。
配置(在上一个实验的基础上):

server3(master):

[root@server3 mysql]# vim /etc/my.cnf   ##修改配置文件
添加
gtid_mode=ON     #开启gtid模式
enforce_gtid_consistency=true   ##强制gtid一致性,开启后对于特定create table不被支持
[root@server3 mysql]# systemctl restart mysqld  ##重启数据库
[root@server3 mysql]# mysql -p
mysql> reset master;   ##这一步如果配置完server4(slave)会报错,需要做这一步

server4(slave):

扫描二维码关注公众号,回复: 5348752 查看本文章
[root@server4 mysql]# vim /etc/my.cnf  ##修改配置文件(加入和server3一样的内容)
gtid_mode=ON
enforce_gtid_consistency=true
[root@server4 mysql]# systemctl restart mysqld    
[root@server4 mysql]# mysql -p   ##登陆mysql
mysql> stop slave;   ##把之前的slvae停掉
mysql> change master to master_host='172.25.5.3',master_user='westos',master_password='Asimov+123',master_auto_position=1;##修改master指定的用户,注意这里不是手动设置二进制文件信息和位置,变成了自动设置
mysql> start slave;    ##开启slave服务
mysql> show slave status\G;   ##查看是否配置完成
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes

半同步复制

MySQL默认的复制即是异步的,主库在执行完客户端提交的事务后会立即将结果返给给客户端,并不关心从库是否已经接收并处理,这样就会有一个问题,主如果crash掉了,此时主上已经提交的事务可能并没有传到从上,如果此时,强行将从提升为主,可能导致新主上的数据不完整。
只当主库执行完一个事务,所有的从库都执行了该事务才返回给客户端。因为需要等待所有从库执行完该事务才能返回,所以全同步复制的性能必然会收到严重的影响。
介于异步复制和全同步复制之间,主库在执行完客户端提交的事务后不是立刻返回给客户端,而是等待至少一个从库接收到并写到relay log中才返回给客户端。相对于异步复制,半同步复制提高了数据的安全性,同时它也造成了一定程度的延迟,这个延迟最少是一个TCP/IP往返的时间。所以,半同步复制最好在低延时的网络中使用。
默认情况下MySQL是异步复制,异步复制可以提供最佳的性能。主库把binlog日志发送给从库,从库IO线程接收存入中继日志,SQL线程执行二进制日志以同步主库数据。这一过程并不会验证从库是否接收完毕,也就意味着有可能出现当主服务器或从服务器端发生故障的时候,有可能从服务器没有接收到主服务器发送过来的binlog日志,这就会造成主服务器和从服务器的数据不一致,甚至在恢复时造成数据的丢失。
MySQL5.5之后支持半自动同步模式,该模式可以确保从服务器接收完主服务器发送的binlog日志文件并写入到自己的中继日志relay log里,然后会给主服务器一个反馈,告诉主服务器已经接收完毕,这时主服务线程才返回给当前session告知操作完成。
当出现超时情况是,主服务器会暂时切换到异步复制模式,直到至少有一个从服务器从及时收到信息为止。
从MySQL5.5开始,增加了relay_log_recovery参数,这个参数的作用是:当slave从库宕机后,假如relay.log损坏了,导致一部分中继日志没有处理,则自动放弃所有未执行的relay-log,并且重新从master上获取日志,这样就保证了relay-log的完整性。默认情况下该功能是关闭的,将relay_log_recovery的值设置为1时,可在slave从库上开启该功能,建议开启。
半同步复制与异步复制的切换:
半同步复制的工作原理就是当slave从库IO_Thread线程将binlog日志接收完毕之后,要给master主库一个确认,如果rpl_semi_sync_master_timeout=10000 (10秒)超过10秒未收到slave从库的接受确认信号,那么就会自动切换为传统的异步复制模式。

MySQL支持两种略有不同的半同步复制:AFTER_SYNC和AFTER_COMMIT(受rpl_semi_sync_master_wait_wait_point控制),MySQL5.7.3开始支持配置半同步复制等待Slave应答的个数:rpl_semi_sync_master_wait_slave_count 。
AFTER_SYNC: 日志复制到Slave之后,Master再commit。
所有在master上commit的事务都已经复制到slave。
所有已经复制到slave的事务在master不一定commit了(比如,master将日志复制到slave之后,在commit之前宕机了)
AFTER_COMMIT:Master commit之后再将日志复制到Slave。
所有master上commit的事务不一定复制到slave。(比如,master commit之后,还没来得及将日志复制到slave就宕机了)
所有已经复制到slave的事务在master上一定commit了。
注意:
半同步复制模式必须在主服务器和从服务器端同时开启,否则主服务器默认使用异步复制模式。

图解:
在这里插入图片描述
在这里插入图片描述
配置(在上一个实验的基础上):
server3(master):

mysql> INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
Query OK, 0 rows affected (0.02 sec) ##安装master的半同步模块
mysql> set global rpl_semi_sync_master_enabled=1;  ##临时生效,如果永久生效,要写到mysql的配置文件里面
Query OK, 0 rows affected (0.00 sec)
mysql> show status like '%rpl%';  ##查看半同步模块是否开启
mysql> show variables like '%rpl%';##查看半同步模块的默认参数

参数说明:

  • rpl_semi_sync_master_enabled = 1,表示在master上已经开启了半同步复制模式;
  • rpl_semi_sync_master_timeout = 10000,表示如果主库在某次事务中的等待时间超过10000毫秒,则降级为异步复制模式,不在等待slave从库。如果主库再次探测到slave从恢复了,则会自动切换回半同步复制模式;一般生产环境中为了保障主从一致,会把timeout设置为无穷大
  • rpl_semi_sync_master_wait_no_slave ,表示是否允许master每个事务提交后都要等待slave的接收确认信号。默认为ON,即每一个事务都会等待。如果为OFF,则slave追赶上之后,也不会开启半同步复制模式,需要手工开启;
  • rpl_semi_sync_master_trace_level = 32,指用于开启半同步复制模式时的调试级别,默认为32,可以看出,在配置Master的时候,只设置了1,其他的都采取的默认设置。

server4(slave):

mysql> INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so'; ##添加slave端的半同步模块
Query OK, 0 rows affected (0.00 sec)

mysql> set global rpl_semi_sync_slave_enabled=1;  ##同样要永久生效要写到配置文件里面
Query OK, 0 rows affected (0.00 sec)
mysql> stop slave io_thread;
Query OK, 0 rows affected (0.00 sec)
mysql> start slave io_thread;   ##重新启动io线程
Query OK, 0 rows affected (0.00 sec)
mysql> start slave io_thread;
Query OK, 0 rows affected (0.00 sec)
mysql> show status like '%rpl%';   ##查看半同步模块的参数
+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| Rpl_semi_sync_slave_status | ON    |
+----------------------------+-------+
1 row in set (0.00 sec)
mysql> show variables like '%rpl%';  ##查看半同步的默认参数
+---------------------------------+----------+
| Variable_name                   | Value    |
+---------------------------------+----------+
| rpl_semi_sync_slave_enabled     | ON       |
| rpl_semi_sync_slave_trace_level | 32       |
| rpl_stop_slave_timeout          | 31536000 |
+---------------------------------+----------+

测试
在server4上停止io线程

myql> stop slave io_thread;

在server3上插入数据时会默认等待10秒,会自动切会异步同步

并行复制(在主从复制的基础上)

基于组的并发复制,可以支持在一个database中,并发执行relaylog中的事务。相同的二进制日志组在master上提交并行应用到slave节点上,没有跨数据库的限制,并且不需要把数据分割到多个数据库。
配置:
server4(slave):

server4(slave):
[root@server4 mysql]# vim /etc/my.cnf   (添加)
slave-parallel-type=LOGICAL_CLOCK  ##基于组提交的并行用户
slave-parallel-workers=10        ##开启10个worker:单线程变成多线程(前两个必须加入,后面为优化)
master_info_repository=TABLE ##优化选项,默认以文件存储,记录master信息,用表来记录,更新速度更快
relay_log_info_repository=TABLE  ##读日志信息,用表来记录(原来是记录在磁盘里)
relay_log_recovery=ON     ## 激活recovery:读取master二进制日志,如果损坏,直接丢弃然后重新读取
[root@server4 mysql]# systemctl restart mysqld  ##重新启动数据库

配置完成登陆数据库

mysql> use mysql;
mysql> show tables;  ##配置完成,登陆数据库,在mysql数据库中可以看见系统自动建立了三个表

在这里插入图片描述

mysql> show processlist;  ##查看线程
+----+-------------+-----------+-------+---------+------+--------------------------------------------------------+------------------+
| Id | User        | Host      | db    | Command | Time | State                                                  | Info             |
+----+-------------+-----------+-------+---------+------+--------------------------------------------------------+------------------+
|  1 | system user |           | NULL  | Connect |   93 | Waiting for master to send event                       | NULL             |
|  2 | system user |           | NULL  | Connect |   93 | Slave has read all relay log; waiting for more updates | NULL             |
|  4 | system user |           | NULL  | Connect |   93 | Waiting for an event from Coordinator                  | NULL             |
|  5 | system user |           | NULL  | Connect |   93 | Waiting for an event from Coordinator                  | NULL             |
|  6 | system user |           | NULL  | Connect |   93 | Waiting for an event from Coordinator                  | NULL             |
|  7 | system user |           | NULL  | Connect |   93 | Waiting for an event from Coordinator                  | NULL             |
|  8 | system user |           | NULL  | Connect |   93 | Waiting for an event from Coordinator                  | NULL             |
|  9 | system user |           | NULL  | Connect |   93 | Waiting for an event from Coordinator                  | NULL             |
| 10 | system user |           | NULL  | Connect |   93 | Waiting for an event from Coordinator                  | NULL             |
| 11 | system user |           | NULL  | Connect |   93 | Waiting for an event from Coordinator                  | NULL             |
| 12 | system user |           | NULL  | Connect |   93 | Waiting for an event from Coordinator                  | NULL             |
| 13 | system user |           | NULL  | Connect |   93 | Waiting for an event from Coordinator                  | NULL             |
| 14 | root        | localhost | mysql | Query   |    0 | starting                                               | show processlist |
+----+-------------+-----------+-------+---------+------+--------------------------------------------------------+------------------+
13 rows in set (0.00 sec)
## 从库会有十个线程来等待事物处理,已经不是一个了。

猜你喜欢

转载自blog.csdn.net/weixin_43407305/article/details/87911235