MHA介绍及组成

MHA介绍

​ MHA能够在较短的时间内实现自动故障检测和故障转移,通常在10-30秒以内;在复制框架中,MHA能够很好地解决复制过程中的数据一致性问题,由于不需要在现有的replication中添加额外的服务器,仅需要一个manager节点,而一个Manager能管理多套复制,所以能大大地节约服务器的数量;另外,安装简单,无性能损耗,以及不需要修改现有的复制部署也是它的优势之处。

MHA还提供在线主库切换的功能,能够安全地切换当前运行的主库到一个新的主库中(通过将从库提升为主库),大概0.5-2秒内即可完成。

MHA的组成部分

1
2
3
4
5
`MHA Manager(管理节点)`
可以单独部署在一台独立的机器上管理多个master-slave集群,也可以部署在一台slave上。

`MHA Node(数据节点)`
运行在每台MySQL服务器上 MHA Manager 会定时探测集群中的master节点,当master出现故障时,它可以自动将最新数据的slave提升为新的master;然后将所有其他的slave重新指向新的master,整个故障转移过程对应用程序是完全透明的;

MHA软件结构介绍

节点信息 软件组件 作用介绍
MHA Manager(管理节点) masterha_manger 用于启动MHA
masterha_check_ssh 用于检查MHA的SSH配置互信状况
masterha_check_repl 用于检查MySQL复制状态,以及配置信息
masterha_master_monitor 用于检测master是否宕机
masterha_check_status 用于检测当前MHA运行状态
masterha_master_switch 用于控制故障转移(自动或者手动)
masterha_conf_host 添加或删除配置的server信息
MHA Node(数据节点) save_binary_logs 保存和复制master的二进制日志
apply_diff_relay_logs 识别差异的中继日志事件并将其差异的事件应用于其他slave
purge_relay_logs 清除中继日志(不会阻塞SQL线程)

MHA的工作的原理

QQ_1724757765903

:dango:MHA的设计原理分析(Failover 过程)

1.MHA软件启动

根据启动命令,分析MHA软件启动原理:

1
nohup masterha_manager --conf=/etc/mha/app1.cnf --remove_dead_master_conf --ignore_last_failover  < /dev/null > /var/log/mha/app1/manager.log 2>&1 &

根据以上启动命令,需要先调取MHA启动脚本文件masterha_manager

--conf=.../app1.cnf 会根据加载的MHA的配置文件不同,实现管理多个高可用架构环境,进行高可用业务的架构环境的区分;

--remove_dead_master_conf参数表示在主节点出现宕机情况时,将会从集群中被踢出,即从配置文件中删除掉故障节点;

--ignore_last_failover 默认MHA服务是不能频繁进行故障切换的,需要有一定的间隔时间,加此参数表示忽略切换的间隔时间;

/var/log/mha/app1/manager.log 2>&1最后将MHA启动运行的信息放入到日志文件中即可

:dango:补充

1
2
3
4
5
6
7
8
9
10
11
补充说明:--ignore_last_failover

【官方解释】
If the previous failover failed, MHA does not start failover because the problem might happen again. The normal step to start failover is manually remove failover error file which is created under (manager_workdir)/(app_name).failover.error .By setting --ignore_last_failover, MHA continues failover regardless of the last failover status.

如果上一次高可用功能失败,MHA不会再启动高可用功能,因为这个问题可能会再次出现。后续再想启动故障转移的正常步骤是手动删除故障转移错误文件,错误文件会在manager_workdir目录下,创建一个名为app_name.failover.error的文件。对于设置--ignore_last_failover,表示无论上次故障切换状态如何,MHA都会继续进行启动故障切换功能


在缺省情况下,如果 MHA 检测到连续发生宕机,且两次宕机间隔不足 8 小时的话,则不会进行 Failover;之所以这样限制是为了避免 ping-pong 效应。该参数代表忽略上次 MHA 触发切换产生的文件;默认情况下,MHA 发生切换后会在日志记录,在日志目录中会生成 app1.failover.complete 文件;下次再次切换的时候如果发现该目录下存在该文件将不允许触发切换,除非在第一次切换后删除该文件;

`官方默认8小时之内不能再次执行切换主库,除非删除锁文件 设置的工作目录下的*.failover.error文件`

2.MHA实现监控

利用MHA启动脚本文件masterha_manager会自动调用监控脚本文件masterha_master_monitor,并且每隔配置文件指定时间;

ping_interval=2 进行脚本监控一次,从而判断主节点是否处于存活状态,连续4次还没有主库心跳,即说明主库宕机;

wiki
1
2
3
4
5
6
7
8
# 监控脚本验证主节点存活方法
[root@xiaoQ-03 ~]# mysql -umha -pmha -h192.168.30.101 -e "select user();"
mysql: [Warning] Using a password on the command line interface can be insecure.
+-----------------+
| user() |
+-----------------+
| mha@172.16.1.51 |
+-----------------+

3.MHA选主过程

在MHA中进行选主时,根据选主源码文件信息分析,主要会利用到四个数组:alive latest pref bad,并且会识别节点编号信息;

在进行选主时,主要会关注竞选新主节点的日志量、以及是否设置candidate_master参数配置信息;

