mysql-高可用架构:MHA

mysql-高可用架构:MHA

1. MHA简介

MHA(Master High Availability)是由日本人yoshinorim开发的一款成熟且开源的MySQL高可用程序,它实现了MySQL主从环境下MASTER宕机后能够自动进行单次故障转移的功能,其本身由perl语言编写,安装方便使用简单。

该软件由两部分组成: MHA Manager(管理节点)和 MHA Node(数据节点)。MHA Manager 可以单独部署在一台独立的机器上管理多个 master-slave 集群,也可以部署在一台 slave 节点上。MHA Node 运行在每台 MySQL 服务器上,MHA Manager 会定时探测集群中的 master 节点,当 master 出现故障时,它可以自动将最新数据的 slave 提升为新的 master,然后将所有其他的 slave 重新指向新的 master。整个故障转移过程对应用程序完全透明。

1.1 MHA 工作流程

以下是MHA的工作流程,Manager节点通过masterha_manager脚本启动MHA后会先进行检查工作:

  • Manager节点通过masterha_check_ssh脚本检查各节点的互信配置
  • Manager节点通过masterha_check_repl脚本检查主从之间的复制情况

检查工作均完成且确认无误后,Manager节点会进行监控工作:

  • Manager节点通过masterha_master_monitor对主库不断的进行心跳检测,主库3次无响应后会认为其以宕机

当主库宕机后,会开始故障转移工作,首先会对SLAVE进行选主,有以下3种算法:

  • 读取Manager配置文件,判断是否有强制选主的Slave
  • 自动判断目前已有从库的日志量,将最接近主库日志量的从库选为新的主库
  • 根据配置文件中先后顺序进行选主

当选主完成后,Manager节点会再次通过SSH链接已宕机主库,有以下2种情况发生:

  • 已宕机主库的SSH能够链接,表明MySQL服务是由逻辑因素所导致的宕机,此时Manager会通过save_binary_logs脚本,计算各个从库(包括新主库)与已宕机主库之间binlog差异,将已宕机主库的binlog位置找出来并进行截取、分发到各个从库上进行数据对齐,确保数据一致性
  • 已宕机主库的SSH不能链接,表明MySQL服务是由物理因素所导致的宕机,此时Manager会通过apply_diff_relay_logs脚本,计算各个从库relay-log的差异,将差异较大的从库与新主库进行relay-log对齐,确保数据一致性

当所有库的数据一致性被确保之后,所有从库都将会与新主库建立主从关系,同时旧的已宕机主库信息将会从Manager项目配置文件中移除,至此整个MHA软件服务结束,Manager不会再对Node进行管理,接下来需要管理员手动对已宕机主库进行排查恢复,并且手动搭建旧主库与新主库之间的主从关系然后重新启动整个MHA服务。

MHA高可用架构 – 知乎 (zhihu.com)

2. MHA实操配置

2.1 环境配置

本次所用主机系统版本均为centos7,mysql版本为5.7.37

服务列表 IP地址 mysql主节点(Master) 192.168.80.20 mysql从节点1 192.168.80.25 mysql从节点2 192.168.80.30 MHA Manager 192.168.80.35

2.2 搭建步骤

1.首先关闭所有虚拟机的防火墙与SElinux。

systemctl stop firewalld
systemctl disable firewalld
setenforce 0

2.配置主机名

为方便操作时区分各个主机,分别设置Master,Slaver1,Slaver2节点主机名称为mysql_master,mysql_slaver1,mysql_slaver2.

hostnamectl set-hostname mysql_master
hostnamectl set-hostname mysql_slaver1
hostnamectl set-hostname mysql_slaver2

su

3.修改 Master、Slaver1、Slaver2 节点的 Mysql主配置文件/etc/my.cnf,配置主从同步。

##Master 节点##
vim /etc/my.cnf
[mysqld]
server-id = 1
log_bin = master-bin
log-slave-updates = true

systemctl restart mysqld

##Slave1、Slave2 节点##
vim /etc/my.cnf
server-id = 2 / 3                       #三台服务器的 server-id 不能一样
log_bin = master-bin
relay-log = relay-log-bin
relay-log-index = slave-relay-bin.index

