lnmp 九之mysql数据库MHA高可用

MHA集群

MHA简介

传统的主从复制如果主库宕机,其余从库不会自动的代替主库继续工作,这样就不能保证业务的高可用,而MHA就是一个mysql主从复制高可用的解决方案,当主库宕机后,MHA能在1-30秒实现故障检测和故障自动转移,选择一个最优的从库作为主库,同时新的主库还继续与其他从库保持数据一致的状态。
在这里插入图片描述

MHA与MGR

MHA是外部的基于mysql主从半同步开发的一套高可用切换方案,它并不属于mysql内核,独立于mysql存在于外围,MHA重点在切换,可以理解为一套切换工具。而MGR存在于mysql内核层面,是内核层面数据强一致方案,它的重点在高可用强一致,如果将MGR用在生产环境中,那么针对MGR,还需要开发一套监控及切换方案,而MHA将这一整套切换方案vip之类的都考虑进去了。

MHA组成

MHA 服务有两种角色, MHA Manager(管理节点)和 MHA Node(数据节点)。

  • MHA Manager:通常单独部署在一台独立机器上管理多个 master/slave 集群(组),每个 master/slave 集群称作一个 application,用来管理统筹整个集群。
  • MHA Node:运行在每台 MySQL 服务器上(master/slave/manager),它通过监控具备解析和清理logs功能的脚本来加快故障转移。

MHA Manager服务器会定时通过主库上的MHA Node检测主库的运行状态,当主库出现故障时他可以将最优从库(可以提前指定或者由MHA判定)提升为新的主库,然后其他从库和新的主库重新保持新的复制状态。

MHA工作原理

  • 主库实例挂掉但是ssh还能连接
    (1)监控到主库宕机,选择一个新主,被选择的新主会取消从库的角色( reset slave)
    选择标准:
    一是根据其他从库的binlog日志的位置选择最新的从库作为新的主库
    二是如果设置了半同步从库,直接选择半同步从库作为新的主库
    (2)从库通过MHA自带的脚本程序,通过ssh向主库索取缺失部分的binlog
    (3)其他从库与新的主库重新构建主从,继续提供服务
    (4)如果由vip机制,将vip从原来的主库漂移到新的主库,让应用无感知
  • 主节点服务器宕机(ssh已经连接不上了)
    (1)监控到主机宕机后,尝试ssh连接,连接失败
    (2)通过上边所讲的选择标准选择新的主库
    (3)计算从库之间的relay-log的差异,补偿到新的其他从库
    (4)其他从库重新与新主构建主从关系,继续提供服务
    (5)如果由VIP机制,将VIP从原主漂移到新主,让应用无感知
    (6)如果有binlog server机制,会继续将binlog server中缺失的事物,补偿到新的主库

MHA实现

四台虚拟机,三台做node(一主二从),一台做manager。
server1:主
server2、server3:从
server4:manager

MHA工具包介绍
Manager工具包主要包括以下几个工具:
	masterha_check_ssh           #检查MHA的SSH配置状况
    masterha_check_repl          #检查MySQL复制状况	
    masterha_manger              #启动MHA
    masterha_check_status        #检测当前MHA运行状态
    masterha_master_monitor      #检测master是否宕机
    masterha_master_switch       #控制故障转移(自动或者手动)
    masterha_conf_host           #添加或删除配置的server信息

Node工具包(由MHA Manager的脚本触发,无需人为操作)主要包括以下几个工具:
	save_binary_logs             #保存和复制master的二进制日志
	apply_diff_relay_logs        #识别差异的中继日志事件并将其差异的事件应用于其他的slave
	filter_mysqlbinlog           #去除不必要的ROLLBACK事件(MHA已不再使用这个工具)
	purge_relay_logs             #清除中继日志(不会阻塞SQL线程)

主(server1)的配置