数组信息 简述 作用说明
alive 存活数组 主要用于探测存活的节点状态;当主库宕机后,探测的就是两个从库节点
latest 最新数组 表示获取日志最新的从库信息,即数据量最接近主库的从库(根据GTID信息 或 position信息)
pref 备选数组 在数组中具有candidate_master参数判断条件,此参数可以放入配置文件节点中,便于节点优先选择为新主
bad 不选数组 如果设定了参数:no_master=1,表示相应节点不参与竞选主;
如果设定了参数:log_bin=0(二进制日志没开),表示相应节点不参与竞选主;
如何设定了参数:check_slave_delay,检查从库延迟主库100M数据信息日志量,表示节点不参与竞选主

MHA选主判断总结(利用if判断选主的情况)

  • 循环对比latest数组和pref数组的slave,如果存在相同的slave,并且这个slave不在bad数组当中,该slave会被推选为新的master

    DB02节点即满足latest数组信息,又满足perf数组信息,但不满足bad数据信息,即会被选为新主,有多个按照号码顺序选举;

  • 如果pref和bad数组当中的个数为0,则选择latest数组当中的第一个slave为master;

    DB02节点没有candidate_master参数配置,又没有不选数组里的三种情况配置,即db02恰好是latest,为新主;

  • 循环对比alive数组和pref数组当中的slaves,如果有一个slave相同,并且不在bad数组当中,该节点就会成为新的master;

    DB02节点即不满足latest,也不满足bad,但是满足pref,也会被选择作为新主;

  • 循环latest数组,如果又循环到slave不在bad数组当中,这个slave就会成为master,就算添加了candidate_master=1参数;

    该slave也不一定会成为主库;

    DB02节点即满足latest数组,不是bad数组,也会成为新的主;

  • 从活着的slave当中进行循环,如果循环到slave不在bad数组当中,那么这个slave就会成为主库;

    DB02节点是活着的,不满足bad,也可以成为新的主;

  • 如果进行了多次选择都找不到主库,那么主库选择失败,failover失败;

选主策略简述表:

优先级 alive数组 latest数组 pref数组 bad数组 选主策略 多个选择情况
01 满足 满足 满足 不满足 优选选择 按照节点号码顺序选择
02 满足 满足 不满足 不满足 优选选择 按照节点号码顺序选择
03 满足 不满足 满足 不满足 优选选择 按照节点号码顺序选择
04 满足 不满足 不满足 不满足 优选活着节点 按照节点号码顺序选择

说明:在进行手工指定切换新主时,即应用了prio_new_master_host参数信息时,会最优先选择相应节点为新主;

一般情况下是:根据mha配置文件里server后的数值小的切换

1
2
3
4
5
6
[server1]
hostname=10.0.0.51
port=3306
[server2]
hostname=10.0.0.52
port=3306

4.MHA数据补偿

在进行数据补偿之前,需要让新主库与原有宕机主库进行对比,获悉需要补偿的数据量情况,即对比差的数据日志量信息;

然后可以从binlog日志中,进行补充数据信息的截取,随之进行数据信息补偿,但是有种特殊情况,若原有主库无法访问了;

所以进行数据补偿操作,也需要分各种情景进行处理:

  • 原主库SSH连接正常:

    各个从节点自动调用:save_binary_logs脚本文件,立即保存缺失部分的bin_log,到各节点/var/tmp/目录;

  • 原主库SSH连接异常:

    各个从节点自动调用:apply_diff_relay_logs脚本文件,进行relay_log日志差异信息补偿;

  • 额外特殊数据补充:(利用主库日志冗余机制)

    MHA提供了binlog_server功能,可以实时拉取主库的binlog日志到备份节点,从而进行数据额外补偿;

5.MHA业务切换

自动解除原有的主从关系,实现新的主从关系的建立;

wiki
1
2
3
4
5
6
# 所有从库解除主从关系操作
stop slave;
reset slave;

# 所有从库重构主从关系操作
change master to ...

6.MHA应用透明

实现MHA的VIP功能,利用脚本实现,上传mha_script.tar文件到/usr/local/bin目录中,然后进行解压处理;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 上传MHA所需的脚本文件
[root@xiaoQ-03 ~]# cd /usr/local/bin/
[root@xiaoQ-03 bin]# chmod +x /usr/local/bin/*

# 修改MHA脚本文件的信息
[root@xiaoQ-03 bin]# cp master_ip_failover master_ip_failover.bak
[root@xiaoQ-03 bin]# dos2unix /usr/local/bin/*
[root@xiaoQ-03 bin]# vim master_ip_failover
13 my $vip = '192.168.30.110/24';
14 my $key = '1';
15 my $if = 'eth0';
16 my $ssh_start_vip = "/sbin/ifconfig $if:$key $vip";
17 my $ssh_stop_vip = "/sbin/ifconfig $if:$key down";
18 my $ssh_Bcast_arp= "/sbin/arping -I $if -c 3 -A 192.168.30.110";

# 修改配置文件
[root@xiaoQ-03 ~]# vim /etc/mha/app1.cnf
master_ip_failover_script=/usr/local/bin/master_ip_failover