systemctl restart mysqld

4.在 Master、Slave1、Slave2 节点上都创建两个软链接

ln -s /usr/local/mysql/bin/mysql /usr/sbin/
ln -s /usr/local/mysql/bin/mysqlbinlog /usr/sbin/

5.配置 mysql 一主两从

(1)权限配置

mysql -uroot -pabc123
grant replication slave on *.* to 'myslave'@'192.168.80.%' identified by '123';     #从数据库同步使用
grant all privileges on *.* to 'mha'@'192.168.80.%' identified by 'manager';        #manager 使用

grant all privileges on *.* to 'mha'@'mysql_master' identified by 'manager';                #防止从库通过主机名连接不上主库
grant all privileges on *.* to 'mha'@'mysql_slaver1' identified by 'manager';
grant all privileges on *.* to 'mha'@'mysql_slaver2' identified by 'manager';
flush privileges;

(2)在 Master 节点查看二进制文件和同步点

##Master 节点##
mysql> show master status;
+-------------------+----------+--------------+------------------+-------------------+
| File              | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+-------------------+----------+--------------+------------------+-------------------+
| master-bin.000001 |     1765 |              |                  |                   |
+-------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)

(3)在 Slave1、Slave2 节点执行同步操作

(3)在 Slave1、Slave2 节点执行同步操作,注意log_pos需要与主的查询一致
change master to master_host='192.168.80.20',master_user='myslave',master_password='123',master_log_file='master-bin.000001',master_log_pos=1765;

start slave;

(4)在 Slave1、Slave2 节点查看数据同步结果

show slave status\G
//确保 IO 和 SQL 线程都是 Yes,代表同步正常。
Slave_IO_Running: Yes
Slave_SQL_Running: Yes

(5) Slave1、Slave2开启只读模式。

set global read_only=1;

(6)插入数据测试数据库同步

##在 Master 主库插入条数据,测试是否同步##
create database canyun_db;
use canyun_db;
create table test(id int);
insert into test(id) values (1);

##SLAVER1,2 查看是否完成同步
select * from canyun_db.test;

6.安装 MHA 软件
(1)所有服务器(包括MHA Manager)上都安装 MHA 依赖的环境,首先安装 epel 源

yum install epel-release --nogpgcheck -y

yum install -y perl-DBD-MySQL \
perl-Config-Tiny \
perl-Log-Dispatch \
perl-Parallel-ForkManager \
perl-ExtUtils-CBuilder \
perl-ExtUtils-MakeMaker \
perl-CPAN

(2)安装 MHA 软件包,先在所有服务器上必须先安装 node 组件

对于每个操作系统版本不一样,这里 CentOS7.6 必须选择 0.57 版本。
在所有服务器上必须先安装 node 组件,最后在 MHA-manager 节点上安装 manager 组件,因为 manager 依赖 node 组件。

事先准备软件包到/opt目录

cd /opt
tar zxvf mha4mysql-node-0.57.tar.gz
cd mha4mysql-node-0.57
perl Makefile.PL
make && make install

(3)在 MHA manager 节点上安装 manager 组件

cd /opt
tar zxvf mha4mysql-manager-0.57.tar.gz
cd mha4mysql-manager-0.57
perl Makefile.PL
make && make install

7.在所有服务器上配置无密码认证
(1)在 manager 节点上配置到所有数据库节点的无密码认证

ssh-keygen -t rsa               #一路按回车键
ssh-copy-id 192.168.80.20
ssh-copy-id 192.168.80.25
ssh-copy-id 192.168.80.30

(2)在 master上配置到数据库节点 slaver1 和 slaver2 的无密码认证

ssh-keygen -t rsa
ssh-copy-id 192.168.80.25
ssh-copy-id 192.168.80.30

(3)在 slaver1上配置到数据库节点 master 和 slaver2 的无密码认证

ssh-keygen -t rsa
ssh-copy-id 192.168.80.20
ssh-copy-id 192.168.80.30

