一、相关概念介绍:
1、GTID简介:
GTID:Global Transaction ID,全局事务ID,是一个已提交事务的编号,并且是一个全局唯一的编号。MySQL 5.6版本之后在主从复制类型上新增了GTID复制。通过GTID保证了每个在master节点上提交的事务在集群中有一个唯一的ID,这种方式强化了数据库的主从一致性、故障恢复及容错能力。
2、GTID工作原理:
GTID用于在binlog中唯一标识一个事务。当事务提交时,MySQL在写binlog时,会先写一个特殊的binlog event,类型为GTID_Event,指定下一个事务的GTID,然后再写事务的binlog。主从同步时GTID_Event和事务的binlog都会传递到slave节点,slave节点在执行时也用同样的GTID写binlog,这样主从同步后,就可通过GTID确定slave节点同步到的位置了。GTID使用master_auto_position=1代替了基于master_log_file和master_log_pos的主从复制构建方式。
3、GTID组成:GTID=server_uuid:transaction_id
(1)server_uuid:MySQL实例的唯一标识,每台主机的server_uuid都不同(128位),保存在数据目录下的auto.cnf文件中。MySQL第一次启动时创建auto.cnf文件,并生成server_uuid,之后MySQL再次启动时不会重复生成server_uuid,而是使用auto.cnf中的server_uuid。
(2)transaction_id:事务提交时由系统顺序分配的一个不会重复的序列号,代表了该实例上已经提交的事务数量,一般来说随着事务提交递增。
备注:使用server_uuid:transaction_id共同组成一个GTID的好处是,由于server_uuid唯一,即使一个集群内多个节点同时写入,也不会造成GTID冲突。
4、GTID使用限制:
(1)不支持create table ... select语句
(2)不支持针对临时表的操作,即create | drop temporary table
(3)不支持非事务存储引擎(如:MyISAM)
(4)不支持sql_slave_skip_counter
5、Keepalived简介:
Keepalived是VRRP协议的软件实现,原生设计是为了高可用IPVS服务,可以实现如下功能:
(1)基于VRRP协议完成地址流动
(2)为VIP地址所在的IPVS集群节点生成IPVS规则(在配置文件中预先定义)
(3)为IPVS集群的各RS做健康状态检测
(4)基于脚本调用接口,通过执行脚本完成脚本中定义的功能,进而影响集群事务
Keepalived官网:https://www.keepalived.org/
6、Keepalived架构图:
当Keepalived启动后,会生成WatchDog、Checkers和VRRP三个工作进程:
(1)WatchDog:负责监控Checkers和VRRP进程
(2)Checkers:负责检测主机健康状态
(3)VRRP:负责当master节点上的服务不可用时,可通过VRRP将其切换到backup节点上
7、VRRP协议简介:
VRRP:Virtual Router Redundancy Protocol,虚拟路由冗余协议。VRRP是一种路由容错协议,也可称为备份路由协议。一个局域网内的所有主机都设置缺省路由,当网内主机发出的目的地址不在本网段时,报文将被通过缺省路由发往外部路由器,从而实现了主机与外部网络的通信。当缺省路由器down掉(即端口关闭)后,内部主机将无法与外部通信,如果路由器设置了VRRP,虚拟路由将启用备份路由器,从而实现全网通信。
8、VRRP相关术语简介:
(1)虚拟路由器:由一个master路由器和多个backup路由器组成,主机将虚拟路由器当作默认网关
(2)VRID:虚拟路由器标识,有相同VRID的一组路由器构成一个虚拟路由器,取值范围为0~255
(3)master路由器:虚拟路由器中承担报文转发任务的路由器
(4)backup路由器:master路由器出现故障时,能代替master路由器工作的路由器
(5)虚拟IP地址:虚拟路由器的IP地址,一个虚拟路由器可以拥有一个或多个IP地址
(6)虚拟MAC地址:一个虚拟路由器拥有一个虚拟MAC地址,虚拟MAC地址的格式为00-00-5E-00-01-{VRID},通常情况下,虚拟路由器回应ARP请求使用的是虚拟MAC地址,只有虚拟路由器做特殊配置时,才回应接口的真实MAC地址
(7)优先级:VRRP根据优先级来确定虚拟路由器中每台路由器的地位,取值范围为0~255,数值越小表示优先级越低,数值越大表示优先级越高,当数值为0时,表示当前master节点放弃持有VIP,当数值为255时,表示当前master节点的优先级最高且已持有VIP,所以VRRP的优先级可选取值范围为1~254
(8)非抢占模式:如果backup路由器工作在非抢占模式下,则只要master路由器没有出现故障,backup路由器即使随后被配置了更高的优先级也不会成为master路由器
(9)抢占模式:如果backup路由器工作在抢占模式下,当它收到VRRP报文后,会将自己的优先级与通告报文中的优先级进行比较,如果自己的优先级比当前的master路由器的优先级高,就会主动抢占成为master路由器,否则将保持backup状态
9、VRRP工作流程:
(1)虚拟路由器中的路由器根据优先级选举出master,master路由器通过发送免费ARP报文,将自己的虚拟MAC地址通知给与它连接的设备或主机,从而承担报文转发任务;
(2)master路由器周期性发送VRRP报文,以公布其配置信息(优先级等)和工作状态;
(3)如果master路由器出现故障,虚拟路由器中的backup路由器将根据优先级重新选举出新的master;
(4)虚拟路由器状态切换时,master路由器由一台设备切换为另一台设备,新的master路由器只是简单地发送一个携带虚拟路由器的MAC地址和虚拟IP地址信息的免费ARP报文,这样就可以更新与它连接的主机或设备中的ARP相关信息。网络中的主机感知不到master路由器已经切换为另一台设备。
备注:backup路由器的优先级高于master路由器时,由backup路由器的工作模式(抢占模式和非抢占模式)决定是否重新选举master
二、准备工作(如未特殊说明,在两个节点中分别执行如下操作):
1、演示环境:
IP |
操作系统 |
主机名 |
角色 |
软件包版本 |
安装方式 |
192.168.1.145 |
CentOS 7.6 x86_64 |
node1 |
master |
Percona Server:5.7.26-29-log Keepalived:1.3.5-8 |
yum |
192.168.1.146 |
CentOS 7.6 x86_64 |
node2 |
backup |
Percona Server:5.7.26-29-log Keepalived:1.3.5-8 |
yum |
备注:VIP为192.168.1.130
2、集群架构:
3、关闭SELinux和firewalld
4、配置epel源
5、配置percona源:
# yum -y install https://repo.percona.com/yum/percona-release-latest.noarch.rpm
# yum repolist
# yum list | grep -i percona
6、配置节点时间同步
7、配置主机名
8、配置/etc/hosts文件:
# vim /etc/hosts
192.168.1.145 node1
192.168.1.146 node2
三、安装配置Percona Server,实现GTID双主复制(如未特殊说明,在两个节点中分别执行如下操作):
1、安装Percona Server:# yum -y install Percona-Server-server-57
2、修改MySQL配置文件:
# mv /etc/my.cnf /etc/my.cnf.bak
# update-alternatives --install /etc/my.cnf my.cnf "/etc/percona-server.cnf" 200
# vim /etc/percona-server.conf.d/mysqld.cnf
master节点:
[mysqld]
port=3306
socket=/var/lib/mysql/mysql.sock
datadir=/var/lib/mysql
pid-file=/var/run/mysqld/mysqld.pid
log-error=/var/log/mysqld.log
lower_case_table_names=1
character_set_server=utf8mb4
collation_server=utf8mb4_general_ci
innodb_file_per_table=1
skip_name_resolve=1
slow_query_log=1
slow_query_log_file=mysql-slow.log
symbolic-links=0
explicit_defaults_for_timestamp=1
log_bin=mysql-bin
log_bin_index=mysql-bin.index
relay_log=relay-log
relay_log_index=relay-log.index
sync_binlog=1
innodb_flush_log_at_trx_commit=1
binlog_format=row
gtid_mode=on
enforce_gtid_consistency=on
server_id=1
备注:
(1)backup节点的server_id=2
(2)从MySQL 5.7版本开始,gtid_mode支持动态修改,可取值为:
a、off:不支持GTID事务,生成的是匿名事务,slave节点也只能应用匿名事务
b、off_permissive:生成的是匿名事务,slave节点可以应用匿名事务和GTID事务
c、on_permissive:生成的是GTID事务,slave节点可以应用匿名事务和GTID事务(此步骤操作完成后,master节点的二进制日志就会变成GTID模式)
d、on:支持GTID事务,生成的是GTID事务,slave节点也只能应用GTID事务
注意:在生产环境中,可能有把传统复制改为GTID复制模式的需求,gtid_mode虽然支持动态修改,但不支持跳跃式修改,比如从on_permissive修改为off是不可以的
(3)enforce_gtid_consistency主要用于不让违反GTID的操作执行,可取值为:
a、off:允许所有操作
b、on:不允许有违反GTID的操作,且报错
c、warn:MySQL 5.7版本新增,允许所有操作,但是违反GTID的操作会提示警告
(4)MySQL 5.6版本中使用GTID复制模式,必须要开启参数log_slave_updates=1,但在MySQL 5.7版本中使用gtid_executed系统表记录已经执行的GTID集合信息,所以就不用开启参数log_slave_updates=1,开启的意义是把relay log中的日志内容再次记录到slave节点的本地binlog中
3、初始化MySQL数据:# mysqld --initialize --user=mysql
备注:确保初始化前/var/lib/mysql目录为空,初始化完成后会在此目录中生成各类文件
4、启动MySQL服务:
# systemctl start mysqld.service
# ss -tunlp | grep mysqld
# systemctl enable mysqld.service
# systemctl status mysqld.service
5、查看root@localhost用户的初始密码:# grep password /var/log/mysqld.log
6、配置MySQL安全向导:# mysql_secure_installation
7、创建具有复制权限的用户:
master节点:
# mysql -uroot -p
mysql> create user 'repluser1'@'192.168.1.%' identified by '123456';
mysql> grant replication slave on *.* to 'repluser1'@'192.168.1.%';
mysql> flush privileges;
mysql> show global variables like 'server_uuid';
备注:
(1)backup节点创建的复制用户为[email protected].%,不能与master节点中的用户重名
(2)内容和/var/lib/mysql/auto.cnf文件中server-uuid的值一致
8、backup节点使用具有复制权限的用户repluser1连接至master节点,并启动复制线程:
mysql> change master to master_host='192.168.1.145',master_user='repluser1',master_password='123456',master_port=3306,master_auto_position=1;
mysql> start slave;
备注:
(1)start slave等同于分别执行start slave io_thread和start slave sql_thread
(2)stop slave表示停止主从复制线程
(3)重启slave节点所在的主机,复制线程会自动启动
mysql> show slave status\G
备注:
(1)只有当Slave_IO_Running和Slave_SQL_Running的值都为Yes时,复制线程才算启动成功
(2)Seconds_Behind_master的值为0,说明backup节点没有落后于master节点
(3)复制时的详细信息记录在backup节点的错误日志/var/log/mysqld.log中
(4)backup节点start slave时,会计算show slave status中Retrieved_Gtid_Set和Executed_Gtid_Set的并集,然后将此GTID并集发送给master节点。master节点会使用backup节点请求的GTID集合和master节点自身的gtid_executed比较,把backup节点GTID集合里缺失的事务全部发送给backup节点。如果backup节点缺失的GTID已经被master节点清除,则backup节点会提示1236错误,I/O线程中断。
9、master节点使用具有复制权限的用户repluser2连接至backup节点,并启动复制线程:
mysql> change master to master_host='192.168.1.146',master_user='repluser2',master_password='123456',master_port=3306,master_auto_position=1;
mysql> start slave;
mysql> show slave status\G
10、查看GTID相关信息:
mysql> show master status\G
master节点:
backup节点:
mysql> show slave hosts;
master节点:
backup节点:
mysql> show slave status\G
mysql> show global variables like '%gtid%';
master节点:
backup节点:
备注:
(1)gtid_executed:当前实例上已经执行过的GTID集合,实际上包含了所有记录到binlog中的事务。如果set sql_log_bin=0,执行的事务不会生成binlog事件,也不会记录到gtid_executed中。执行reset master可以将变量@@global.gtid_executed清空。
(2)gtid_owned:当前实例正在执行中的GTID,以及对应的线程ID
(3)gtid_purged:记录当前实例执行过,但已被清除的GTID集合。gtid_purged是gtid_executed的子集。只有gtid_executed为空时才能手动设置gtid_purged变量,此时会将gtid_executed更新为和gtid_purged相同的值。
mysql> show variables like '%gtid%';
master节点:
backup节点:
备注:gtid_next,session会话级别的变量,如何产生下一个GTID,可取值为
(1)automatic:默认取值,在每次事务提交时自动生成新的GTID,它从当前已执行的GTID集合(即gtid_executed)中,找一个大于0的、未使用的transaction_id最小值作为下个事务的GTID,同时在binlog的实际更新事务事件前插入一条set gtid_next事件,所以即使是同一个server_uuid,也不能通过transaction_id的大小来判断事务的顺序。
(2)anonymous:执行事务不会产生GTID
(3)显示指定GTID:可以指定任意合法的GTID,但不能是当前gtid_executed中已经包含的GTID
mysql> show processlist;
master节点:
backup节点:
11、master节点创建测试数据:
mysql> create database db;
mysql> use db;
mysql> create table tb(id int unsigned auto_increment primary key not null,age int not null);
mysql> desc tb;
mysql> insert into tb(age) values(35),(40);
mysql> select * from tb;
12、backup节点查看测试数据:
mysql> show databases like 'db';
mysql> select * from db.tb;
13、backup节点创建测试数据:
mysql> insert into db.tb(age) values(60),(80);
mysql> select * from db.tb;
14、master节点查看测试数据:
mysql> select * from db.tb;
四、安装配置Keepalived,实现MySQL高可用(如未特殊说明,在两个节点中分别执行如下操作):
1、安装Keepalived:# yum -y install keepalived
2、定义检测MySQL服务的脚本:
# vim /etc/keepalived/chk_mysqld.sh
#!/bin/bash
n=$(ps -C mysqld --no-headers | wc -l)
if [ $n -eq 0 ]; then
systemctl stop keepalived.service
fi
# chmod +x /etc/keepalived/chk_mysqld.sh
# bash -n /etc/keepalived/chk_mysqld.sh
备注:通过Keepalived自带的服务监控功能和自定义脚本实现MySQL故障自动转移
3、master节点配置Keepalived:
# cd /etc/keepalived
# mv keepalived.conf{,.bak}
# openssl rand -base64 7 --> IDDf1j+yfw==
# vim keepalived.conf
global_defs {
notification_email {
root@localhost
}
notification_email_from node1@localhost
smtp_server 127.0.0.1
smtp_connect_timeout 30
router_id node1
vrrp_mcast_group4 224.1.100.88
}
vrrp_script chk_mysqld {
script "/etc/keepalived/chk_mysqld.sh"
interval 10
}
vrrp_instance VI_1 {
state BACKUP
nopreempt
interface ens160
virtual_router_id 50
priority 100
advert_int 5
authentication {
auth_type PASS
auth_pass IDDf1j+yfw==
}
virtual_ipaddress {
192.168.1.130
}
track_script {
chk_mysqld
}
}
备注:常用指令说明
(1)notification_email:收件箱
(2)notification_email_from:发件箱
(3)vrrp_mcast_group4:VRRP多播地址,必须为D类地址,即可用IP范围为224.0.0.0~239.255.255.255
(4)script:自定义检查脚本路径
(5)interval:自定义检查脚本的执行时间间隔,单位为秒
(6)vrrp_instance:配置虚拟路由器实例
(7)state:MASTER或BACKUP,当前节点在此虚拟路由器上的初始状态,只能有一个为MASTER,其余的都应该为BACKUP,此处都需要配置为BACKUP
(8)nopreempt:定义工作模式为非抢占模式,默认为抢占模式
(9)preempt_delay:抢占模式下,节点上线后触发新选举操作的延迟时长,单位为秒
(10)interface:绑定当前虚拟路由器使用的物理接口
(11)virtual_router_id:当前虚拟路由器的唯一标识,取值范围为0~255,两个节点必须一致
(12)priority:当前主机在此虚拟路由器中的优先级,取值范围为0~255
(13)advert_int:VRRP通告心跳信息和优先级信息的时间间隔,单位为秒
(14)auth_type:认证类型
(15)auth_pass:认证密码,两个节点必须一致
(16)virtual_ipaddress:VIP地址
(17)可通过命令# man keepalived.conf查看keepalived.conf配置文件的详细帮助文档
4、backup节点配置Keepalived:
# cd /etc/keepalived
# mv keepalived.conf{,.bak}
# vim keepalived.conf
global_defs {
notification_email {
root@localhost
}
notification_email_from node2@localhost
smtp_server 127.0.0.1
smtp_connect_timeout 30
router_id node2
vrrp_mcast_group4 224.1.100.88
}
vrrp_script chk_mysqld {
script "/etc/keepalived/chk_mysqld.sh"
interval 10
}
vrrp_instance VI_1 {
state BACKUP
nopreempt
interface ens160
virtual_router_id 50
priority 98
advert_int 5
authentication {
auth_type PASS
auth_pass IDDf1j+yfw==
}
virtual_ipaddress {
192.168.1.130
}
track_script {
chk_mysqld
}
}
备注:master和backup节点配置Keepalived时,要注意两个节点的state都要采用BACKUP状态,而且都是nopreempt非抢占模式,通过优先级决定哪个节点为master节点,避免出现冲突,发生脑裂现象
5、master节点启动Keepalived服务,并查看VIP信息:
# systemctl start keepalived.service
# systemctl enable keepalived.service
# systemctl status keepalived.service
# tail -f /var/log/messages
备注:从Keepalived启动完成之后的日志中可以得出,VRRP_Instance(VI_1)首先变成BACKUP状态,由于192.168.1.145主机上的优先级高,状态会从BACKUP升级为MASTER,且chk_mysqld脚本执行成功,VIP已经绑定在master节点的ens160网卡上
# ip a l
6、backup节点启动Keepalived服务:
# systemctl start keepalived.service
# systemctl enable keepalived.service
# systemctl status keepalived.service
# tail -f /var/log/messages
备注:从Keepalived启动完成之后的日志中可以得出,VRRP_Instance(VI_1)变成BACKUP状态,时刻准备接管master节点上的MySQL服务,且chk_mysqld脚本执行成功,但并没有绑定VIP
# ip a l
7、测试使用VIP连接master节点:
(1)在任意一台主机上安装MySQL客户端(此处为192.168.1.144):# yum -y install mariadb
(2)在master或backup任意一个节点中创建登录用户[email protected].%,并赋予权限:
mysql> create user 'root'@'192.168.1.%' identified by '123456';
mysql> grant all on *.* to 'root'@'192.168.1.%';
mysql> flush privileges;
(3)在192.168.1.144主机上使用VIP连接master节点,并使用status命令查看当前数据库状态:
# mysql -uroot -p -h192.168.1.130
8、测试高可用:
(1)master节点模拟MySQL服务宕机:# systemctl stop mysqld.service
(2)master节点查看Keepalived服务、日志及VIP信息:
# systemctl status keepalived.service # tail -f /var/log/messages # ip a l
备注:master节点已经自动停止Keepalived服务,且VIP没有绑定在master节点的ens160网卡上
(3)backup节点查看Keepalived服务、日志及VIP信息:
# systemctl status keepalived.service # tail -f /var/log/messages # ip a l
备注:backup节点的Keepalived已经变成MASTER状态,且VIP漂移至backup节点的ens160网卡上
(4)在192.168.1.144主机上使用VIP连接master节点,并使用status命令查看当前数据库状态:
# mysql -uroot -p -h192.168.1.130
备注:客户端没有受到任何影响,依旧可以使用VIP连接已经变成MASTER状态的backup节点
(5)master节点启动MySQL服务:# systemctl start mysqld.service
(6)master节点启动Keepalived服务:# systemctl start keepalived.service
备注:master节点的Keepalived已经变成BACKUP状态,且chk_mysqld脚本执行成功,但由于是非抢占模式,所以VIP依旧绑定在backup节点的ens160网卡上