# 重启MHA服务
[root@xiaoQ-03 bin]# masterha_stop --conf=/etc/mha/app1.cnf
[root@xiaoQ-03 bin]# nohup masterha_manager --conf=/etc/mha/app1.cnf --remove_dead_master_conf --ignore_last_failover < /dev/null> /var/log/mha/app1/manager.log 2>&1 &

# 手工在主库上添加VIP
[root@xiaoQ-03 bin]# masterha_check_status --conf=/etc/mha/app1.cnf
app1 (pid:103046) is running(0:PING_OK), master:192.168.30.101
-- 核实此时的MHA的主库节点
ifconfig eth0:1 192.168.30.110/24
-- 在主库节点手工添加vip地址信息

# 进行VIP地址连接测试
-- 可以使用navcat软件,连接MHA的vip地址,查看所连主机信息是否为主节点,当故障转移后可以核实VIP地址是否持续连接;

说明:进行MHA的VIP地址漂移时,只能在局域网环境进行漂移,不能实现跨网段的VIP地址漂移;

7.MHA故障报警

实现MHA的报警功能,利用脚本实现,上传mha_script.tar文件到/usr/local/bin目录中,然后进行解压处理;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 准备脚本文件
[root@xiaoQ-03 bin]# cp send_report send_report.bak
28 my $smtp='smtp.qq.com';
-- smtp服务器地址域名
29 my $mail_from='330882721@qq.com';
-- 发件箱信息配置
30 my $mail_user='330882721';
-- 用户名 QQ号
31 my $mail_pass='ypokkranqlgkcbba';
-- 邮箱授权码
32 my $mail_to='330882721@qq.com';
or
my $mail_to=['to1@qq.com','to2@qq.com'];
-- 收件箱信息配置

# 修改配置文件
[root@xiaoQ-03 ~]# vim /etc/mha/app1.cnf
report_script=/usr/local/bin/send_report

# 重启MHA服务
[root@xiaoQ-03 bin]# masterha_stop --conf=/etc/mha/app1.cnf
[root@xiaoQ-03 bin]# nohup masterha_manager --conf=/etc/mha/app1.cnf --remove_dead_master_conf --ignore_last_failover < /dev/null> /var/log/mha/app1/manager.log 2>&1 &

8.MHA额外补偿

利用binlog_server作为额外的日志补偿的冗余方案,即实时保存主库的bin_log日志文件到特定节点目录中;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 创建日志存放目录
[root@xiaoQ-03 ~]# mkdir -p /data/binlog_server/
[root@xiaoQ-03 ~]# chown -R mysql.mysql /data/*
[root@xiaoQ-03 ~]# cd /data/binlog_server
[root@xiaoQ-03 binlog_server]# mysql -e "show slave status\G"|grep "Master_Log"
Master_Log_File: mysql-bin.000002
Read_Master_Log_Pos: 1201
Relay_Master_Log_File: mysql-bin.000002
Exec_Master_Log_Pos: 1201
-- 拉取日志的起点,需要按照目前从库的已经获取到的二进制日志点为起点
[root@xiaoQ-03 binlog_server]# mysqlbinlog -R --host=192.168.30.101 --user=mha --password=mha --raw --stop-never mysql-bin.000002 &

# 编写配置文件信息
[root@xiaoQ-03 ~]# vim /etc/mha/app1.cnf
[binlog1]
no_master=1
-- 不存于竞选
hostname=192.168.30.103
-- 将日志额外补偿到哪个主机上
master_binlog_dir=/data/binlog_server/
-- 日志额外补偿的存储目录

# 重启MHA服务
[root@xiaoQ-03 bin]# masterha_stop --conf=/etc/mha/app1.cnf
[root@xiaoQ-03 bin]# nohup masterha_manager --conf=/etc/mha/app1.cnf --remove_dead_master_conf --ignore_last_failover < /dev/null> /var/log/mha/app1/manager.log 2>&1 &

MHA搭建

  • 搭建MySQL的MHA需要保证主从复制是OK的

环境一览

主机名 WanIP LanIP 角色
mha 10.0.0.50 172.16.1.50 MHA管理端
db01 10.0.0.51 172.16.1.51 暂时主库,客户端
db02 10.0.0.52 172.16.1.52 从库,MHA客户端
db03 10.0.0.53 172.16.1.53 从库,MHA客户端
db04 10.0.0.54 172.16.1.54 从库,MHA客户端

MHA的必要条件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
1.主从复制OK
2.数据库的每个节点都得有rep主从复制用户
3.数据库每个节点要有mha用户
4.关闭自动删除relay-log
5.每一台都需要做免密连接
6.做mysqld软链接


# 三台从库设置只读(临时生效)
mysql> set global read_only=1;

# 四台数据库关闭relaylog自动删除功能(临时生效)
mysql> set global relay_log_purge = 0;

:dango:主从复制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#1.编辑主库配置文件
[root@db01 ~]# vim /etc/my.cnf
[mysqld]
basedir=/app/mysql
datadir=/app/mysql/data
server_id=1
log-bin=mysql-bin
skip_name=resolve
#关闭自动删除relay-log
relay_log_purge=0

