一、了解主从复制
1.主从复制的原理:
影响MySQL-A数据库的操作,在数据库执行后,都会写入本地的日志系统A中。假设,实时的将变化了的日志系统中的数据库事件操作,在MYSQL-A的3306端口,通过网络发给MYSQL-B。MYSQL-B收到后,写入本地日志系统B,然后一条条的将数据库事件在数据库中完成。那么,MYSQL-A的变化,MYSQL-B也会变化,这样就是所谓的MYSQL的复制,即MYSQL replication。
在上面的模型中,MYSQL-A就是主服务器,即master,MYSQL-B就是从服务器,即slave。
日志系统A,其实它是MYSQL的日志类型中的二进制日志,也就是专门用来保存修改数据库表的所有动作,即bin log
日志系统B,并不是二进制日志,由于它是从MYSQL-A的二进制日志复制过来的,并不是自己的数据库变化产生的,有点接力的感觉,称为中继日志,即relay log。
可以发现,通过上面的机制,可以保证MYSQL-A和MYSQL-B的数据库数据一致,但是时间上肯定有延迟,即MYSQL-B的数据是滞后的。
2.主从复制的几种方式:
同步复制
所谓的同步复制,意思是master的变化,必须等待slave-1,slave-2,...,slave-n完成后才能返回。
这样,显然不可取,也不是MYSQL复制的默认设置。比如,在WEB前端页面上,用户增加了条记录,需要等待很长时间
异步复制
如同AJAX请求一样。master只需要完成自己的数据库操作即可。至于slaves是否收到二进制日志,是否完成操作,不用关心。MYSQL的默认设置。
半同步复制
master只保证slaves中的一个操作成功,就返回,其他slave不管。
这个功能,是由google为MYSQL引入的。
3.mysql主从复制用途
1)实时灾备,用于故障切换
2)读写分离,提供查询服务
3)备份,避免影响业务
4.主从部署必要条件:
1)主库开启binlog日志(设置log-bin参数)
2)主从server-id不同
3)从库服务器能连通主库
MySQL复制原理,其通过三个线程来完成,在master节点上运行的binlogdump线程以及在slave节点上运行的I/O线程和SQL线程。
1. master节点上的binlogdump线程,在slave与其正常连接的情况下,将binlog发送到slave上。
2.slave节点上的I/O线程,通过读取master节点发送的内容,并将数据复制到本地的relaylog(中继日志)中。
3.slave节点上的SQL线程,读取relaylog中的日志,并将其事务在本地执行。
二、mysql异步复制
在主节点上执行完命令之后生成一个日志文件,然后将日志文件发送给从节点,最后提交,从节点收到日志文件后,开始同步里面的数据(事物),最后得到与主节点一致的数据
环境:rhel6.5
两台主机:server1:master
server2:slave
1) 在两台主机上安装服务
在server1(master)和server2上(master)
tar xf mysql-5.7.17-1.el6.x86_64.rpm-bundle.tar ##解压安装包
yum install -y mysql-community-client-5.7.17-1.el6.x86_64.rpm
mysql-community-common-5.7.17-1.el6.x86_64.rpm
mysql-community-libs-5.7.17-1.el6.x86_64.rpm
mysql-community-libs-compat-5.7.17-1.el6.x86_64.rpm
mysql-community-server-5.7.17-1.el6.x86_64.rpm
在server1上(master)
vim /etc/my.cnf
写入:server-id=1 #数据库中的id号,三者不能相同
log-bin=mysql-bin #允许slave同步自己的二进制文件
/etc/init.d/mysqld start ###打开数据库
grep password /var/log/mysqld.log ###查看日志,l里面有数据库初始密码
mysql_secure_installation ###进行数据库初始化
mysql -p
show databases;
mysql> grant replication slave on *.* to westos@’172.25.45.%’ identified by ‘SHIjin_?’; #对172.25.45.%网段有权限同步
show master status ##查看master的状态
在server2上(slave)
查看授权是否成功
mysql -u westos -p -h 172.25.45.1
vim /etc/my.cnf 写入:server-id=2
/etc/init.d/mysqld start
grep password /var/log/mysqld.log ##查看日志,看初始化密码
mysql_secure_installation ###进行数据库初始化
mysql -p ###登陆即可,密码为你设定的密码
在master中:
mysql> show master status;
在slave中:
change master to master_host='172.25.45.1',master_user='westos',master_password='SHIjin_?',master_log_file='mysql-bin.000004',master_log_pos=1089; # master_log_file和master_log_pos与上边server1的保持一致
mysql> start slave;
mysql> show slave status\G
这两个参数都为yes就证明成功了
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
测试:
在master中:
mysql> create database test;
mysql> use test;
mysql> create table userlist(
username varchar(15) not null,
password varchar(25) not null);
select * from userlist;
在slave中:
nysqk> usr test;
mysql= select * from userlist;
三、基于gtid模式
1.概念:GTID(Global Transaction Identifier)称为全局事务标示符, 是由mysql服务器自动管理的在原始master上提交事务时被创建。 GTID需要在全局的主-备拓扑结构 中保持唯一性,每一个 GTID 代表一个数据库事务。
GTID由两部分组成: source_id和transaction_id
source_id: 用于表示源服务器,用server_uuid来表示
transaction_id: 则是根据在源服务器上第几个提交的事务来确定。 transaction_id 是一个从 1 开始的自增计数,表示在这个主库上执行的第 n 个事务。 MySQL 会保证事务与 GTID 之间的 1 : 1 映射。
工作原理:前面在slave端配置,进行change master to操作时, 使用的是日志号(指定position),当master端的服务down掉了, 就会在slave端选择一个日志号与原来的master最接 近的作为master, 但是,在另一个slave上,并没有指定新的master的信息, 因此还要手动去指定,而使用gtid的话,slave通过寻找 next的值, 并不用指定master的二进制日志文件和日志号,所以使用gtid更能保证数据的完整性。
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。
在master:中
vim /etc/my.cnf
gtid_mode=ON ##开启gtid模式
enforce-gtid-consistency=true
/etc/init.d/mysqld restart ###重启mysql
在slave中:
vim /etc/my.cnf ##开启gtid模式
gtid_mode=ON
enforce-gtid-consistency=true
/etc/init.d/mysqld restart
mysql -p
mysql> stop slave;
mysql>change master to master_host='172.25.45.1',master_user='westos',master_password='SHIjin_?',MASTER_AUTO_POSITION=1;
mysql> start slave;
mysql> show slave status\G;
测试
在master中:
mysql> use test;
mysql> show tables;
mysql> delete from userlist where username='user3';
在slave中:
mysql> use test;
mysql> select * from userlist;
####如果出现i/o线程:connection状态。可能原因是执行change命令时密码错误
四、半同步复制配置
(一)master----->slave
MySQL默认的复制即是异步的,主库在执行完客户端提交的事务后会立即将结果返给给客户端,并不关心从库是否已经接收并处理,这样就会有一个问题,主如果crash掉了,此时主上已经提交的事务可能并没有传到从上,如果此时,强行将从提升为主,可能导致新主上的数据不完整。
全同步复制指当主库执行完一个事务,所有的从库都执行了该事务才返回给客户端。因为需要等待所有从库执行完该事务才能返回,所以全同步复制的性能必然会收到严重的影响。
介于异步复制和全同步复制之间,主库在执行完客户端提交的事务后不是立刻返回给客户端,而是等待至少一个从库接收到并写到relay log中才返回给客户端。相对于异步复制,半同步复制提高了数据的安全性,同时它也造成了一定程度的延迟,这个延迟最少是一个TCP/IP往返的时间。所以,半同步复制最好在低延时的网络中使用。
注意:半同步复制模式必须在主服务器和从服务器端同时开启,否则主服务器默认使用异步复制模式。
半同步复制与异步复制的切换:
半同步复制的工作原理就是当slave从库IO_Thread线程将binlog日志接收完毕之后,要给master主库一个确认,如果rpl_semi_sync_master_timeout=10000 (10秒)超过10秒未收到slave从库的接受确认信号,那么就会自动切换为传统的异步复制模式。
在master中:
mysql> INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
mysql> set global rpl_semi_sync_master_enabled=1;
mysql> show variables like '%semi_sync%';
从节点(slave):
mysql> INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
mysql> set global rpl_semi_sync_slave_enabled=1;
mysql> stop slave io_thread;
mysql> start slave io_thread;
mysql> show global variables like '%semi%';
插入检测:
在master中:
mysql> use test;
mysql> insert into userlist values ('user3','123');
mysql> show status like '%semi_sync%';
Rpl_semi_sync_master_yes_tx ##使用半同步成功的次数,数据一致性性能提高
Rpl_semi_sync_master_no_tx####使用半同步失败的次数,10s后没有得到反馈信息,会转为异步复制
将slave的半同步关掉,进行插入测试:
在slave中:
mysql> set global rpl_semi_sync_slave_enabled=OFF; ###将半同步设置为关闭
mysql> stop slave io_thread;
mysql> start slave io_thread;
mysql> show global variables like '%semi%';
在master中:
当把从机的I/O线程关闭后,主数据库在进行对复制数据库的库进行更改时,在进行操作会等待10秒,10s后没有得到反馈信息,会转为异步复制增加了一次半同步传输的失败次数。
mysql> insert into userlist values ('user4','666');
Query OK, 1 row affected (10.31 sec) #本次插入花费了十秒,因为异步复制有十秒等待slave发送ack的时间.
mysql> show global status like '%semi%';
(二)master---->slave(master)----->slave
实验环境:server1:172.25.45.1和server2连接的master端
server2:172.25.45.2相对于server1是slave端相当于server3是master端
server3;172.25.45.3和server2连接的slave端
保持上一步中server1master的设置
1.保持server1中上一步的设置 然后对数据库test进行备份并复制到server3中 因为主从复制需要各个端的数据保持一致
mysqldump -p test < test.sql ##对server1中数据库中操作的数据备份 备份文件为test.sql
此处warning提示备份文件中包含gitd的相关配置信息
scp test.sql root@172.25.45.3:/root ##将备份数据复制到server3中
2.server2中:
vim /etc/my.cnf
server-id=2
log-bin=mysql-bin
log-slave-updates=ON
gtid_mode=ON
enforce-gtid-consistency=true
slave-parallel-type=LOGICAL_CLOCK
slave-parallel-workers=16
master_info_repository=TABLE
relay_log_info_repository=TABLE
relay_log_recovery=ON
/etc/init.d/mysqld restart
mysql -p
grant replication slave on *.* to westos@'%' identified by 'SHIjin;1'; ##给server2master授权
在server3中测试: mysql -h 172.25.45.2 -u westos -p(提前安装好相关包并且开启mysqld服务)
3.sevrer3中执行上个实验中只充当slave的server2一样的操作:
yum install -y mysql-community-client-5.7.17-1.el6.x86_64.rpm
mysql-community-common-5.7.17-1.el6.x86_64.rpm
mysql-community-libs-5.7.17-1.el6.x86_64.rpm
mysql-community-libs-compat-5.7.17-1.el6.x86_64.rpm
mysql-community-server-5.7.17-1.el6.x86_64.rpm
/etc/init.d/mysqld start
vim /etc//my.cnf
/etc/init.d/mysqld restart
然后对进行数据库初始化:
grep password /var/log/mysql.log
mysql_secure_installation(第一个enter其余Y)
mysql -p
show databases; #此时可以看到server1上的数据库
mysqladmin -p create test ##在server3中创建和server1一样的数据库名
mysql -p test < test.sql ##将test.sql中备份的数据导入test中
mysql -p
4.在server2上:
INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
show plugins;
set global rpl_semi_sync_master_enabled=1;###重启mysqld服务之后需要重新加此参数或者直接将此参数加如/etc/my.cnf中
show slave status\G;
5在sevrer3中:
mysql -p;
use mysql;
show tables;
select * from gtid_executed; ###3表示gtid使用3次
change master to master_host='172.25.45.2',master_user='westos',master_password='SHIjin_?1',master_auto_position=1;
##执行change命令时需要提前关闭slave : stop slave 操作完成之后需要开启
start slave;
show slave status/G;
6.在sevrer1中做插入测试:
use test;
insert into userlist values ('user4','123');
在server2中:
show status like '%rpl%' ##可以看到两个插件都是关闭状态
set global rpl_semi_sync_master_enabled=1 ;
set global rpl_semi_sync_slave_enabled=1; ##这两个参数在mysqld服务重启之后都会消失需要重新设定
stop slave io_thread;
start slave io_thread;
show status like '%rpl%'
在server3中安装插件并开启:
INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
set global rpl_semi_sync_slave_enabled=1;
stop slave io_thread;
start slave io_thread;
server2中重新开启
set global rpl_semi_sync_master_enabled=1 ;参数
show status like '%rpl%'
插入测试:
在server1中:
insert into userlist values ('user5','123');
在server2中:rpl_semi_sync_master_yes_tx=1表示matser成功连接一次
在server3中:select * from userlist 可以看到数据同步过来了
五.基于组提交的并行复制
并发复制是数据库级别的,这意味着一个SQL线程可以处理一个数据库的连续事务,而不用等待其它数据库完成。这个版本的并发复制,可以理解成一个数据库一个SQL线程
在slave(server2)中:
vim /etc/my.conf
slave-parallel-type=LOGICAL_CLOCK 基于组提交的并行用户
slave-parallel-workers=16 开启16个work:单线程变成多线程(前两个必须加入,后面为优化)
master_info_repository=TABLE 优化选项,默认以文件存储,记录master信息,用表来记录,更新速度更快
relay_log_info_repository=TABLE 读日志信息,用表来记录(原来是刷在磁盘里)
relay_log_recovery=ON 激活recovery:读取master二进制日志,如果损坏,直接丢弃然后重新读取
mysql -p
use mysql;
show tables;
最终结果:slave进程查看(多个线程在等待主线程的调用)
show peocesslist;