(4)在 slaver2 上配置到数据库节点 master和 slaver1 的无密码认证

ssh-keygen -t rsa
ssh-copy-id 192.168.80.20
ssh-copy-id 192.168.80.25
  1. 在 manager 节点上配置 MHA

(1)在 manager 节点上复制相关脚本到/usr/local/bin 目录

cp -rp /opt/mha4mysql-manager-0.57/samples/scripts /usr/local/bin
//拷贝后会有四个执行文件
ll /usr/local/bin/scripts/

(2)复制上述的自动切换时 VIP 管理的脚本到 /usr/local/bin 目录,这里使用master_ip_failover脚本来管理 VIP 和故障切换

cp /usr/local/bin/scripts/master_ip_failover /usr/local/bin

(3)修改内容如下:(删除原有内容,直接复制并修改vip相关参数。可在拷贝前输入 :set paste 解决vim粘贴乱序问题)

vim /usr/local/bin/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
);
#############################添加内容部分#########################################
my $vip = '192.168.80.200';                                 #指定vip的地址
my $brdc = '192.168.80.255';                                #指定vip的广播地址
my $ifdev = 'ens33';                                        #指定vip绑定的网卡
my $key = '1';                                              #指定vip绑定的虚拟网卡序列号
my $ssh_start_vip = "/sbin/ifconfig ens33:$key $vip";       #代表此变量值为ifconfig ens33:1 192.168.80.200
my $ssh_stop_vip = "/sbin/ifconfig ens33:$key down";        #代表此变量值为ifconfig ens33:1 192.168.80.200
my $exit_code = 0;                                          #指定退出状态码为0
#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 \";
}
## A simple system call that disable the VIP on the old_master
sub stop_vip() {
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";
}

(4)创建 MHA 软件目录并拷贝配置文件,这里使用app1.cnf配置文件来管理 mysql 节点服务器

mkdir /etc/masterha
cp /opt/mha4mysql-manager-0.57/samples/conf/app1.cnf /etc/masterha

vim /etc/masterha/app1.cnf                      #删除原有内容,直接复制并修改节点服务器的IP地址
[server default]
manager_log=/var/log/masterha/app1/manager.log
manager_workdir=/var/log/masterha/app1
master_binlog_dir=/usr/local/mysql/data
master_ip_failover_script=/usr/local/bin/master_ip_failover
master_ip_online_change_script=/usr/local/bin/master_ip_online_change
password=manager
ping_interval=1
remote_workdir=/tmp
repl_password=123
repl_user=myslave
secondary_check_script=/usr/local/bin/masterha_secondary_check -s 192.168.80.25 -s 192.168.80.30
shutdown_script=""
ssh_user=root
user=mha

[server1]
hostname=192.168.80.20
port=3306

[server2]
candidate_master=1
check_repl_delay=0
hostname=192.168.80.25
port=3306

[server3]
hostname=192.168.80.30
port=3306
_____________________________________配置文件解释————————————————————————————————————---
[server default]
manager_log=/var/log/masterha/app1/manager.log       #manager日志
manager_workdir=/var/log/masterha/app1.log         #manager工作目录
master_binlog_dir=/usr/local/mysql/data/          #master保存binlog的位置,这里的路径要与master里配置的binlog的路径一致,以便MHA能找到
master_ip_failover_script=/usr/local/bin/master_ip_failover  #设置自动failover时候的切换脚本,也就是上面的那个脚本
master_ip_online_change_script=/usr/local/bin/master_ip_online_change  #设置手动切换时候的切换脚本
password=manager            #设置mysql中root用户的密码,这个密码是前文中创建监控用户的那个密码
ping_interval=1             #设置监控主库,发送ping包的时间间隔,默认是3秒,尝试三次没有回应的时候自动进行failover
remote_workdir=/tmp         #设置远端mysql在发生切换时binlog的保存位置
repl_password=123           #设置复制用户的密码
repl_user=myslave           #设置复制用户的用户
report_script=/usr/local/send_report     #设置发生切换后发送的报警的脚本
secondary_check_script=/usr/local/bin/masterha_secondary_check -s 192.168.80.20 -s 192.168.80.30    #指定检查的从服务器IP地址
shutdown_script=""          #设置故障发生后关闭故障主机脚本(该脚本的主要作用是关闭主机防止发生脑裂,这里没有使用)
ssh_user=root               #设置ssh的登录用户名
user=mha                    #设置监控用户root