#2.从库配置文件的每台server_id不同即可

#3.主库创建主从复制用户
mysql> grant replication slave on *.* to rep@'172.16.1.5%' identified by '123';

#主库检查bin-log位置点
db01 [(none)]>show master status;
+------------------+----------+--------------+
| File | Position | Binlog_Do_DB |
+------------------+----------+--------------+
| mysql-bin.000003 | 327 | |
+------------------+----------+--------------+

#4.所有从库执行
change master to
master_host='172.16.1.51',
master_user='rep',
master_password='123',
master_log_file='mysql-bin.000003',
master_log_pos=327,
master_port=3306;

#所有从库开启主从复制
mysql > start slave;

:dango:主库执行

1
2
3
4
5
6
#主库执行(主从复制OK情况下)
#每台都有主从复制用户
mysql> grant replication slave on *.* to rep@'172.16.1.5%' identified by '123';

#每台都有mha用户
mysql> grant all on *.* to mha@'172.16.1.5%' identified by 'mha';

:dango:互信免密

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#可以执行脚本,每一台都需要免密(注意修改密码 -p 1 )
[root@db01 ~]# cat push_public_key.sh
#!/bin/bash
yum -y install sshpass
test -f ~/.ssh/id_rsa || ssh-keygen -t rsa -P '' -f ~/.ssh/id_rsa >/dev/null 2>&1
for ip in 50 51 52 53 54;do
ping -c1 -W1 172.16.1.$ip &>/dev/null
[ $? -eq 0 ] &&\
sshpass -p 1 ssh-copy-id -o StrictHostKeyChecking=no -i ~/.ssh/id_rsa.pub root@172.16.1.$ip &>/dev/null &&\
echo "172.16.1.$ip 推送成功..." ||\
echo "172.16.1.$ip 推送失败..."
done

#不用脚本
## 生成密钥对
[root@db01 ~]# ssh-keygen -t dsa -P '' -f ~/.ssh/id_dsa >/dev/null 2>&1
[root@db02 ~]# ssh-keygen -t dsa -P '' -f ~/.ssh/id_dsa >/dev/null 2>&1
[root@db03 ~]# ssh-keygen -t dsa -P '' -f ~/.ssh/id_dsa >/dev/null 2>&1
[root@db04 ~]# ssh-keygen -t dsa -P '' -f ~/.ssh/id_dsa >/dev/null 2>&1
[root@mha-manager ~]# ssh-keygen -t dsa -P '' -f ~/.ssh/id_dsa >/dev/null 2>&1


## 推送公钥(每一台都需要执行,sshpass需要安装,不然需要交互)
[root@db01 ~]# sshpass -p 1 ssh-copy-id -i ~/.ssh/id_dsa.pub root@172.16.1.50
[root@db01 ~]# sshpass -p 1 ssh-copy-id -i ~/.ssh/id_dsa.pub root@172.16.1.51
[root@db01 ~]# sshpass -p 1 ssh-copy-id -i ~/.ssh/id_dsa.pub root@172.16.1.52
[root@db01 ~]# sshpass -p 1 ssh-copy-id -i ~/.ssh/id_dsa.pub root@172.16.1.53
[root@db01 ~]# sshpass -p 1 ssh-copy-id -i ~/.ssh/id_dsa.pub root@172.16.1.54


#所以用脚本吧

:dango:命令软链接

1
2
3
4
5
6
7
8
9
10
11
[root@db01 ~]# ln -s /app/mysql/bin/mysqlbinlog /usr/bin/mysqlbinlog
[root@db01 ~]# ln -s /app/mysql/bin/mysql /usr/bin/mysql

[root@db02 ~]# ln -s /app/mysql/bin/mysqlbinlog /usr/bin/mysqlbinlog
[root@db02 ~]# ln -s /app/mysql/bin/mysql /usr/bin/mysql

[root@db03 ~]# ln -s /app/mysql/bin/mysqlbinlog /usr/bin/mysqlbinlog
[root@db03 ~]# ln -s /app/mysql/bin/mysql /usr/bin/mysql

[root@db04 ~]# ln -s /app/mysql/bin/mysqlbinlog /usr/bin/mysqlbinlog
[root@db04 ~]# ln -s /app/mysql/bin/mysql /usr/bin/mysql

部署MHA客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#MySQL 5.6版本可以使用node0.56版本
[root@db01 ~]# wget http://test.driverzeng.com/MySQL_plugins/mha4mysql-node-0.56-0.el6.noarch.rpm

#MySQL 5.7及以上建议使用node0.58版本
[root@db01 ~]# wget https://github.com/yoshinorim/mha4mysql-node/releases/download/v0.58/mha4mysql-node-0.58-0.el7.centos.noarch.rpm

#将node传到其它机器
[root@db01 ~]# scp mha4mysql-node-0.56-0.el6.noarch.rpm 10.0.0.50:/root
[root@db01 ~]# scp mha4mysql-node-0.56-0.el6.noarch.rpm 10.0.0.52:/root
[root@db01 ~]# scp mha4mysql-node-0.56-0.el6.noarch.rpm 10.0.0.53:/root
[root@db01 ~]# scp mha4mysql-node-0.56-0.el6.noarch.rpm 10.0.0.54:/root

