MHA高可用
一、MHA简介
MHA 是Perl语言写的,开源的MYSQL故障切换方案;全称:Master High Availability,故障切换时间10-30s
MHA(Master HA)是一款开源的 MySQL 的高可用程序,它为 MySQL主从复制架构提供了 automating master failover (自动化主故障转移)功能。
MHA 在监控到 master 节点故障时,会提升其中拥有最新数据的 slave 节点成为新的master 节点,在此期间,MHA 会通过于其它从节点获取额外信息来避免一致性方面的问题。
MHA 还提供了 master 节点的在线切换功能,即按需切换 master/slave 节点。
MHA 是由日本人 yoshinorim(原就职于DeNA现就职于FaceBook)开发的比较成熟的 MySQL 高可用方案。
MHA 能够在30秒内实现故障切换,并能在故障切换中,最大可能的保证数据一致性。目前淘宝也正在开发相似产品 TMHA, 目前已支持一主一从
二、MHA服务
MHA 服务有两种角色:
1》MHA Manager(管理节点)
2》MHA Node(数据节点)
1>#MHA Manager:
通常单独部署在一台独立机器上管理多个 master/slave 集群(组),每master/slave 集群称作一个 application,用来管理统筹整个集群
2>#MHA node:
运行在每台 MySQL 服务器上(master/slave/manager),它通过监控具备解析和清理 logs 功能的脚本来加快故障转移。主要是接收管理节点所发出指令的代理,代理需要运行在每一个 mysql 节点上。简单讲 node 就是用来收集从节点服务器上所生成的 bin-log 。对比打算提升为新的主节点之上的从节点的是否拥有并完成操作,如果没有发给新主节点在本地应用后提升为主节点
由图我们可以看出,每个复制组内部和 Manager 之间都需要ssh实现无密码互连(做免密),只有这样,在 Master 出故障时, Manager 才能顺利的连接进去,实现主从切换功能
1、【MHA提供的工具】
#MHA提供的工具, 其常见的如下:
########################################## Manager节点: #######################################
masterha_check_ssh: #MHA 依赖的 ssh 环境监测工具;
masterha_check_repl:MYSQL #复制环境检测工具;
masterga_manager: #MHA 服务主程序;
masterha_check_status: #MHA 运行状态探测工具;
masterha_master_monitor: #MYSQL master 节点可用性监测工具;
masterha_master_swith:master: #节点切换工具;
masterha_conf_host: #添加或删除配置的节点;
masterha_stop: #关闭 MHA 服务的工具
########################################## Node节点: #######################################
(这些工具通常由MHA Manager的脚本触发,无需人为操作)
save_binary_logs: #保存和复制 master 的二进制日志;
apply_diff_relay_logs: #识别差异的中继日志事件并应用于其他 slave;
purge_relay_logs: #清除中继日志(不会阻塞 SQL 线程);
自定义扩展: secondary_check_script: #通过多条网络路由检测master的可用性;
master_ip_failover_script: #更新application使用的masterip;
report_script: #发送报告;
init_conf_load_script: #加载初始配置参数;
master_ip_online_change_script; #更新master节点ip地址
2、【MHA的工作原理】
MHA工作原理总结为以下几条:(1) 获取从宕机崩溃的 master 保存二进制日志事件(binlog events);
(2) 识别含有最新更新的 slave ;
(3) 将差异的中继日志(relay log)应用到其他 slave ;
(4) 将 master 保存的二进制日志事件(binlog events)应用到要提升为master节点的slave;
(5) 将这 slave 只读模式解除并提升为新 master ,重新部署主从关系;
3、【MHA自动故障切换 】
1)#Manager会每隔3秒钟探测一次MASTER主库;
ping_interval 控制间隔时间;
ping_type 控制探测方式,SELECT(执行SELECT 1)和CONNECT(创建连接/断开连接)
2)# 如果Manager探测到MASTER主库故障、无法访问,Manager会执行下面操作:
1》从其他node发起ssh连接,检查主库是否能够SSH上去;
2》从其他node发起mysql连接,检查MASTER库是否能够登陆;
3)#如果所有Node节点ssh连接、msyql主库连接均连接失败,则开始故障转移
1》找到数据最新的从库(通过对比relay-log,查看show slave status即可)
2》将最新的从库上的新数据同步到其他从库
3》提升一个从库为主库(一般情况提升数据最新的,二般情况提升我们指定的从库为主库)
4》通过原来主库的binlog补全新的主库数据
5》其他从库以新的主库为主做主从复制
详情
三、MHA的优点总结
1》自动的故障检测与转移,通常在10-30秒以内;
2》MHA还提供在线主库切换的功能,能够安全地切换当前运行的主库到一个新的主库中(通过将从库提升为主库),大概0.5-2秒内即可完成。
3》很好地解决了主库崩溃数据的一致性问题
4》不需要对当前的mysql环境做重大修改
5》不需要在现有的复制框架中添加额外的服务器,仅需要一个manager节点,而一个Manager能管理多套复制,所以能大大地节约服务器的数量;
6》性能优秀,可以工作在半同步和异步复制框架,支持gtid,当监控mysql状态时,仅需要每隔N秒向master发送ping包(默认3秒),所以对性能无影响。你可以理解为MHA的性能和简单的主从复制框架性能一样。
7》只要replication支持的存储引擎都支持MHA,不会局限于innodb
8》对于一般的keepalived高可用,当vip在一台机器上的时候,另一台机器是闲置的,而MHA中并无闲置主机
五、GTID主从复制
MHA可以与半同步复制结合起来。如果只有一个slave已经收到了最新的二进制日志,MHA可以将最新的二进制日志应用于其他所有的slave服务器上,因此可以保证所有节点的数据一致性,或者采用GTID
1、GTID介绍
GTID (Global Transaction ID全局事务ID)是对于一个已提交事务的编号,并且是一个全局唯一的编号
mysql5.6.2 版本开始新增了一种基于 GTID 的复制方式,用以替代以前传统的复制方式,MySQL5.6.10后逐渐完善,通过 GTID 保证了每个在主库上提交的事务在集群中有一个唯一的ID,这种方式强化了数据库的主备一致性,故障恢复以及容错能力
mysql 5.7版本GTID做了增强,不手工开启也自动维护匿名的GTID信息
GTID不仅对其发起的服务器是唯一的,而且在给定复制设置中的所有服务器都是唯一的,即所有的事务和所有的GTID都是1对1的映射
#GTID实际上是由UUID+TID组成的。
UUID是一个MySQL实例的唯一标识,保存在mysql数据目录下的auto.cnf文件里。
TID代表了该实例上已经提交的事务数量,并且随着事务提交单调递增。
#GTID的具体形式:
3E11FA47-71CA-11E1-9E33-C80AA9429562:23
#GTID分布式ID实践方案,它满足分布ID的两个基本要求:
1)全局唯一性
2)趋势递增
2、GTID主从的原理
#一个GTID的生命周期
1)事务在主库上执行并提交给事务分配一个gtid(由主库的uuid和该服务器上未使用的最小事务序列号),该GTID被写入到binlog中。
2)备库读取relaylog中的gtid,并设置session级别的gtid_next的值,以告诉备库下一个事务必须使用这个值
3)备库检查该gtid是否已经被其使用并记录到他自己的binlog中。slave需要担保之前的事务没有使用这个gtid,也要担保此时已分读取gtid,但未提交的事务也不恩呢过使用这个gtid.
4)由于gtid_next非空,slave不会去生成一个新的gtid,而是使用从主库获得的gtid。这可以保证在一个复制拓扑中的同一个事务gtid不变。由于GTID在全局的唯一性,通过GTID,我们可以在自动切换时对一些复杂的复制拓扑很方便的提升新主库及新备库,例如通过指向特定的GTID来确定新备库复制坐标
#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。
6)在解析过程中会判断是否有主键,如果没有就用二级索引,如果没有就用全部扫描
#GTID架构
同样的GTID不能被执行两次,如果有同样的GTID,会自动被skip掉
slave1:将自己的UUID1:1发送给master,然后接收到了UUID1:2,UUID1:3 event
slave2:将自己的UUID1:1,UUID1:2发送给master,然后接收到了UUID1:3事件
3、GTID的部署主从复制(mysql5.7)
注意:
🔊 主库和从库都要开启binlog
🔊 主库和从库server-id必须不同
🔊 要有主从复制用户
1)################################ 主库:192.168.15.51 ##################################
#配置文件添加修改(server-id不能冲突)
[mysqld]
server-id=51
binlog_format=row
log-bin=mysql-bin
skip-name-resolve # 跳过域名解析(非必须)
gtid-mode=on # 启用gtid类型,否则就是普通的复制架构
enforce-gtid-consistency=true #强制GTID的一致性
log-slave-updates=1 # slave更新是否记入日志(5.6必须的)
relay_log_purge = 0 # 关闭relay_log自动清除功能,保障故障时的数据一致
2)################################ 从库一:192.168.15.52 ##################################
#配置文件添加修改(server-id不能与主库冲突)
[mysqld]
server-id=52
binlog_format=row
log-bin=mysql-bin
skip-name-resolve # 跳过域名解析(非必须)
gtid-mode=on # 启用gtid类型,否则就是普通的复制架构
enforce-gtid-consistency=true #强制GTID的一致性
log-slave-updates=1 # slave更新是否记入日志(5.6必须的)
relay_log_purge = 0 # 关闭relay_log自动清除功能,保障故障时的数据一致
3)################################# 从库一192.168.15.53 ##################################
#配置文件添加修改 (server-id不能于主库冲突)
[mysqld]
server-id=53
binlog_format=row
log-bin=mysql-bin
skip-name-resolve # 跳过域名解析(非必须)
gtid-mode=on # 启用gtid类型,否则就是普通的复制架构
enforce-gtid-consistency=true #强制GTID的一致性
log-slave-updates=1 # slave更新是否记入日志(5.6必须的)
relay_log_purge = 0 # 关闭relay_log自动清除功能,保障故障时的数据一致
4)#创建复制用户(主库)
mysql> GRANT REPLICATION SLAVE ON *.* TO hzl@'%' IDENTIFIED BY 'Hzl@20144'; #创建用户
Query OK, 0 rows affected, 1 warning (1.01 sec)
mysql> flush privileges; #刷新权限
Query OK, 0 rows affected (0.00 sec)
5)#主从复制开启(所有从库)
change master to
master_host='192.168.15.51', #主库节点ip
master_user='hzl', #主库同步的用户
master_password='Hzl@20144',
master_auto_position=1;
6)启动主从复制(所有从库)
mysql> start slave; #启动主从复制模式
Query OK, 0 rows affected (0.00 sec)
mysql> show slave status\G #查看主从复制状态
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.15.51
Master_User: hzl
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000003
Read_Master_Log_Pos: 194
Relay_Log_File: mysql-relay-bin.000003
Relay_Log_Pos: 407
Relay_Master_Log_File: mysql-bin.000003
Slave_IO_Running: Yes #o线程状态
Slave_SQL_Running: Yes #sql转换状态
Replicate_Do_DB:
Replicate_Ignore_DB:
mysql> show variables like '%gtid%'; #查看gtid状态
+----------------------------------+-----------+
| Variable_name | Value |
+----------------------------------+-----------+
| binlog_gtid_simple_recovery | ON |
| enforce_gtid_consistency | ON |
| gtid_executed_compression_period | 1000 |
| gtid_mode | ON |
| gtid_next | AUTOMATIC |
| gtid_owned | |
| gtid_purged | |
| session_track_gtids | OFF |
+----------------------------------+-----------+
8 rows in set (0.03 sec)
4、GTID部署双主+主从复制
1)################################ 新主库:192.168.15.54 ##################################
#配置文件添加修改 (server-id不能冲突)
[mysqld]
server-id=54
binlog_format=row
log-bin=mysql-bin
skip-name-resolve # 跳过域名解析(非必须)
gtid-mode=on # 启用gtid类型,否则就是普通的复制架构
enforce-gtid-consistency=true #强制GTID的一致性
log-slave-updates=1 # slave更新是否记入日志(5.6必须的)
relay_log_purge = 0 # 关闭relay_log自动清除功能,保障故障时的数据一致
2)#在新主机上创建复制用户
mysql> GRANT REPLICATION SLAVE ON *.* TO hzl@'%' IDENTIFIED BY 'Hzl@20144'; #新主库创建用户
Query OK, 0 rows affected, 1 warning (1.01 sec)
mysql> flush privileges; #刷新权限
Query OK, 0 rows affected (0.00 sec)
3)#主从复制开启(新主库执行)
change master to
master_host='192.168.15.51', #主库节点ip
master_user='hzl', #主库同步的用户
master_password='Hzl@20144',
master_auto_position=1;
4)#主从复制开启(旧主库执行)
change master to
master_host='192.168.15.54', #主库节点ip
master_user='hzl', #主库同步的用户
master_password='Hzl@20144',
master_auto_position=1;
5)#双主库都开启slave
mysql> start slave; #启动主从复制模式
Query OK, 0 rows affected (0.00 sec)
6)#查看主从复制状态
mysql> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.15.7
Master_User: hzl
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000001
Read_Master_Log_Pos: 696
Relay_Log_File: localhost-relay-bin.000002
Relay_Log_Pos: 414
Relay_Master_Log_File: mysql-bin.000001
Slave_IO_Running: Yes #io线程状态
Slave_SQL_Running: Yes #sql转换状态
Replicate_Do_DB:
Replicate_Ignore_DB:
7)#取消双主从,删除其中一个就可以
mysql> slave stop; #停止当前slave
mysql>reset slave; #重置slave
mysql>change master to master_user=' ', master_host=' ', master_password=' '; #引号之间空一格,写入一个空的slave信息,相当于注销掉当前slave,取消主库的master状态
5、GTID跳过事务设定
####################################### 传统跳过事务 ##########################################
1)停止slave进程
mysql> STOP SLAVE;
2)设置事务号,执行show slave status\G查看Retrieved_Gtid_Set的值即事务号
在session里设置gtid_next,即跳过这个GTID
mysql> SET GTID_NEXT= '6d257f5b-5e6b-11e8-b668-5254003de1b6:1'
3)设置空事物
mysql> BEGIN; COMMIT;
4)恢复事物号
mysql> SET SESSION GTID_NEXT = AUTOMATIC;
5)启动slave进程
mysql> START SLAVE;
#主从复制遇到了某条sql错误,SQL停了,手动设定参数
stop slave; #停止主从复制
set global sql_slave_skip_counter=1; #跳过执行错误的sql
start slave; #开启主从复制slave
ps :在传统的主从里,counter=1是跳过一条sql,而GTID是基于事务的主从复制,如果跳过就是跳过一整个事务,所以上述方法并不适用于GTID
####################################### GTID跳过事务 ##########################################
#GTID跳过事务方式:
1)#停止slave进程
mysql> STOP SLAVE;
2)#设置事务号,执行show slave status\G查看Retrieved_Gtid_Set的值即事务号,在session里设置gtid_next,即跳过这个GTID
mysql> SET GTID_NEXT= '6d257f5b-5e6b-11e8-b668-5254003de1b6:1'
3)#设置空事物
mysql> BEGIN; COMMIT;
4)#恢复事物号
mysql> SET SESSION GTID_NEXT = AUTOMATIC;
5)#启动slave进程
mysql> START SLAVE;
6、GTID优缺点
GTID相比传统复制的优点(新特性):
1、一个事务对应一个唯一ID,一个GTID在一个服务器上只会执行一次,强化了一致性
2、GTID是用来代替传统复制的方法,GTID复制与普通复制模式的最大不同就是不需要指定二进文件名和位置,直接自动查找
3、GTID会开启多个SQL线程,每一个库,开启一个SQL线程
4、支持延时复制
GTID的限制:
1、不支持非事务引擎
2、不支持create table t1(…) select * from t2; 语句复制(主库直接报错)—>原理:( 会生成两个sql,一个是DDL创建表SQL,一个是insert into 插入数据的sql,由于DDL会导致自动提交,所以这个sql至少需要两个GTID,但是GTID模式下,只能给这个sql生成一个GTID )
3、不允许一个SQL同时更新一个事务引擎表和非事务引擎表
4、在一个复制组中,必须要求统一开启GTID或者是关闭GTID
5、开启GTID需要重启(5.7除外)
6、开启GTID后,就不再使用原来的传统复制方式
7、对于create temporary table 和 drop temporary table语句不支持
8、不支持sql_slave_skip_counter
9、mysqldump 备份起来很麻烦,需要额外加参数 --set-gtid=on
六、MHA部署
1、MHA环境准备
机器名称 | IP地址 | 角色 | 备注 |
---|---|---|---|
manager | 192.168.15.51 | Manager控制器 | 用于监控管理 |
master | 192.168.15.52 | 主数据库服务器 | 开启binlog、relay-log,关闭relay_log_purge |
slave1 | 192.168.15.53 | 从1数据库服务器 | 开启binlog、relay-log,关闭relay_log_purge、设置read_only=1 |
slave2 | 192.168.15.54 | 从2数据库服务器 | 开启binlog、relay-log,关闭relay_log_purge、设置read_only=1 |
GTID的一主两从复制,在做主从之前,要保证主从数据的一致性:(方式同上所示)
- 所有数据库服务器都需要开启binlog日志
- 所有数据库都需要有主从复制用户(但我们之前在主库上执行过下述命令,从库已经同步过去了,所以不必重复创建)
################################# (MHA主从复制用户创建)#####################################
用户创建:grant all on *.* to 'hzl'@'%' identified by 'Hzl@20144';
刷新权限:flush privileges;
################################# (MHA的管理用户创建)#####################################
1)#在主库上执行即可,从库会同步过去
mysql> grant all on *.* to 'mhaadmin'@'%' identified by 'Hzl@20144';
mysql> flush privileges;
################################## (开启中继日志及binlog)####################################
MHA 对 MYSQL 复制环境有特殊要求,例如各节点都要开启二进制日志及中继日志,各个“slave节点”必须显式启用3其`read-only`属性,并关闭`relay_log_purge`功能等
1》#在从库上进行操作
#设置只读,不要添加配置文件,因为从库以后可能变成主库
mysql> set global read_only=1;
2》#所有库禁止自动清除relay log (之前配置文件已经添加设置,无需设定)
#关闭MySQL自动清除relaylog的功能 (手动临时设定)
mysql> set global relay_log_purge = 0;
#编辑配置文件
[root@mysql-db02 ~]# vim /etc/my.cnf (配置文件永久修改)
[mysqld]
#禁用自动删除中继日志(relay log)永久生效
relay_log_purge = 0
2、MHA主机之间做免密(必须所有主机之间)
#创建秘钥对
1)#创建ssh-keygen 密钥对
ssh-keygen
2)#跳过交互
ssh-keygen -t dsa -P '' -f ~/.ssh/id_dsa >/dev/null 2>&1
3)#发送公钥(所有主机,包括自己)
#方式一:
ssh-copy-id -i /root/.ssh/id_dsa.pub root@192.168.15.51
ssh-copy-id -i /root/.ssh/id_dsa.pub root@192.168.15.52
ssh-copy-id -i /root/.ssh/id_dsa.pub root@192.168.15.53
ssh-copy-id -i /root/.ssh/id_dsa.pub root@192.168.15.54
#方式二:
使用for循环传输密钥(免交互传输)
yum install sshpass -y #安装软件包
for i in 51 52 53 54;do sshpass -p1 ssh-copy-id -i /root/.ssh/id_rsa.pub root@192.168.15.$i -o StrictHostKeyChecking=no;done
3、MHA依赖软件包安装 (所有主机)
1)#安装yum源
wget http://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
rpm -ivh epel-release-latest-7.noarch.rpm
2)# 安装MHA依赖的perl包(所有主机安装)
yum install -y perl-DBD-MySQL perl-Config-Tiny perl-Log-Dispatch perl-Parallel-ForkManager
3)#安装node包 (所有主机安装)
wget https://qiniu.wsfnk.com/mha4mysql-node-0.58-0.el7.centos.noarch.rpm --no-check-certificate
rpm -ivh mha4mysql-node-0.58-0.el7.centos.noarch.rpm
4)#安装manager包(manager主机安装,192.168.15.51)
wget https://qiniu.wsfnk.com/mha4mysql-manager-0.58-0.el7.centos.noarch.rpm --no-check-certificate
rpm -ivh mha4mysql-manager-0.58-0.el7.centos.noarch.rpm
node 组件安装后会在/usr/local/bin 下面会生成几个脚本(这些工具通常由 MHAManager 的脚本触发,无需人为操作)
manager 组件安装后会在 /usr/local/bin 下面会生成以下几个工具:
4、MHA Manager配置
1)#创建工作目录 (Manager主机)
mkdir -p /service/mha/
mkdir /service/mha/app1
2) #修改配置文件
vim /service/mha/app1.cnf #为什么设置为app1,因为需要管理很多套集群,后面的可以叫app2
[server default]
#日志存放路径
manager_log=/service/mha/manager.log
#定义工作目录位置
manager_workdir=/service/mha/app1
#binlog存放目录(如果三台数据库机器部署的路径不一样,可以将配置写到相应的server下面)
#master_binlog_dir=/usr/local/mysql/data
#设置ssh的登录用户名
ssh_user=root
#如果端口修改不是22的话,需要加参数,不建议改ssh端口
#否则后续如负责VIP漂移的perl脚本也都得改,很麻烦
ssh_port=22
#管理用户
user=mhaadmin
password=Hzl@20144
#复制用户
repl_user=hzl
repl_password=Hzl@20144
#检测主库心跳的间隔时间
ping_interval=1
[server1]
#指定自己的binlog日志存放目录
master_binlog_dir=/var/lib/mysql
hostname=192.168.15.51
port=3306
[server2]
#暂时注释掉,先不使用
#candidate_master=1
#check_repl_delay=0
master_binlog_dir=/var/lib/mysql
hostname=192.168.15.53
port=3306
[server3]
master_binlog_dir=/var/lib/mysql
hostname=192.168.15.54
port=3306
##################################################################################
ps : 设置了以下两个参数,则该从库成为候选主库,优先级最高
#不管怎样都切到优先级高的主机,一般在主机性能差异的时候用
candidate_master=1
# 不管优先级高的备选库,数据延时多久都要往那切
check_repl_delay=0
ps : 上述两个参数详解:
# 设置参数candidate_master=1后,则判断该主机为为候选master,发生主从切换以后将会将此从库提升为主库,即使这个主库不是集群中事件最新的slave
# 默认情况下如果一个slave落后master 100M的relay logs的话,MHA将不会选择该slave作为一个新的master,因为对于这个slave的恢复需要花费很长时间,通过设置check_repl_delay=0,MHA触发切换在选择一个新的master的时候将会忽略复制延时,这个参数对于设置了candidate_master=1的主机非常有用,因为这个候选主在切换的过程中一定是新的master
ps :应该为什么节点设置这俩参数,从而把该节点的优先级调高
(1)#多地多中心,设置本地节点为高权重
(2)#在有半同步复制的环境中,设置半同步复制节点为高权重
(3)#你觉着哪个机器适合做主节点,配置较高的 、性能较好的
5、MHA配置状态检测
#测试免密连接
1)#使用mha命令---(检测ssh免密登录)
masterha_check_ssh --conf=/service/mha/app1.cnf
..........
......
...
Sun Jul 25 23:02:46 2021 - [debug] ok. #表示ok了
Sun Jul 25 23:02:47 2021 - [info] All SSH connection tests passed successfully.
2)#使用mha命令---(检测主从状态)
masterha_check_repl --conf=/service/mha/app1.cnf
......................
.............
......
MySQL Replication Health is OK. #表示ok了
ps : 如果出现问题,可能是反向解析问题,配置文件添加参数:skip-name-resolve
ps : 还有可能是主从状态,mha用户密码的情况
6、MHA启动
#启动命令
nohup masterha_manager --conf=/service/mha/app1.cnf --remove_dead_master_conf --ignore_last_failover < /dev/null > /service/mha/manager.log 2>&1 &
######################################################################################
#命令参数详解:
--remove_dead_master_conf #该参数代表当发生主从切换后,宕机库的配置信息将会从配置文件中移除。
--manger_log #日志存放位置
--ignore_last_failover #在缺省情况下,如果MHA检测到连续发生宕机,且两次宕机间隔不足8小时的话,则不会进行Failover,之所以这样限制是为了避免ping-pong效应。该参数代表忽略上次MHA触发切换产生的文件,默认情况下,MHA发生切换后会在日志目录,也就是上面设置的manager_workdir目录中产生app1.failover.complete文件,下次再次切换的时候如果发现该目录下存在该文件将不允许触发切换,除非在第一次切换后收到删除该文件,为了方便,这里设置为--ignore_last_failover。
#MHA的安全机制:
1》完成一次切换后,会生成一个锁文件在工作目录中
2》下次切换之前,会检测锁文件是否存在
3》如果锁文件存在,8个小时之内不允许第二次切换
7、MHA测试自动切换与恢复
自动切换和手动切换
当主库宕机时,会发生自动切换
模拟被动切换一定要停止数据,不要重启数据库
1)#查看日志
tail -f /service/mha/manager.log
2) #停掉主库master
[root@db01 ~]# systemctl stop mysql
提升数据量最多的为主库
如果数据量一样,根据配置文件里面server的顺序切换
3)#如果把原主库修复,再把提升的主库停止,谁会是主库?
数据量一样的情况下,根据server标签来切换的,标签越小优先级越高
4)#分析日志内容
日志最后有一个sendreport机制,可以发送邮件给我们运维,不过一般不用,我们有zabbix可以帮我们监控
最后执行的时候删除了主库的server信息,他会给他加上注释,然后删除注释的内容
8、 修复MHA故障的主库
#MHA环境修复步骤:
1)#启动宕机的主库
systemctl start mysql
2)#将宕机的库作为从库指向新主库,此时为'192.168.15.53',可以通过查看日志文件确认新主库地址: grep -i 'change master to' /service/mha/manager.log
stop slave;
CHANGE MASTER TO MASTER_HOST='192.168.15.53', MASTER_PORT=3306, MASTER_AUTO_POSITION=1, MASTER_USER='egon', MASTER_PASSWORD='123';
start slave;
3)#如果启动manager时加入了参数--remove_dead_master_conf ,则此处需要将修复后的数据库信息配置到文件中
vim /service/mha/app1.cnf
[server1]
#指定自己的binlog日志存放目录
master_binlog_dir=/var/lib/mysql
hostname=192.168.15.100
port=3306
4)#再次启动MHA(故障迁移一次masterha_manager就结束了,所以故障库修复后需要重新启动)
nohup masterha_manager --conf=/service/mha/app1.cnf --remove_dead_master_conf --ignore_last_failover < /dev/null > /service/mha/manager.log 2>&1 &
5)#检测MHA启动状态
masterha_check_status --conf=/service/mha/app1.cnf
ps : 为了避免MHA切换以后进程退出,官网推荐使用daemon的方式运行
9、主库切换优先级
1)#依据数据量是否最新进行自动切换
1》做好主从
2》在主库上创建表
create database if not exists test;
create table test.t1(id int);
3》在主库运行下述脚本
for i in `seq 1 1000000`
do
mysql -e "insert into test.t1 values($i);"
sleep 1
done
4》将某一台从库的IO线程停止,该从库的数据必然落后了
stop slave io_thread;
5》停止主库查看切换情况
肯定不会选择那个停掉io先从的从库当新主库,但是该从库的io线程会
启动起来,然后指向新主库,并且数据更新到了最新
2)#依据优先级进行切换
1》配置优先级测试
candidate_master=1
check_repl_delay=0
10、配置优先级测试
candidate_master=1
check_repl_delay=0
(1)#VIP漂移的两种方式:
1)通过keepalived的方式,管理虚拟IP的漂移
2)通过MHA自带脚本方式,管理虚拟IP的漂移(推荐)
ps :为了防止脑裂发生,推荐生产环境采用脚本的方式来管理虚拟vip,而不是使用 keepalived来完成
(2)#配置文件中指定脚本路径
[root@mysql-db03 ~]# vim /etc/mha/app1.cnf
[server default]
#指定自动化切换主库后,执行的vip迁移脚本路径
master_ip_failover_script=/service/mha/master_ip_failover
(3)编写脚本:
注:所有数据库网卡名必须一致(主要修改以下几行)
my $vip = ‘192.168.15.250/24’;
my $key = ‘1’;
my $ssh_start_vip = “/sbin/ifconfig eth0: $key $vip”;
my $ssh_stop_vip = “/sbin/ifconfig eth0: $key down”;
vim /service/mha/master_ip_failover
#!/usr/bin/env perl
use strict;
use warnings FATAL => 'all';
use Getopt::Long;
my (
$command, $ssh_user, $orig_master_host,
$orig_master_ip,$orig_master_port, $new_master_host, $new_master_ip,$new_master_port
);
#定义VIP变量
my $vip = '192.168.15.250/24';
my $key = '1';
my $ssh_start_vip = "/sbin/ifconfig eth0:$key $vip";
my $ssh_stop_vip = "/sbin/ifconfig eth0:$key down";
#my $ssh_start_vip = "/usr/sbin/ip addr add $vip/24 brd $brdc dev $ifdev label $ifdev:$key;/usr/sbin/arping -q -A -c 1 -I $ifdev $vip;iptables -F;";
#my $ssh_stop_vip = "/usr/sbin/ip addr del $vip/24 dev $ifdev label $ifdev:$key"
GetOptions(
'command=s' => \$command,
'ssh_user=s' => \$ssh_user,
'orig_master_host=s' => \$orig_master_host,
'orig_master_ip=s' => \$orig_master_ip,
'orig_master_port=i' => \$orig_master_port,
'new_master_host=s' => \$new_master_host,
'new_master_ip=s' => \$new_master_ip,
'new_master_port=i' => \$new_master_port,
);
exit &main();
sub main {
print "\n\nIN SCRIPT TEST====$ssh_stop_vip==$ssh_start_vip===\n\n";
if ( $command eq "stop" || $command eq "stopssh" ) {
my $exit_code = 1;
eval {
print "Disabling the VIP on old master: $orig_master_host \n";
&stop_vip();
$exit_code = 0;
};
if ($@) {
warn "Got Error: $@\n";
exit $exit_code;
}
exit $exit_code;
}
elsif ( $command eq "start" ) {
my $exit_code = 10;
eval {
print "Enabling the VIP - $vip on the new master - $new_master_host \n";
&start_vip();
$exit_code = 0;
};
if ($@) {
warn $@;
exit $exit_code;
}
exit $exit_code;
}
elsif ( $command eq "status" ) {
print "Checking the Status of the script.. OK \n";
exit 0;
}
else {
&usage();
exit 1;
}
}
sub start_vip() {
`ssh $ssh_user\@$new_master_host \" $ssh_start_vip \"`;
}
sub stop_vip() {
return 0 unless ($ssh_user);
`ssh $ssh_user\@$orig_master_host \" $ssh_stop_vip \"`;
}
sub usage {
print
"Usage: master_ip_failover --command=start|stop|stopssh|status --orig_master_host=host --orig_master_ip=ip --orig_master_port=port --new_master_host=host --new_master_ip=ip --new_master_port=port\n";
}
#添加执行权限,否则mha无法启动
chmod +x /service/mha/master_ip_failover
(4)手动绑定vip到主库(假设此时主库为192.168.15.53那台机器)
# ssh到主库所在服务器,然后执行
ifconfig eth0:1 192.168.15.250/24 # 注意与脚本中对应eth0:1
#补充:我们在做keepalived的时候它会帮我们添加VIP,实际上操作就是
ifconfig eth0:1 192.168.15.250/24
切换的时候就是把VIP所在机器
ifconfig eth0:1 down
然后切换到另一台机器去执行
ifconfig eth0:1 192.168.15.250/24
(5)测试vip漂移(测试过程一直保持向vip提交写请求)
# 强调:先执行一下ssh root@192.168.15.250,把yes输入一下,退出后
# 再执行下述脚本
for i in `seq 1 1000000`
do
ssh root@192.168.15.250 "mysql -e 'insert into test.t1 values($i);'"
sleep 1
echo "$i ok"
done
(6)启动MHA(如果已经启动则忽略)
nohup masterha_manager --conf=/service/mha/app1.cnf --remove_dead_master_conf --ignore_last_failover < /dev/null > /service/mha/manager.log 2>&1 &
(7)停止主库,测试ip漂移,验证写操作是否中断
11、手动迁移主库配置vip漂移脚本
(1)【配置文件中指定脚本路径】
vim /service/mha/app1.cnf
[server default]
......
#指定手动切换主库后,执行的vip迁移脚本路径
master_ip_online_change_script="/service/mha/master_online_change"
(2)【编写手动切换主库后对应的vip迁移脚本】
vim /service/mha/master_online_change
#!/bin/bash
source /root/.bash_profile
vip=`echo '192.168.15.250/24'` #设置VIP
key=`echo '1'`
command=`echo "$1" | awk -F = '{print $2}'`
orig_master_host=`echo "$2" | awk -F = '{print $2}'`
new_master_host=`echo "$7" | awk -F = '{print $2}'`
orig_master_ssh_user=`echo "${12}" | awk -F = '{print $2}'`
new_master_ssh_user=`echo "${13}" | awk -F = '{print $2}'`
#要求服务的网卡识别名一样,都为eth0(这里是)
stop_vip=`echo "ssh root@$orig_master_host /usr/sbin/ifconfig eth0:$key down"`
start_vip=`echo "ssh root@$new_master_host /usr/sbin/ifconfig eth0:$key $vip"`
if [ $command = 'stop' ]
then
echo -e "\n\n\n****************************\n"
echo -e "Disabled thi VIP - $vip on old master: $orig_master_host \n"
$stop_vip
if [ $? -eq 0 ]
then
echo "Disabled the VIP successfully"
else
echo "Disabled the VIP failed"
fi
echo -e "***************************\n\n\n"
fi
if [ $command = 'start' -o $command = 'status' ]
then
echo -e "\n\n\n*************************\n"
echo -e "Enabling the VIP - $vip on new master: $new_master_host \n"
$start_vip
if [ $? -eq 0 ]
then
echo "Enabled the VIP successfully"
else
echo "Enabled the VIP failed"
fi
echo -e "***************************\n\n\n"
fi
#添加执行权限,否则mha无法启动
chmod +x /service/mha/master_online_change
(3)手动绑定vip到主库
ifconfig eth0:1 192.168.15.250
(4)手动切换主库验证vip漂移
># 先停掉mha
masterha_stop --conf=/service/mha/app1.cnf
# 将主库切换到192.168.15.52
masterha_master_switch --conf=/service/mha/app1.cnf --master_state=alive --new_master_host=192.168.15.52 --orig_master_is_new_slave --running_updates_limit=10000 --interactive=0
七、binlogserver备份
如果主库断电或者断网,binlog如何保存?可以为MHA配置binlogserver,实时保存binglog
1) 前期准备
准备一台新的mysql实例(与主库板块一致),GTID必须开启。
然后改mysql主机就用于实时拉取主库的binlog,并不与主库同步,只是用来拉取主库的binlog,防止主库突然断电
2) 停止MHA
masterha_stop --conf=/service/mha/app1.cnf
3) 创建binlog存放目录并设置权限
mkdir -p /bak/binlog/
chown -R mysql.mysql /bak/binlog
4)手动执行备份binlog
cd /bak/binlog
# 查看所有从库show slave status\G
mysqlbinlog -R --host=主库ip地址 --user=mhaadmin --password=Hzl@20144 --raw --stop-never mysql-bin.000002 &
# 注意:写成mysql-bin.000002则会从该文件开始拉取一直到最新的
mysqlbinlog -R --host=192.168.15.51 --user=mhaadmin --password=Hzl@20144 --raw --stop-never mysql-bin.000002 &
5)在app1.cnf开启binlogserver功能
[binlog1]
no_master=1
# binlogserver主机的ip地址
hostname=192.168.15.51
# 不能跟当前机器数据库的binlog存放目录一样
master_binlog_dir=/bak/binlog/
6)登录主库验证
mysql> flush logs; -- 看到binlogserver主机上/bak/binlog目录下新增日志
7)再次启动mha
nohup masterha_manager --conf=/service/mha/app1.cnf --remove_dead_master_conf --ignore_last_failover < /dev/null > /service/mha/manager.log 2>&1 &
八 、MHA脚本文件总结
1 查看Node脚本
rpm -ql mha4mysql-node-0.56-0.el6.noarch ,(这些工具通常由MHA Manager的脚本触发,无需人为操作)
2 查看Manager脚本
rpm -ql mha4mysql-manager-0.56-0.el6.noarch
3 实例脚本
九 、常用命令汇总
#1、重置slave
stop slave;
reset slave;
start slave;
#2、查看
SHOW SLAVE STATUS; #查看从库复制状态
SHOW MASTER STATUS; #查看当前binlog位点
SHOW SLAVE HOSTS; #查看从库列表
#3、重做slave指向主库
stop slave;
CHANGE MASTER TO MASTER_HOST='192.168.15.52', MASTER_PORT=3306, MASTER_AUTO_POSITION=1, MASTER_USER='Hzl@20144', MASTER_PASSWORD='Hzl@20144';
start slave;
#4、停止mha
masterha_stop --conf=/service/mha/app1.cnf
#5、查看ssh与主从状态
masterha_check_ssh --conf=/service/mha/app1.cnf
masterha_check_repl --conf=/service/mha/app1.cnf
#6、启动mha
nohup masterha_manager --conf=/service/mha/app1.cnf --remove_dead_master_conf --ignore_last_failover < /dev/null > /service/mha/manager.log 2>&1 &
#7、查看mha状态
masterha_check_status --conf=/service/mha/app1.cnf
#8、修改mha配置文件
cat >> /service/mha/app1.cnf << EOF
[server default]
manager_log=/service/mha/manager.log
manager_workdir=/service/mha/app1
master_ip_failover_script=/service/mha/master_ip_failover
master_ip_online_change_script="/service/mha/master_online_change"
password=Hzl@20144
ping_interval=1
repl_password=Hzl@20144
repl_user=hzl
ssh_port=22
ssh_user=root
user=mhaadmin
[server1]
hostname=192.168.15.52
master_binlog_dir=/var/lib/mysql
port=3306
[server2]
hostname=192.168.15.53
master_binlog_dir=/var/lib/mysql
port=3306
[server3]
hostname=192.168.15.54
master_binlog_dir=/var/lib/mysql
port=3306