[server1]
hostname=192.168.80.10
port=3306

[server2]
hostname=192.168.80.20
port=3306
candidate_master=1
#设置为候选master,设置该参数以后,发生主从切换以后将会将此从库提升为主库,即使这个从库不是集群中最新的slave

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

[server3]
hostname=192.168.80.30
port=3306

9.第一次配置需要在 Master 节点上手动开启虚拟IP

/sbin/ifconfig ens33:1 192.168.80.200/24

10.在 manager 节点上测试 ssh 无密码认证,如果正常最后会输出 successfully,如下所示。

masterha_check_ssh -conf=/etc/masterha/app1.cnf

[root@localhost mha4mysql-manager-0.57]# masterha_check_ssh -conf=/etc/masterha/app1.cnf
Sat Jun 11 00:30:43 2022 - [warning] Global configuration file /etc/masterha_default.cnf not found. Skipping.

Sat Jun 11 00:30:43 2022 - [info] Reading application default configuration from /etc/masterha/app1.cnf..

Sat Jun 11 00:30:43 2022 - [info] Reading server configuration from /etc/masterha/app1.cnf..

Sat Jun 11 00:30:43 2022 - [info] Starting SSH connection tests..

Sat Jun 11 00:30:45 2022 - [debug]
.............................................................

Sat Jun 11 00:30:51 2022 - [info] All SSH connection tests passed successfully.

11.在 manager 节点上测试 mysql 主从连接情况,最后出现 MySQL Replication Health is OK 字样说明正常。如下所示。

masterha_check_repl -conf=/etc/masterha/app1.cnf
....................................

IN SCRIPT TEST====/sbin/ifconfig ens33:1 down==/sbin/ifconfig ens33:1 192.168.80.200===

Checking the Status of the script.. OK
Sat Jun 11 00:34:12 2022 - [info]  OK.

Sat Jun 11 00:34:12 2022 - [warning] shutdown_script is not defined.

Sat Jun 11 00:34:12 2022 - [info] Got exit code 0 (Not master dead).

MySQL Replication Health is OK.

12.在 manager 节点上启动 MHA