#安装node(每个节点都做)
[root@db01 ~]# yum -y localinstall mha4mysql-node-0.56-0.el6.noarch.rpm
[root@db02 ~]# yum -y localinstall mha4mysql-node-0.56-0.el6.noarch.rpm
[root@db03 ~]# yum -y localinstall mha4mysql-node-0.56-0.el6.noarch.rpm
[root@db04 ~]# yum -y localinstall mha4mysql-node-0.56-0.el6.noarch.rpm
[root@mha ~]# yum -y localinstall mha4mysql-node-0.56-0.el6.noarch.rpm

部署MHA管理端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# 1.创建配置文件存放目录
[root@mha-manager ~]# mkdir /etc/mha

# 2.编写配置文件
[root@mha-manager ~]# vim /etc/mha/app1.cnf
[server default]
manager_log=/etc/mha/logs/manager.log
manager_workdir=/etc/mha/app1
master_binlog_dir=/app/mysql/data
user=mha
password=mha
ping_interval=2
repl_user=rep
repl_password=123
ssh_user=root
ssh_port=22

[server1]
#candidate_master=1
#check_repl_delay=0
hostname=172.16.1.51
port=3306

[server2]
#candidate_master=1
#check_repl_delay=0
hostname=172.16.1.52
port=3306

[server3]
hostname=172.16.1.53
port=3306

[server4]
hostname=172.16.1.54
port=3306


# 3.创建MHA管理用户
mysql> grant all on *.* to mha@'172.16.1.5%' identified by 'mha';

# 4.日志和工作目录目录创建
[root@mha-manager ~]# mkdir -p /etc/mha/{logs,app1}
[root@mha-manager ~]# ll /etc/mha/
total 4
drwxr-xr-x 2 root root 6 Aug 27 12:20 app1
-rw-r--r-- 1 root root 457 Aug 27 12:16 app1.cnf
drwxr-xr-x 2 root root 6 Aug 27 12:19 logs

# 5.检测MHA ssh免密
[root@mha-manager ~]# masterha_check_ssh --conf=/etc/mha/app1.cnf
All SSH connection tests passed successfully.

# 6.检测MHA 主从复制
[root@mha-manager ~]# masterha_check_repl --conf=/etc/mha/app1.cnf
MySQL Replication Health is OK.

# 7.启动MHA
nohup masterha_manager --conf=/etc/mha/app1.cnf --remove_dead_master_conf --ignore_last_failover < /dev/null > /etc/mha/logs/manager.log 2>&1 &


`masterha_manager:`启动命令
--conf=/etc/mha/app1.cnf:指定配置文件
--remove_dead_master_conf:做完切换后,从配置文件中摘除宕机的主库
--ignore_last_failover:忽略上一次切换

# MHA切换机制:
1.MHA在做一次切换后,生成一个锁文件(app1.failover.complete),在工作目录下,8个小时之内,无法做第二次切换
2.MHA切换完成后,会自动结束MHA的进程
3.在所有从库数据相同时,MHA会选择配置文件中标签id最小的切换

# 8.启动后检测
[root@mha-manager ~]# masterha_check_status --conf=/etc/mha/app1.cnf
app1 (pid:19524) is running(0:PING_OK), master:172.16.1.51

## 使用systemd管理mha
[root@mha-manager ~]# vim /usr/lib/systemd/system/mha.service
[Unit]
Description=MHA
After=network.target sshd-keygen.service
Wants=sshd-keygen.service
[Service]
Type=sample
ExecStart=/usr/bin/masterha_manager --conf=/etc/mha/app1.cnf --
remove_dead_master_conf --ignore_last_failover > /etc/mha/logs/manager.log
ExecStop=/usr/bin/masterha_stop --conf=/etc/mha/app1.cnf
[Install]
WantedBy=multi-user.target

MHA配置文件详解:dango:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
[server default]
#设置manager的工作目录
manager_workdir=/var/log/masterha/app1

#设置manager的日志
manager_log=/var/log/masterha/app1/manager.log

#设置master 保存binlog的位置,以便MHA可以找到master的日志,我这里的也就是mysql的数据目录
master_binlog_dir=/data/mysql

#设置自动failover时候的切换脚本
master_ip_failover_script= /usr/local/bin/master_ip_failover

#设置手动切换时候的切换脚本
master_ip_online_change_script= /usr/local/bin/master_ip_online_change

#设置mysql中root用户的密码,这个密码是前文中创建监控用户的那个密码
password=1

#设置监控用户root
user=root

#设置监控主库,发送ping包的时间间隔,尝试三次没有回应的时候自动进行failover
ping_interval=1

#设置远端mysql在发生切换时binlog的保存位置
remote_workdir=/tmp

#设置复制用户的密码
repl_password=123

#设置复制环境中的复制用户名
repl_user=rep

#设置发生切换后发送的报警的脚本
report_script=/usr/local/send_report