/etc/init.d/mysqld stop
rm -fr /data/mysql/*
vim /etc/my.cnf
[mysqld]
 basedir=/usr/local/mysql
 datadir=/data/mysql
 socket=/data/mysql/mysql.sock

 server-id=1                    #实现功能的重要参数
 default_authentication_plugin=mysql_native_password
 gtid_mode=ON
 enforce-gtid-consistency=ON
 master_info_repository=TABLE
 relay_log_info_repository=TABLE  
 log_slave_updates=ON
 log_bin=binlog                 #实现功能的重要参数
 binlog_format=ROW 

mysqld --initialize --user=mysql
/etc/init.d/mysqld start 
mysql -p
mysql> alter user root@localhost identified by '123456';
mysql> CREATE USER repl@'%' IDENTIFIED BY '123456';  #在mysql8中grant语句要分为两句
mysql> GRANT REPLICATION SLAVE ON *.* TO repl@'%';   #在mysql8中grant语句要分为两句
mysql> show master status; 

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

node从(server2、3)的设置

和server1配置类似,这里以server2为例子

/etc/init.d/mysqld stop
rm -fr /data/mysql/*
vim /etc/my.cnf
[mysqld]
 basedir=/usr/local/mysql
 datadir=/data/mysql
 socket=/data/mysql/mysql.sock

 server-id=2                    #实现功能的重要参数
 default_authentication_plugin=mysql_native_password
 gtid_mode=ON
 enforce-gtid-consistency=ON
 master_info_repository=TABLE
 relay_log_info_repository=TABLE  
 log_slave_updates=ON
 log_bin=binlog                 #实现功能的重要参数
 binlog_format=ROW 

mysqld --initialize --user=mysql
/etc/init.d/mysqld start 
mysql -p
mysql> alter user root@localhost identified by '123456';
mysql> CHANGE MASTER TO MASTER_HOST='192.168.1.10',MASTER_USER='repl',MASTER_PASSWORD='123456',MASTER_AUTO_POSITION=1;
mysql> start slave;
mysql> show slave status\G; 

以同样的方式配置server3

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
开始配置server3
在这里插入图片描述

MHA Manager(server4)部署

centos软件包下载官网
rpm软件包下载官网

1.首先停止server4之前安装的mysql路由服务
systemctl stop mysqlrouter.service

2.配置4个节点间的免密
ssh-keygen
ssh-copy-id server1
ssh-copy-id server2
ssh-copy-id server3
scp -r .ssh/ server1:
scp -r .ssh/ server2:
scp -r .ssh/ server3:

3.在server4上下载软件并将node包发送给其他节点(如果在线下载的话如下,其实我这里离线包都全部准备好了)
wget https://github.com/yoshinorim/mha4mysql-manager/releases/download/v0.58/mha4mysql-manager-0.58-0.el7.centos.noarch.rpm
wget https://github.com/yoshinorim/mha4mysql-node/releases/download/v0.58/mha4mysql-node-0.58-0.el7.centos.noarch.rpm
scp mha4mysql-node-0.58-0.el7.centos.noarch.rpm server1:
scp mha4mysql-node-0.58-0.el7.centos.noarch.rpm server2:
scp mha4mysql-node-0.58-0.el7.centos.noarch.rpm server3:

4.server1、2、3安装node rpm包
yum install -y mha4mysql-node-0.58-0.el7.centos.noarch.rpm

5.server4安装软件包及依赖
cd MHA-7
ls
mha4mysql-manager-0.58-0.el7.centos.noarch.rpm
mha4mysql-manager-0.58.tar.gz
mha4mysql-node-0.58-0.el7.centos.noarch.rpm
perl-Config-Tiny-2.14-7.el7.noarch.rpm
perl-Email-Date-Format-1.002-15.el7.noarch.rpm
perl-Log-Dispatch-2.41-1.el7.1.noarch.rpm
perl-Mail-Sender-0.8.23-1.el7.noarch.rpm
perl-Mail-Sendmail-0.79-21.el7.noarch.rpm
perl-MIME-Lite-3.030-1.el7.noarch.rpm
perl-MIME-Types-1.38-2.el7.noarch.rpm
perl-Net-Telnet-3.03-19.el7.noarch.rpm
perl-Parallel-ForkManager-1.18-2.el7.noarch.rpm
yum install -y *.rpm

注意:需要有这个repo文件
vim CentOS-Base.repo
[base]
name=CentOS-7 - Base - mirrors.aliyun.com
failovermethod=priority
baseurl=http://mirrors.aliyun.com/centos/7/os/$basearch/
gpgcheck=1
gpgkey=http://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-7

#released updates 
[updates]
name=CentOS-7 - Updates - mirrors.aliyun.com
failovermethod=priority
baseurl=http://mirrors.aliyun.com/centos/7/updates/$basearch/
gpgcheck=1
gpgkey=http://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-7

#additional packages that may be useful
[extras]
name=CentOS-7 - Extras - mirrors.aliyun.com
failovermethod=priority
baseurl=http://mirrors.aliyun.com/centos/7/extras/$basearch/
gpgcheck=1
gpgkey=http://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-7

#additional packages that extend functionality of existing packages
[centosplus]
name=CentOS-7 - Plus - mirrors.aliyun.com
failovermethod=priority
baseurl=http://mirrors.aliyun.com/centos/7/centosplus/$basearch/
gpgcheck=1
enabled=0
gpgkey=http://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-7

#contrib - packages by Centos Users
[contrib]
name=CentOS-7 - Contrib - mirrors.aliyun.com
failovermethod=priority
baseurl=http://mirrors.aliyun.com/centos/7/contrib/$basearch/
gpgcheck=1
enabled=0
gpgkey=http://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-7

6.解压MHA并新建目录(如果在线下载的话如下,其实我这里离线包都全部准备好了)
wget https://github.com/yoshinorim/mha4mysql-manager/releases/download/v0.58/mha4mysql-manager-0.58.tar.gz
tar zxf mha4mysql-manager-0.58.tar.gz
cd mha4mysql-manager-0.58
mkdir /etc/masterha 
cd samples/conf
cp app1.cnf /etc/masterha

7.修改配置文件
cd /etc/masterha
vim app1.cnf 
[server default]
user=root
password=123456
ssh_user=root
master_binlog_dir= /data/mysql
remote_workdir=/tmp
secondary_check_script= masterha_secondary_check -s 192.168.1.10 -s 192.168.1.11
ping_interval=3
# master_ip_failover_script= /script/masterha/master_ip_failover
# shutdown_script= /script/masterha/power_manager
# report_script= /script/masterha/send_report
# master_ip_online_change_script= /script/masterha/master_ip_online_change

manager_workdir=/etc/masterha/app1
manager_log=/var/log/masterha/app1/manager.log

repl_user=repl
repl_password=123456

[server1]
hostname=192.168.1.10

[server2]
hostname=192.168.1.11
candidate_master=1
check_repl_delay=0

[server3]
hostname=192.168.1.12

8.创建工作目录
mkdir app1      

9.测试SSH连接
masterha_check_ssh --conf=/etc/masterha/app1.cnf

10.在server1上创建root用户并授权
CREATE USER root@'%' IDENTIFIED BY '123456';
GRANT ALL ON *.* TO root@'%';
flush privileges;

11.测试主从复制情况
masterha_check_repl --conf=/etc/masterha/app1.cnf

配置免密,server2和server3类似
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在server4上安装
在这里插入图片描述
在这里插入图片描述
解压tar包并修改配置文件
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
测试ssh连接发现正常
在这里插入图片描述
在server1上创建用户并授权
在这里插入图片描述
检测主从复制情况
在这里插入图片描述
在这里插入图片描述
MHA部署成功
在这里插入图片描述

MHA高可用切换

MHA的故障切换过程,共包括以下的步骤:
1.配置文件检查阶段,这个阶段会检查整个集群配置文件配置
2.宕机的master处理,这个阶段包括虚拟ip摘除操作,主机关机操作
3.复制dead maste和最新slave相差的relay log,并保存到MHA Manger具体的目录下
4.识别含有最新更新的slave
5.应用从master保存的二进制日志事件(binlog events)
6.提升一个slave为新的master进行复制
7.使其他的slave连接新的master进行复制

MHA手动切换

具体实验步骤如下:

1.第一种:master存活状态下切换
在server4上执行
masterha_master_switch --conf=/etc/masterha/app1.cnf --master_state=alive --new_master_host=192.168.1.11 --new_master_port=3306 --orig_master_is_new_slave --running_updates_limit=10000
询问一路yes即可

2.第二种:master宕机状态下切换
将server2 mysql服务关闭
/etc/init.d/mysqld stop

在server4上执行下列语句
masterha_master_switch --master_state=dead --conf=/etc/masterha/app1.cnf --dead_master_host=192.168.1.11 --dead_master_port=3306 --new_master_host=192.168.1.10 --new_master_port=3306 --ignore_last_failover
# --ignore_last_failover 忽略最后一次的切换文件(在/etc/masterha/app目录下)
询问一路yes即可

将server2 mysql服务启动并加入服务
/etc/init.d/mysqld start

mysql -p
mysql> CHANGE MASTER TO MASTER_HOST='192.168.1.10',MASTER_USER='repl',MASTER_PASSWORD='123456',MASTER_AUTO_POSITION=1;
mysql> start slave;
mysql> show slave status\G; 

第一种方式
在这里插入图片描述
切换成功
在这里插入图片描述
第二种方式
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
将server2重新加入服务
在这里插入图片描述
在这里插入图片描述

MHA自动切换

为了保证数据完全一致性,在最快的时间内完成切换,MHA的在线切换必须满足以下条件才会切换成功,否则会切换失败。
1.所有slave的IO线程都在运行
2.所有slave的SQL线程都在运行
3.所有的show slave status的输出中Seconds_Behind_Master参数小于或者等于running_updates_limit秒,如果在切换过程中不指定running_updates_limit,那么默认情况下running_updates_limit为1秒。
4.在master端,通过show processlist输出,没有一个更新花费的时间大于running_updates_limit秒。

具体实验步骤如下:

1.将进程打入后台执行
mkdir -p /var/log/masterha/app1     #还需要新建日志目录(前面忘记了)
masterha_manager --conf=/etc/masterha/app1.cnf & 

2.关闭当前server1上master,自动切换到server2。
/etc/init.d/mysqld stop

3.将server1 mysql服务启动并加入服务
/etc/init.d/mysqld start

mysql -p
mysql> CHANGE MASTER TO MASTER_HOST='192.168.1.11',MASTER_USER='repl',MASTER_PASSWORD='123456',MASTER_AUTO_POSITION=1;
mysql> start slave;
mysql> show slave status\G; 

在这里插入图片描述
在这里插入图片描述
在server3上发现成功切换
在这里插入图片描述
将server1 mysql服务启动并加入服务
在这里插入图片描述
在这里插入图片描述

MHA的vip手动/自动切换

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.1.100/24';
my $ssh_start_vip = "/sbin/ip addr add $vip dev ens33";
my $ssh_stop_vip = "/sbin/ip addr del $vip dev ens33";

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";
}

master_ip_online_change文件

#!/usr/bin/env perl
use strict;  
use warnings FATAL =>'all';  
  
use Getopt::Long;  
  
my $vip = '192.168.1.100/24';
my $ssh_start_vip = "/sbin/ip addr add $vip dev ens33";
my $ssh_stop_vip = "/sbin/ip addr del $vip dev ens33";

my $exit_code = 0;  
  
my (  
  $command,              $orig_master_is_new_slave, $orig_master_host,  
  $orig_master_ip,       $orig_master_port,         $orig_master_user,  
  $orig_master_password, $orig_master_ssh_user,     $new_master_host,  
  $new_master_ip,        $new_master_port,          $new_master_user,  
  $new_master_password,  $new_master_ssh_user,  
);  
GetOptions(  
  'command=s'                => \$command,  
  'orig_master_is_new_slave' => \$orig_master_is_new_slave,  
  'orig_master_host=s'       => \$orig_master_host,  
  'orig_master_ip=s'         => \$orig_master_ip,  
  'orig_master_port=i'       => \$orig_master_port,  
  'orig_master_user=s'       => \$orig_master_user,  
  'orig_master_password=s'   => \$orig_master_password,  
  'orig_master_ssh_user=s'   => \$orig_master_ssh_user,  
  'new_master_host=s'        => \$new_master_host,  
  'new_master_ip=s'          => \$new_master_ip,  
  'new_master_port=i'        => \$new_master_port,  
  'new_master_user=s'        => \$new_master_user,  
  'new_master_password=s'    => \$new_master_password,  
  'new_master_ssh_user=s'    => \$new_master_ssh_user,  
);  
  
  
exit &main();  
  
sub main {  
  
#print "\n\nIN SCRIPT TEST====$ssh_stop_vip==$ssh_start_vip===\n\n";  
  
if ( $command eq "stop" || $command eq "stopssh" ) {  
  
        # $orig_master_host, $orig_master_ip, $orig_master_port are passed.  
        # If you manage master ip address at global catalog database,  
        # invalidate orig_master_ip here.  
        my $exit_code = 1;  
        eval {  
            print "\n\n\n***************************************************************\n";  
            print "Disabling the VIP - $vip on old master: $orig_master_host\n";  
            print "***************************************************************\n\n\n\n";  
&stop_vip();  
            $exit_code = 0;  
        };  
        if ($@) {  
            warn "Got Error: $@\n";  
            exit $exit_code;  
        }  
        exit $exit_code;  
}  
elsif ( $command eq "start" ) {  
  
        # all arguments are passed.  
        # If you manage master ip address at global catalog database,  
        # activate new_master_ip here.  
        # You can also grant write access (create user, set read_only=0, etc) here.  
my $exit_code = 10;  
        eval {  
            print "\n\n\n***************************************************************\n";  
            print "Enabling the VIP - $vip on new master: $new_master_host \n";  
            print "***************************************************************\n\n\n\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";  
        `ssh $orig_master_ssh_user\@$orig_master_host \" $ssh_start_vip \"`;  
        exit 0;  
}  
else {  
&usage();  
        exit 1;  
}  
}  
  
# A simple system call that enable the VIP on the new master  
sub start_vip() {  
`ssh $new_master_ssh_user\@$new_master_host \" $ssh_start_vip \"`;  
}  
# A simple system call that disable the VIP on the old_master  
sub stop_vip() {  
`ssh $orig_master_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";  
}

具体实验步骤如下

1.修改/etc/masterha/app1.cnf
vim /etc/masterha/app1.cnf
master_ip_failover_script= /etc/masterha/master_ip_failover       #手动切换脚本
master_ip_online_change_script= /etc/masterha/master_ip_online_change  #自动切换脚本

2.添加上述两个配置文件
看上面两个代码文件
vim master_ip_failover
vim master_ip_online_change

3.给两个配置文件加可执行权限
chmod +x master_ip_failover master_ip_online_change

4.测试
给master主机添加vip
ip addr add 192.168.1.100/24 dev ens33
ip addr show ens33

将进程打入后台执行
masterha_manager --conf=/etc/masterha/app1.cnf &

关闭当前server2上master,在server3上查看自动切换到server1上
/etc/init.d/mysqld stop
server3上
mysql> show slave status\G;

在server1上发现vip
ip addr show ens33

5.最后将server2手动加到集群中即可
/etc/init.d/mysqld start

mysql -p
mysql> CHANGE MASTER TO MASTER_HOST='192.168.1.10',MASTER_USER='repl',MASTER_PASSWORD='123456',MASTER_AUTO_POSITION=1;
mysql> start slave;
mysql> show slave status\G; 

修改 /etc/masterha/app1.cnf
在这里插入图片描述
在这里插入图片描述
添加上述两个配置文件
在这里插入图片描述
开始测试
在master上添加vip
在这里插入图片描述
在这里插入图片描述
关闭master
在这里插入图片描述
在server3上查看master已切换
在这里插入图片描述
在server1上发现vip
在这里插入图片描述
将server2手工加入集群
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值