`bash
nohup masterha_manager –conf=/etc/masterha/app1.cnf –remove_dead_master_conf –ignore_last_failover < /dev/null > /var/log/masterha/app1/manager.log 2>&1 &

●使用&后台运行程序:结果会输出到终端;使用Ctrl+C发送SIGINT信号,程序免疫;关闭session发送SIGHUP信号,程序关闭。
●使用nohup运行程序:结果默认会输出到nohup.out;使用Ctrl+C发送SIGINT信号,程序关闭;关闭session发送SIGHUP信号,程序免疫。
●使用nohup和&配合来启动程序nohup ./test &:同时免疫SIGINT和SIGHUP信号。

Original: https://www.cnblogs.com/Canyun-blogs/p/16368975.html
Author: 残-云
Title: mysql-高可用架构:MHA

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/606876/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 我的第一个程序

    新建一个java文件 文件后缀名为.java Hello.java 【注意点】系统可能没有显示文件后缀名,我们需要手动代开 编写代码 public class Hello{    …

    Linux 2023年6月7日
    066
  • Linux系统编程—信号捕捉

    前面我们学习了信号产生的几种方式,而对于信号的处理有如下几种方式: 默认处理方式; 忽略; 捕捉。 信号的捕捉,说白了就是抓到一个信号后,执行我们指定的函数,或者执行我们指定的动作…

    Linux 2023年6月14日
    0123
  • burp通过条件竞争上传文件

    一·何为条件竞争现代框架更能抵御此类攻击。他们通常不会将文件直接上传到文件系统上的预期目的地。相反,他们采取了预防措施,例如首先上传到临时的沙盒目录并随机命名以避免覆盖现有文件。然…

    Linux 2023年6月7日
    089
  • phpweb成品网站最新版(注入、上传、写shell)

    注入:之所以鸡肋就是该漏洞利用安装文件 重新生成 配置文件 写入可执行代码 鸡肋1: 具有破坏性 动作非常大 重新写了配置文件 数据库连接文件鸡肋2: 有一定安全常识的站长都会删掉…

    Linux 2023年5月28日
    083
  • Harbor部署

    harbor 无论是使用Docker-distribution去自建仓库,还是通过官方镜像跑容器的方式去自建仓库,通过前面的演示我们可以发现其是非常的简陋的,还不如直接使用官方的D…

    Linux 2023年6月7日
    0106
  • Golang 实现 Redis(6): 实现 pipeline 模式的 redis 客户端

    本文是使用 golang 实现 redis 系列的第六篇, 将介绍如何实现一个 Pipeline 模式的 Redis 客户端。 通常 TCP 客户端的通信模式都是阻塞式的: 客户端…

    Linux 2023年5月28日
    085
  • list底层实现

    list和vector都是容器,只不过他们的存储结构不同,vector实际底层结构是顺序表,支持随机访问。list的底层结构带头双向链表,不支持随机访问。 但list的底层实现不同…

    Linux 2023年6月13日
    0106
  • 外键,查询关键字

    目录 自增特性 约束条件之外键 *查询关键字 内容 自增特性 自增不会随着数据的删除而回退 删除数据但无法重置主键 truncate 删除数据并重置主键值 约束条件之外键 简介 给…

    Linux 2023年6月7日
    0100
  • [转帖]shell 学习之until语句

    404. 抱歉,您访问的资源不存在。 可能是网址有误,或者对应的内容被删除,或者处于私有状态。 代码改变世界,联系邮箱 contact@cnblogs.com 园子的商业化努力-困…

    Linux 2023年5月28日
    0105
  • 四大高阶函数、匿名函数、递归

    四大高阶函数: map、reduce、filter、sorted 1.map函数: 根据提供的函数对指定序列做映射 使用可迭代对象(指定的序列)中的每个元素调用函数,将返回值作为新…

    Linux 2023年6月8日
    0112
  • 【微服务】Nacos初体验

    SpringCloud – Nacos初体验 😄生命不息,写作不止🔥 继续踏上学习之路,学之分享笔记👊 总有一天我也能像各位大佬一样🏆 一个有梦有戏的人 @怒放吧德德🌝…

    Linux 2023年6月6日
    0116
  • 建表参数PCTFREE、PCTUSED、INITRANS和MAXTRANS释疑

    PCTFREE与PCTUSED建表时可以指定以上两个参数的值(整数),PCTFREE表示一个块中保留的剩余空间大小百分比,该保留空间主要用于已有记录的更 新操作;PCTUSED表示…

    Linux 2023年6月14日
    089
  • 白话TCP/IP原理

    TCP/IP(Transmission-Control-Protocol/Internet-Protocol),中文译名为传输控制协议/因特网互联协议,又名网络通讯协议,是Inte…

    Linux 2023年5月27日
    0101
  • 如何写出有效的单元测试

    测试不要名不副实避免测试的描述与测试内容不符;测试结果必须精准;测试该失败的时候一定要失败! 测试私有或者受保护的方法解决思路: 将方法变成公共方法; 将方法抽取到新类; 将方法变…

    Linux 2023年6月8日
    0104
  • Java使用Redis删除指定前缀Key

    Java使用Redis删除指定前缀Key // 获取Redis中特定前缀 Set keys = stringRedisTemplate.keys("BLOG_SORT_B…

    Linux 2023年5月28日
    094
  • js中对象深度拷贝的方法(浅拷贝)

    JS中,一般的赋值传递的都是对象/数组的引用,并没有真正的深拷贝一个对象(浅拷贝),某些情况下需要用到深度拷贝,可以使用如下写法 let data = {username:&quo…

    Linux 2023年6月14日
    0100
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球