#一旦MHA到server02的监控之间出现问题,MHA Manager将会尝试从server03登录到server02
secondary_check_script= /usr/local/bin/masterha_secondary_check -s server03 -s server02 --user=root --master_host=server02 --master_ip=192.168.0.50 --master_port=3306
#设置故障发生后关闭故障主机脚本(该脚本的主要作用是关闭主机放在发生脑裂,这里没有使用)
shutdown_script=""
#设置ssh的登录用户名
ssh_user=root
[server1]
hostname=10.0.0.51
port=3306
[server2]
hostname=10.0.0.52
port=3306
#设置为候选master,如果设置该参数以后,发生主从切换以后将会将此从库提升为主库,即使这个主库不是集群中事件最新的slave。
candidate_master=1
#默认情况下如果一个slave落后master 100M的relay logs的话,MHA将不会选择该slave作为一个新的master,因为对于这个slave的恢复需要花费很长时间,通过设置check_repl_delay=0,MHA触发切换在选择一个新的master的时候将会忽略复制延时,这个参数对于设置了candidate_master=1的主机非常有用,因为这个候选主在切换的过程中一定是新的master
check_repl_delay=0


#一旦MHA到server02的监控之间出现问题,MHA Manager将会尝试从server03登录到server02
secondary_check_script= /usr/local/bin/masterha_secondary_check -s server03 -s
server02 --user=root --master_host=server02 --master_ip=192.168.0.50 --
master_port=3306

#设置故障发生后关闭故障主机脚本(该脚本的主要作用是关闭主机放在发生脑裂,这里没有使用)
shutdown_script=""

#设置ssh的登录用户名
ssh_user=root

[server1]
hostname=10.0.0.51
port=3306

[server2]
hostname=10.0.0.52
port=3306

#设置为候选 master,如果设置该参数以后,发生主从切换以后将会将此从库提升为主库,即使这个主库不是集群中事件最新的 slave。
candidate_master=1

#默认情况下如果一个 slave 落后 master 100M 的 relay logs 的话,MHA 将不会选择该 slave 作为一个新的 master,因为对于这个 slave 的恢复需要花费很长时间,通过设置 check_repl_delay=0,MHA 触发切换在选择一个新的 master 的时候将会忽略复制延时,这个参数对于设置了 candidate_master=1 的主机非常有用,因为这个候选主在切换的过程中一定是新的 master
check_repl_delay=0

切换日志—注意几点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
## 切换日志:
# GTID主从没有开启
GTID failover mode = 0
Starting Non-GTID based failover.

# VIP漂移的脚本没有设置
master_ip_failover_script is not set. Skipping invalidating dead master IP address.

# 没有配置 Candidate masters
Candidate masters from the configuration file:
Non-candidate masters:
candidate_master=1 // 设立太子,但是如果太子落后其他机器数据超过100M,就废储
check_repl_delay=0 // 关闭对太子落后的检测

# change master语句 以后恢复数据时候要根据这个点位来切换
All other slaves should start replication from here. Statement should be:
CHANGE MASTER TO MASTER_HOST='172.16.1.54', MASTER_PORT=3306,MASTER_LOG_FILE='mysql-bin.000003', MASTER_LOG_POS=878597, MASTER_USER='rep',MASTER_PASSWORD='xxx';

MHA相关工具命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
save_binary_logs
--command=save
--start_file=mysql-bin.000001
--start_pos=878597
--binlog_dir=/app/mysql/data
--
output_file=/var/tmp/saved_master_binlog_from_172.16.1.52_3306_20240827154042.bi
nlog
--handle_raw_binlog=1
--disable_log_bin=0
--manager_version=0.58
pply_diff_relay_logs
--command=apply
--slave_user='mha'
--slave_host=172.16.1.54
--slave_ip=172.16.1.54
--slave_port=3306
--
apply_files=/var/tmp/saved_master_binlog_from_172.16.1.52_3306_20240827154042.bi
nlog
--workdir=/var/tmp
--target_version=5.7.42-log
--timestamp=20240827154042
--handle_raw_binlog=1
--disable_log_bin=0
--manager_version=0.58
--slave_pass=xxx

binlog的路径

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 1.先将binlog保存在宕机主库的 /var/tmp/
[root@db02 ~]# ll
/var/tmp/saved_master_binlog_from_172.16.1.52_3306_20240827154042.binlog
-rw-r--r-- 1 root root 177 Aug 27 15:40
/var/tmp/saved_master_binlog_from_172.16.1.52_3306_20240827154042.binlog
# 2.将binlog从宕机主库保存到manager所在的机器
[root@mha-manager ~]# ll
/etc/mha/app1/saved_master_binlog_from_172.16.1.52_3306_20240827154042.binlog
-rw-r--r-- 1 root root 177 Aug 27 15:40
/etc/mha/app1/saved_master_binlog_from_172.16.1.52_3306_20240827154042.binlog
# 3.将binlog从manager所在的机器发送给新主库
[root@db04 ~]# ll
/var/tmp/saved_master_binlog_from_172.16.1.52_3306_20240827154042.binlog
-rw-r--r-- 1 root root 177 Aug 27 15:40
/var/tmp/saved_master_binlog_from_172.16.1.52_3306_20240827154042.binlog

QQ_1724772576926

MHA自动恢复

手动恢复

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 1.修复宕机的主库
[root@db02 ~]# systemctl start mysqld

