一、Mysql的主从复制
1、为什么要做主从复制?
在业务复杂的系统中,有这么一个情景,有一句sql语句需要锁表,导致暂时不能使用读的服务,那么就很影响运行中的业务,使用主从复制,让主库负责写,从库负责读,这样,即使主库出现了锁表的情景,通过读从库也可以保证业务的正常运作。架构的扩展。业务量越来越大,I/O访问频率过高,单机无法满足,此时做多库的存储,降低磁盘I/O访问的频率,提高单个机器的I/O性能。
2、mysql主从复制的原理
当一个从服务器连接主服务器时,它通知主服务器从服务器在日志中读取的最后一次成功更新的位置。从服务器接收从那时起发生的任何更新,然后封锁并等待主服务器通知新的更新。
主从复制的基础是主库记录数据库的所有变更记录到binlog( binary log,主库中保存更新事件日志的二进制文件)。binlog是数据库中保存配置中过期时间内所有修改数据库结构或内容的一个文件。如果过期时间是10d的话,那么就是最近10d的数据库修改记录。
mysql主从复制是一个异步的复制过程,主库发送更新事件到从库,从库读取更新记录,并执行更新记录,使得从库的内容与主库保持一致。
-
在 主库 里,只要有更新事件出现,就会被依次地写入到binlog里面,是之后从库连接到主库时,从主库拉取过来进行复制操作的数据源。
binlog输出线程 每当有从库连接到主库的时候,主库都会创建一个线程然后发送binlog内容到从库。 对于每一个即将发送给从库的sql事件,binlog输出线程会将其锁住。一旦该事件被线程读取完之后,该锁会被释放,即使在该事件完全发送到从库的时候,该锁也会被释放。 -
在 从库 里,当复制开始的时候,从库就会创建两个线程进行处理:
从库I/O线程 当START SLAVE语句在从库开始执行之后,从库启动I/O线程,该线程连接到主库并请求主库发送binlog里面的更新记录到从库上。
从库I/O线程读取主库的binlog输出线程发送的更新并拷贝这些更新到本地文件,其中包括relay log文件。从库的SQL线程 从库启动SQL线程,这个线程读取从库I/O线程写到relay log(中继日志)的更新事件并执行。
可知道,对于每一个主从复制的连接,都有三个线程。拥有多个从库的主库为每一个连接到主库的从库创建一个binlog输出线程,每一个从库都有它自己的I/O线程和SQL线程。 从库通过启动两个独立的线程,使得在进行复制时,从库的读和写进行了分离。因此,即使负责执行的线程运行较慢,负责读取更新语句的线程并不会因此变得缓慢。比如说,如果从库有一段时间没运行了,当它在此启动的时候,尽管它的SQL线程执行比较慢,它的I/O线程可以快速地从主库里读取所有的binlog内容。这样一来,即使从库在SQL线程执行完所有读取到的语句前停止运行了,I/O线程也至少完全读取了所有的内容,并将其安全地备份在从库本地的relay log,随时准备在从库下一次启动的时候执行语句。
3、异步复制
MySQL默认的复制即是异步的,主库在执行完客户端提交的事务后会立即将结果返给给客户端,并不关心从库是否已经接收并处理,这样就会有一个问题,主库如果crash掉了,此时主库上已经提交的事务可能并没有传到从库上,如果此时,强行将从提升为主,可能导致新主库上的数据不完整。
二、基于position的异步复制
实验环境
实验环境
主机名 IP | 服务 |
---|---|
虚拟机server1 172.25.7.1 | 数据库的master节点 |
虚拟机server2 172.25.7.2 | 数据库的slave节点 |
物理机 172.25.7.250 | 测试端 |
1、在server1和server2上,下载mysql的rpm包,解压:
tar xf mysql-5.7.24-1.el7.x86_64.rpm-bundle.tar
2、安装需要的包
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
server2上同样的操作:
3、修改配置文件,开始配置主节点(server1)数据库 vim /etc/my.cnf
在文件末尾写:
log-bin=mysql-bin
server-id=1(每个节点的序号是唯一的)
- 1
- 2
- 3
4、master节点(server1 )的数据库初始化
1)开启服务之后会生成一个临时密码,使用临时密码进行数据库安全初始化,复制密码:cat /var/log/mysqld.log | grep password
2)mysql -uroot -p 粘贴密码,登录成功
3)show databases;发现必须进行初始化
4)安全初始化:mysql_secure_installation
- 安全初始化登陆的时候使用的是临时密码,接下来要自己设置数据库的密码,这个密码必须有特殊字符,英文字母的大小写还有数字
5)使用自己设置的密码登录数据库:mysql -uroot -pWestos123==
5、slave节点(server2 )的数据库初始化
1)vim /etc/my.cnf
2)复制密码:cat /var/log/mysqld.log | grep password
3)安全初始化:mysql_secure_installation
4)使用自己设置的密码登录slave数据库:mysql -uroot -pWestos123==
6、在 master 上,创建并授权用来做复制的用户
在Master的数据库中建立一个备份帐户:每个slave使用标准的MySQL用户名和密码连接master。进行复制操作的用户会授予REPLICATION SLAVE权限。用户名的密码都会存储在文本文件master.info中
mysql> grant replication slave on *.* to repl@'172.25.7.%' identified by 'Westos==123';
## 创建用户,可以使用此用户远程登录数据库;授权为可以复制master节点数据的slave节点
mysql> show plugins;
##查看插件,因为有密码插件,所以密码必须设置为复杂的
mysql> show master status;
##查看master状态
- 1
- 2
- 3
- 4
- 5
- 6
参数 | 解释 |
---|---|
REPLICATION | 表示复制的权限 |
* .* | 表示对所有库的所有表都授权 |
repl | 用户名 |
‘172.25.7.%’ | 授权172.25.7网段的所有数据库节点都可以同步(复制) |
7、在 slave(server2)上配置master信息
mysql> change master to master_host='172.25.7.1',
##在这个slave节点上面设置管理它的master节点主机信息
->master_user='repl',
##用户
->master_password='Westos==123',
##密码
->master_log_file='mysql-bin.000002',
##基于position的主从复制的重要信息
->master_log_pos=861;
##
mysql> start slave; ##开启本节点的slave
mysql> show slave status\G ##查看主从复制状态
##这两个参数是Yes,表示成功 。Slave_IO_Running: Yes Slave_SQL_Running: Yes
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 对于slave节点来说,io线程和sql线程是最重要的两个线程。只有当io线程和sql线程都开启的时候,slave节点才可以正常复制master节点的数据
8、测试主从同步是否生效
- 注意:写操作只能在master节点上做,因为master节点不会去同步slave节点的内容
在master创建新数据
mysql> create database ranran; ##在server2上发现也能看到westos库
mysql> use ranran
mysql> create table usertb (
-> username varchar(10) not null,
-> password varchar(15) not null); ##建表
mysql> desc usertb; ##查看表信息
mysql> insert into usertb values ('user1','123'); ##插入数据
mysql> select * from usertb; ##查看
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
在slave查看select * from ranran.usertb;
三、基于GTID的异步复制
1、 DTID的含义
- Global Transaction Identifier,全局事务标识
- 一个GTID在一个服务器上只执行一次,避免重复执行导致数据混乱或者主从不一致。
- GTID用来代替传统复制方法,不再使用MASTER_LOG_FILE+MASTER_LOG_POS开启复制。而是使用MASTER_AUTO_POSTION=1的方式开始复制。
- 基于gtid的主从复制原理:每个mysql数据库上都有一个唯一uuid,每个事务生成一个id。gtid由上面两者组合: uuid+事务id
2、优势
- 更简单的搭建主从复制。
- 比传统的复制更加安全。在传统的复制里面,当发生故障,需要主从切换,需要找到binlog和pos点,然后将主节点指向新的主节点,相对来说比较麻烦,也容易出错。在MySQL 5.6里面,不用再找binlog和pos点,我们只需要知道主节点的ip,端口,以及账号密码就行,因为复制是自动的,MySQL会通过内部机制GTID自动找点同步。
- GTID是连续的没有空洞的,保证数据的一致性,零丢失
- 主从提升更加简单容易。从服务器连接到主服务器之后,把自己执行过的GTID(Executed_Gtid_Set)<SQL线程> 、获取到的GTID(Retrieved_Gtid_Set)<IO线程>发给主服务器,主服务器把从服务器缺少的GTID及对应的transactions发过去补全即可。当主服务器挂掉的时候,找出同步最成功的那台从服务器,直接把它提升为主即可。如果硬要指定某一台不是最新的从服务器提升为主, 先change到同步最成功的那台从服务器, 等把GTID全部补全了,就可以把它提升为主了
3、GTID工作原理
- 当一个事务在主库端执行并提交时,产生GTID,一同记录到binlog日志中。
- binlog传输到slave,并存储到slave的relaylog后,读取这个GTID的这个值设置gtid_next变量,即告诉Slave,下一个要执行的GTID值。
- sql线程从relay log中获取GTID,然后对比slave端的binlog是否有该GTID。
- 如果有记录,说明该GTID的事务已经执行,slave会忽略。
- 如果没有记录,slave就会执行该GTID事务,并记录该GTID到自身的binlog,在读取执行事务前会先检查其他session持有该GTID,确保不被重复执行。
- 在解析过程中会判断是否有主键,如果没有就用二级索引,如果没有就用全部扫描。
4、基于GTID的主从复制
此实验是基于position的主从复制的基础上做的
1、在server1上,配置主节点
1)修改配置文件加入开启gtid的信息,vim /etc/my.cnf
gtid_mode=ON
enforce-gtid-consistency=true
- 1
- 2
此时登录数据库: mysql -uroot -pWestos123==
mysql>use mysql;
mysql>select * from gtid_executed;
- 1
- 2
发现gtid_executed是空的,
2)在/var/lib/mysql路径下,mysqlbinlog mysql-bin.000002 可以看到之前的全部操作。
3)在/var/lib/mysql路径下 ,cat auto.cnf 查看此节点的uuid
4)重启数据库:systemctl restart mysqld
2、在server2上,配置slave
1)vim /etc/my.cnf,加入:开启gtid的信息
2)systemctl restart mysqld
3)在/var/lib/mysql路径下,cat relay-log.info
4)此时登录数据库: mysql -uroot -pWestos123==
mysql> stop slave; ##先停止复制
mysql> CHANGE MASTER TO ##修改master信息
-> MASTER_HOST = '172.25.7.1',
-> MASTER_USER = 'repl',
-> MASTER_PASSWORD = 'Westos==123',
-> MASTER_AUTO_POSITION = 1; ##启用gtid,它是自动的
mysql> start slave;
mysql> show slave status\G ##查看状态,可以看到下面两个参数是空的
Retrieved_Gtid_Set:
Executed_Gtid_Set:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
3、在server1上插入数据
mysql>use ranran
mysql> insert into usertb values ('user2','123');
mysql> insert into usertb values ('user3','123');
- 1
- 2
- 3
4、在server2上面查看状态和同步的数据
发现这两个参数 Retrieved_Gtid_Set: /Executed_Gtid_Set: 变了,从1位置开始复制的
再查看gtid模式复制的起始和结束位置
此时查看表,即可看到插入内容。