# 2.找到change master语句
CHANGE MASTER TO MASTER_HOST='172.16.1.54', MASTER_PORT=3306,
MASTER_LOG_FILE='mysql-bin.000003', MASTER_LOG_POS=878597, MASTER_USER='rep',
MASTER_PASSWORD='123';

# 3.启动主从复制
mysql> start slave;
# 4.补全配置文件
[root@mha-manager ~]# vim /etc/mha/app1.cnf
[server2]
hostname=172.16.1.52
port=3306

# 5.启动MHA
[root@mha-manager ~]# systemctl start mha
# 6.检测MHA启动
[root@mha-manager ~]# masterha_check_status --conf=/etc/mha/app1.cnf

自动恢复脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#!/bin/bash
. /etc/init.d/functions
#vars
log_file='/etc/mha/logs/manager.log'
mha_conf="/etc/mha/app1.cnf"
repl_pass='123'
mha_user=$(awk -F= '/^user/{print $2}' ${mha_conf})
mha_password=$(awk -F= '/^password/{print $2}' ${mha_conf})
down_master=$(sed -nr 's#^Master (.*)\(.*\).*!$#\1#gp' ${log_file}|tail -1 )
change_master=$(grep -i 'change master to' ${log_file}|tail -1|awk -F: '{print $4}'|sed "s#xxx#${repl_pass}#g")
master_ip_failover_script=/etc/mha/app1/master_ip_failover



#启动MySQL,检测MySQL是否完全启动,启动后执行命令,开启主从复制
ssh ${down_master} 'systemctl start mysqld'
while true;do
mysqladmin -u${mha_user} -p${mha_password} -h${down_master} ping &>/dev/null
if [ $? -eq 0 ];then
mysql -u${mha_user} -p${mha_password} -h${down_master} -e "${change_master};start slave"
break
fi
done

#重新写入MHA管理端配置文件
cat > ${mha_conf} <<EOF
[server default]
manager_log=/etc/mha/logs/manager.log
manager_workdir=/etc/mha/app1
master_binlog_dir=/app/mysql/data
password=${mha_password}
ping_interval=2
repl_password=123
repl_user=rep
ssh_port=22
ssh_user=root
user=${mha_user}
[server1]
hostname=172.16.1.51
port=3306
[server2]
hostname=172.16.1.52
port=3306
[server3]
hostname=172.16.1.53
port=3306
[server4]
hostname=172.16.1.54
port=3306
EOF

#启动MHA,并且检测MHA状态,直至启动成功结束循环
systemctl start mha
while true;do
masterha_check_status --conf=${mha_conf} &>/dev/null
if [ $? -eq 0 ];then
action "mha server" /bin/true
break
fi
done

优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
[root@mha ~]# cat failover_status 
#!/bin/bash
#上一次新主库
last_new_master=$(grep '(new master)' /etc/mha/logs/manager.log |tail -2|awk -F '(' 'NR==1{print $1}')

#
[root@mha ~]# cat recovery_mha.sh
#!/bin/bash
. /etc/init.d/functions
. /root/failover_status

log_file='/etc/mha/logs/manager.log'
mha_conf="/etc/mha/app1.cnf"
repl_pass='123'
mha_user=$(awk -F= '/^user/{print $2}' ${mha_conf})
mha_password=$(awk -F= '/^password/{print $2}' ${mha_conf})
down_master=$(sed -nr 's#^Master (.*)\(.*\).*!$#\1#gp' ${log_file}|tail -1 )

while true;do
#判断是否修复完成
#当前down的主库和上次主库一致时,判定修复完成(依据截取Master 172.16.1.*(172.16.1.*:3306) is down!)
#判定依据就是只有修复完成才会有Master 172.16.1.*(172.16.1.*:3306) is down!)
if [ ${down_master} == ${last_new_master} ];then
change_master=$(grep -i 'change master to' ${log_file}|tail -1|awk -F: '{print $4}'|sed "s#xxx#${repl_pass}#g")
echo "主库修复中..."
ssh ${down_master} -C 'systemctl start mysqld'
while true;do
mysqladmin -u${mha_user} -p${mha_password} -h${down_master} ping &>/dev/null
if [ $? -eq 0 ];then
#down的机器做从库
mysql -u${mha_user} -p${mha_password} -h${down_master} -e "${change_master};start slave"
echo "主库修复成功..."
break
fi
done

echo "正在补全MHA配置文件..."
cat > ${mha_conf} <<- EOF
[server default]
manager_log=/etc/mha/logs/manager.log
manager_workdir=/etc/mha/app1
master_binlog_dir=/app/mysql/data
password=${mha_password}
ping_interval=2
repl_password=123
repl_user=rep
ssh_port=22
ssh_user=root
user=${mha_user}
[server1]
hostname=172.16.1.51
port=3306
[server2]
hostname=172.16.1.52
port=3306
[server3]
hostname=172.16.1.53
port=3306
[server4]
hostname=172.16.1.54
port=3306
EOF

echo "正在启动MHA..."
systemctl start mha
while true;do
masterha_check_status --conf=${mha_conf} &>/dev/null
if [ $? -eq 0 ];then
action "MHA manager启动" /bin/true
exit 0
fi
done
else
continue
fi
done

MHA的vip漂移

配置master_ip_failover

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 1.修改MHA配置文件,加上脚本
[root@mha-manager ~]# vim /etc/mha/app1.cnf
[server default]
master_ip_failover_script=/etc/mha/app1/master_ip_failover

# 2.修改MHA脚本 加上绑定vip的命令(先上传脚本)
[root@mha-manager ~]# vim /etc/mha/app1/master_ip_failover
my $vip = '172.16.1.55/24';
my $key = '1';
my $ssh_start_vip = "/sbin/ifconfig eth1:$key $vip";
my $ssh_stop_vip = "/sbin/ifconfig eth1:$key down";

# 4.给脚本执行权限
[root@mha-manager ~]# chmod +x /etc/mha/app1/master_ip_failover

# 5.手动在主库上绑定VIP
[root@db01 ~]# ifconfig eth1:1 172.16.1.55/24

# 6.重启MHA
[root@mha-manager ~]# systemctl stop mha
[root@mha-manager ~]# systemctl start mha


## 添加脚本后,启动不起来的原因:
1.脚本权限问题
[root@mha-manager ~]# chmod +x /etc/mha/app1/master_ip_failover
2.脚本语法问题
3.脚本格式问题
[root@mha-manager ~]# dos2unix /etc/mha/app1/master_ip_failover
dos2unix: converting file /etc/mha/app1/master_ip_failover to Unix format ...

自动恢复脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
[root@mha ~]# cat failover_status 
#!/bin/bash
#上一次新主库
last_new_master=$(grep '(new master)' /etc/mha/logs/manager.log |tail -2|awk -F '(' 'NR==1{print $1}')

#
[root@mha ~]# cat recovery_mha.sh
#!/bin/bash
. /etc/init.d/functions
. /root/failover_status

log_file='/etc/mha/logs/manager.log'
mha_conf="/etc/mha/app1.cnf"
repl_pass='123'
mha_user=$(awk -F= '/^user/{print $2}' ${mha_conf})
mha_password=$(awk -F= '/^password/{print $2}' ${mha_conf})
down_master=$(sed -nr 's#^Master (.*)\(.*\).*!$#\1#gp' ${log_file}|tail -1 )

while true;do
#判断是否修复完成
#当前down的主库和上次主库一致时,判定修复完成(依据截取Master 172.16.1.*(172.16.1.*:3306) is down!)
#判定依据就是只有修复完成才会有Master 172.16.1.*(172.16.1.*:3306) is down!)
if [ ${down_master} == ${last_new_master} ];then
change_master=$(grep -i 'change master to' ${log_file}|tail -1|awk -F: '{print $4}'|sed "s#xxx#${repl_pass}#g")
echo "主库修复中..."
ssh ${down_master} -C 'systemctl start mysqld'
while true;do
mysqladmin -u${mha_user} -p${mha_password} -h${down_master} ping &>/dev/null
if [ $? -eq 0 ];then
#down的机器做从库
mysql -u${mha_user} -p${mha_password} -h${down_master} -e "${change_master};start slave"
echo "主库修复成功..."
break
fi
done

echo "正在补全MHA配置文件..."
cat > ${mha_conf} <<- EOF
[server default]
master_ip_failover_script=/etc/mha/app1/master_ip_failover
manager_log=/etc/mha/logs/manager.log
manager_workdir=/etc/mha/app1
master_binlog_dir=/app/mysql/data
password=${mha_password}
ping_interval=2
repl_password=123
repl_user=rep
ssh_port=22
ssh_user=root
user=${mha_user}
[server1]
hostname=172.16.1.51
port=3306
[server2]
hostname=172.16.1.52
port=3306
[server3]
hostname=172.16.1.53
port=3306
[server4]
hostname=172.16.1.54
port=3306
EOF

echo "正在启动MHA..."
systemctl start mha
while true;do
masterha_check_status --conf=${mha_conf} &>/dev/null
if [ $? -eq 0 ];then
action "MHA manager启动" /bin/true
exit 0
fi
done
else
continue
fi
done

MySQL binlog实时同步

使用mysqlbinlog实时同步binlog

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
## MHA 配置 binlog server
# 1.修改MHA配置文件
[root@mha-manager ~]# vim /etc/mha/app1.cnf
[binlog1]
#加上no_master之后无论如何都不会被提升为主库
no_master=1
hostname=172.16.1.50
master_binlog_dir=/data/mysql/binlog/

# 2.创建binlog目录
[root@mha-manager ~]# mkdir -p /data/mysql/binlog/

# 3.manager服务器安装mysql5.7客户端
[root@mha-manager ~]# cat /etc/yum.repos.d/mysql-community.repo
[mysql56-community]
name=MySQL 5.6 Community Server
baseurl=http://repo.mysql.com/yum/mysql-5.6-community/el/7/$basearch
enabled=1
gpgcheck=0

[root@mha-manager binlog]# yum install -y mysql

# 4.实时同步binlog
[root@mha-manager binlog]# mysqlbinlog -R --host=172.16.1.55 --user=mha --password=mha --raw --stop-never mysql-bin.000001 &