MySQL MHA高可用原理与部署(Master High Availability)

MySQL-MHA简介:

当master出现故障时,它可以自动将最新数据的slave提升为新的master,然后将所有其他slave重新指向新的master。

  • MHA(Master High Availability)目前在MySQL高可用方面是一个相对成熟的解决方案,它由日本DeNA公司youshimaton(现就职于Facebook公司)开发,是一套优秀的作为MySQL高可用性环境下故障切换和主从提升的高可用软件。在MySQL故障切换过程中,MHA能做到在0~30秒之内自动完成数据库的故障切换操作,并且在进行故障切换的过程中,MHA能在最大程度上保证数据的一致性,以达到真正意义上的高可用。

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

自动故障检测和自动故障转移:
  • MHA能够在一个已经存在的复制环境中监控MySQL,当检测到Master故障后能够实现 自动故障转移,通过鉴定出最“新”的Salve的relay log,并将其应用到所有的Slave,这样MHA就能够保证各个slave之间的数据一致性,即使有些slave在主库崩溃时还没有收到最新的relay log事件。一个slave节点能否成为候选的主节点可通过在配置文件中配 置它的优先级。由于master能够保证各个slave之间的数据一致性,所以所有的slave节 点都有希望成为主节点。在通常的replication环境中由于复制中断而极容易产生的数据 一致性问题,在MHA中将不会发生
交互式(手动)故障转移:
  • MHA可以手动地实现故障转移,而不必去理会master的状态,即不监控master状态,确认故障发生后可通过MHA手动切换。
在线切换Master到不同的主机:
  • MHA能够在0.5-2秒内实现切换,0.5-2秒的写阻塞通常是可接受的,所以你甚至能在非维护期间就在线切换master。诸如升级到高版本,升级到更快的服务器之类的工作,将会变得更容易。
MHA优点总结:
1)Masterfailover and slave promotion can be done very quickly
自动故障转移快

2)Mastercrash does not result in data inconsistency
主库崩溃不存在数据一致性问题

3)Noneed to modify current MySQL settings (MHA works with regular MySQL)
不需要对当前mysql环境做重大修改

4)Noneed to increase lots of servers
不需要添加额外的服务器(仅一台manager就可管理上百个replication)

5)Noperformance penalty
性能优秀,可工作在半同步复制和异步复制,当监控mysql状态时,仅需要每隔N秒向master发送ping包(默认3秒),所以对性能无影响。你可以理解为MHA的性能和简单的主从复制框架性能一样。

6)Works with any storage engine
只要replication支持的存储引擎,MHA都支持,不会局限于innodb
MHA的组成:
  • MHA由Manager节点和Node节点组成

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

MHA工作流程:
  • 从宕机崩溃的master保存二进制日志事件(binlog events);

  • 识别含有最新更新的slave;

  • 应用差异的中继日志(relay log)到其他的slave;

  • 应用从master保存的二进制日志事件(binlog events);

  • 提升一个slave为新的master;

  • 使其他的slave连接新的master进行复制;

1)保存master节点上所有的binlog事件
2)找到拥有最新relay-log的slave节点
3)将拥有最新relay-log上的数据同步到其他slave节点
4)将拥有最新数据的slave节点提升为master角色
5)根据旧master几点上的binlog日志,补全新master节点上的数据
6)将其他slave重新指向新master节点,开启主从同步

MHA高可用架构:
1)MHA是C/S架构的服务
2)MHA可以管理多套集群
3)每台机器都要安装node包
4)manager可以装在任意一台服务器(尽量避免安装在主库)

MHA高可用工具介绍:
tar zxf mha4mysql-manager-0.57.tar.gz && cd mha4mysql-manager-0.57/bin/

[root@mysql bin]# ll -sh
total 40K
4.0K -rwxr-xr-x 1 1001 1001 2.0K May 31  2015 masterha_check_repl              检查replication主从复制
4.0K -rwxr-xr-x 1 1001 1001 1.8K May 31  2015 masterha_check_ssh               检查ssh-key
4.0K -rwxr-xr-x 1 1001 1001 1.9K May 31  2015 masterha_check_status            查看MHA启动状态
4.0K -rwxr-xr-x 1 1001 1001 3.2K May 31  2015 masterha_conf_host               添加与删除MHA配置文件中主机信息
4.0K -rwxr-xr-x 1 1001 1001 2.5K May 31  2015 masterha_manager                 启动MHA集群
4.0K -rwxr-xr-x 1 1001 1001 2.2K May 31  2015 masterha_master_monitor          检测主库心跳连接
4.0K -rwxr-xr-x 1 1001 1001 2.4K May 31  2015 masterha_master_switch           切换数据库主从角色(故障转移)
8.0K -rwxr-xr-x 1 1001 1001 5.1K May 31  2015 masterha_secondary_check         建立TCP连接到远程服务器
4.0K -rwxr-xr-x 1 1001 1001 1.7K May 31  2015 masterha_stop                    停止MHA集群
tar zxf mha4mysql-node-0.57.tar.gz && cd mha4mysql-node-0.57/bin/

[root@mysql bin]# ll -sh
total 44K
 16K -rwxr-xr-x 1 1001 1001  16K May 31  2015 apply_diff_relay_logs            对比从库的relaylog日志
8.0K -rwxr-xr-x 1 1001 1001 4.7K May 31  2015 filter_mysqlbinlog               防止数据前滚或回滚(redo与undo)
 12K -rwxr-xr-x 1 1001 1001 8.1K May 31  2015 purge_relay_logs                 配置relaylog执行SQL语句后也不删除日志
8.0K -rwxr-xr-x 1 1001 1001 7.4K May 31  2015 save_binary_logs                 保存宕机master的binlog日志

MHA-部署-5.7-8.0通用版本:

当前环境架构图:
  • 当前GTID主从复制模式

配置别名解析:
  • 所有节点
cat >> /etc/hosts <<EOF
172.18.1.76  db01
172.18.1.77  db02
172.18.1.78  db03
172.18.1.79  mha-manager
EOF
下载并安装MHA-node包:
[root@db01 ~]# yum install epel-release -y
[root@db01 ~]# yum install -y perl-DBD-MySQL
[root@db01 ~]# wget https://github.com/yoshinorim/mha4mysql-node/releases/download/v0.58/mha4mysql-node-0.58-0.el7.centos.noarch.rpm
[root@db01 ~]# rpm -ivh mha4mysql-node-0.58-0.el7.centos.noarch.rpm 
Preparing...                          ################################# [100%]
Updating / installing...
   1:mha4mysql-node-0.58-0.el7.centos ################################# [100%]
下载并安装MHA-manager包:
  • MHA-manager管理监控节点安装 manager软件包
[root@mha-manager ~]# yum install epel-release -y
[root@mha-manager ~]# yum install perl-DBD-MySQL perl-Config-Tiny perl-Log-Dispatch perl-Parallel-ForkManager -y
[root@mha-manager ~]# wget https://github.com/yoshinorim/mha4mysql-manager/releases/download/v0.58/mha4mysql-manager-0.58-0.el7.centos.noarch.rpm
[root@mha-manager ~]# rpm -ivh mha4mysql-manager-0.58-0.el7.centos.noarch.rpm
Preparing...                          ################################# [100%]
Updating / installing...
   1:mha4mysql-manager-0.58-0.el7.cent################################# [100%]
创建MHA配置文件:
  • MHA-manager管理监控节点创建配置文件
[root@mha-manager ~]# vim /etc/app1.cnf

[server default]
user=root                                            # 连接MySQL的用户
password=123456                                      # 连接MySQL的用户密码
ssh_user=root                                        # 连接node节点的 SSH端口
manager_workdir=/var/log/masterha/app1               # MHA的工作目录
remote_workdir=/var/log/masterha/app1                # 被拉取MySQL主库的binlog日志文件存储位置
repl_user=rep                                        # 主从复制的用户
repl_password=123456                                 # 主从复制的用户密码
[server1]                                            # 第一个 MySQL node节点标签
hostname=db01                                        # 主机名 ( hosts 别名 )
port=3306                                            # node节点的 MySQL端口号
master_binlog_dir=/usr/local/mysql-8.0.16/data       # node节点的 MySQL 二进制日志文件存放路径
[server2]                                            # 第二个 MySQL node节点标签
hostname=db02                                        # 主机名 ( hosts 别名 )
port=3306                                            # node节点的 MySQL端口号
master_binlog_dir=/usr/local/mysql-8.0.16/data       # node节点的 MySQL 二进制日志文件存放路径
[server3]                                            # 第三个 MySQL node节点标签
hostname=db03                                        # 主机名 ( hosts 别名 )
port=3306                                            # node节点的 MySQL端口号
master_binlog_dir=/usr/local/mysql-8.0.16/data       # node节点的 MySQL 二进制日志文件存放路径
关闭MySQL自动清理日志:
  • 所有MySQL复制集群节点都要关闭自动清理日志功能。
[root@db01 ~]# vim /etc/my.cnf
[mysqld]
relay_log_purge=0

[root@db01 ~]# systemctl restart mysqld
配置无密码登录:
  • 所有MySQL复制集群节点Manager节点都要无密码登录。
ssh-keygen -t rsa -P "" -f ~/.ssh/id_rsa

ssh-copy-id root@mha-manager
ssh-copy-id root@db01
ssh-copy-id root@db02
ssh-copy-id root@db03
创建mysql命令软链接:
  • 所有节点
# 创建MHA工作目录
mkdir -p /var/log/masterha/app1

# 一切以MySQL路劲为准,但必须是 /usr/bin目录下
ln -s /usr/local/mysql-8.0.16/bin/mysqlbinlog /usr/bin/mysqlbinlog 
ln -s /usr/local/mysql-8.0.16/bin/mysql /usr/bin/mysql
检测SSH连接是否配置正常:
  • Manager节点
[root@mha-manager ~]# masterha_check_ssh --conf=/etc/app1.cnf
Mon Nov  4 10:56:51 2019 - [warning] Global configuration file /etc/masterha_default.cnf not found. Skipping.
Mon Nov  4 10:56:51 2019 - [info] Reading application default configuration from /etc/app1.cnf..
Mon Nov  4 10:56:51 2019 - [info] Reading server configuration from /etc/app1.cnf..
Mon Nov  4 10:56:51 2019 - [info] Starting SSH connection tests..
Mon Nov  4 10:56:52 2019 - [debug] 
Mon Nov  4 10:56:51 2019 - [debug]  Connecting via SSH from root@db01(172.18.1.76:22) to root@db02(172.18.1.77:22)..
Mon Nov  4 10:56:51 2019 - [debug]   ok.
Mon Nov  4 10:56:51 2019 - [debug]  Connecting via SSH from root@db01(172.18.1.76:22) to root@db03(172.18.1.78:22)..
Mon Nov  4 10:56:51 2019 - [debug]   ok.
Mon Nov  4 10:56:52 2019 - [debug] 
Mon Nov  4 10:56:51 2019 - [debug]  Connecting via SSH from root@db02(172.18.1.77:22) to root@db01(172.18.1.76:22)..
Mon Nov  4 10:56:52 2019 - [debug]   ok.
Mon Nov  4 10:56:52 2019 - [debug]  Connecting via SSH from root@db02(172.18.1.77:22) to root@db03(172.18.1.78:22)..
Mon Nov  4 10:56:52 2019 - [debug]   ok.
Mon Nov  4 10:56:53 2019 - [debug] 
Mon Nov  4 10:56:52 2019 - [debug]  Connecting via SSH from root@db03(172.18.1.78:22) to root@db01(172.18.1.76:22)..
Mon Nov  4 10:56:52 2019 - [debug]   ok.
Mon Nov  4 10:56:52 2019 - [debug]  Connecting via SSH from root@db03(172.18.1.78:22) to root@db02(172.18.1.77:22)..
Mon Nov  4 10:56:52 2019 - [debug]   ok.
Mon Nov  4 10:56:53 2019 - [info] All SSH connection tests passed successfully.
检测主从复制是否正确配置:
  • Manager节点
[root@mha-manager ~]# masterha_check_repl --conf=/etc/app1.cnf
Mon Nov  4 11:20:52 2019 - [warning] Global configuration file /etc/masterha_default.cnf not found. Skipping.
Mon Nov  4 11:20:52 2019 - [info] Reading application default configuration from /etc/app1.cnf..
Mon Nov  4 11:20:52 2019 - [info] Reading server configuration from /etc/app1.cnf..
Mon Nov  4 11:20:52 2019 - [info] MHA::MasterMonitor version 0.58.
Mon Nov  4 11:20:53 2019 - [info] GTID failover mode = 1
Mon Nov  4 11:20:53 2019 - [info] Dead Servers:
Mon Nov  4 11:20:53 2019 - [info] Alive Servers:
Mon Nov  4 11:20:53 2019 - [info]   db01(172.18.1.76:3306)
Mon Nov  4 11:20:53 2019 - [info]   db02(172.18.1.77:3306)
Mon Nov  4 11:20:53 2019 - [info]   db03(172.18.1.78:3306)
Mon Nov  4 11:20:53 2019 - [info] Alive Slaves:
Mon Nov  4 11:20:53 2019 - [info]   db02(172.18.1.77:3306)  Version=8.0.16 (oldest major version between slaves) log-bin:enabled
Mon Nov  4 11:20:53 2019 - [info]     GTID ON
Mon Nov  4 11:20:53 2019 - [info]     Replicating from 172.18.1.76(172.18.1.76:3306)
Mon Nov  4 11:20:53 2019 - [info]   db03(172.18.1.78:3306)  Version=8.0.16 (oldest major version between slaves) log-bin:enabled
Mon Nov  4 11:20:53 2019 - [info]     GTID ON
Mon Nov  4 11:20:53 2019 - [info]     Replicating from 172.18.1.76(172.18.1.76:3306)
Mon Nov  4 11:20:53 2019 - [info] Current Alive Master: db01(172.18.1.76:3306)
Mon Nov  4 11:20:53 2019 - [info] Checking slave configurations..
Mon Nov  4 11:20:53 2019 - [info]  read_only=1 is not set on slave db02(172.18.1.77:3306).
Mon Nov  4 11:20:53 2019 - [info]  read_only=1 is not set on slave db03(172.18.1.78:3306).
Mon Nov  4 11:20:53 2019 - [info] Checking replication filtering settings..
Mon Nov  4 11:20:53 2019 - [info]  binlog_do_db= , binlog_ignore_db= 
Mon Nov  4 11:20:53 2019 - [info]  Replication filtering check ok.
Mon Nov  4 11:20:53 2019 - [info] GTID (with auto-pos) is supported. Skipping all SSH and Node package checking.
Mon Nov  4 11:20:53 2019 - [info] Checking SSH publickey authentication settings on the current master..
Mon Nov  4 11:20:53 2019 - [info] HealthCheck: SSH to db01 is reachable.
Mon Nov  4 11:20:53 2019 - [info] 
db01(172.18.1.76:3306) (current master)
 +--db02(172.18.1.77:3306)
 +--db03(172.18.1.78:3306)

Mon Nov  4 11:20:53 2019 - [info] Checking replication health on db02..
Mon Nov  4 11:20:53 2019 - [info]  ok.
Mon Nov  4 11:20:53 2019 - [info] Checking replication health on db03..
Mon Nov  4 11:20:53 2019 - [info]  ok.
Mon Nov  4 11:20:53 2019 - [warning] master_ip_failover_script is not defined.
Mon Nov  4 11:20:53 2019 - [warning] shutdown_script is not defined.
Mon Nov  4 11:20:53 2019 - [info] Got exit code 0 (Not master dead).

MySQL Replication Health is OK.
启动MHA管理节点:
  • Manager节点
[root@mha-manager ~]# cat /usr/bin/application_mha
#!/bin/bash
mha_log='/var/log/masterha/app1/mha_manager.log'
mha_cnf='/etc/app1.cnf'

mha_start () {
        mha_processpid=`ps -ef |grep masterha_manager |grep -cv grep`
        if [ ${mha_processpid} -eq 0 ]; then
                nohup masterha_manager --conf=${mha_cnf} > ${mha_log} < /dev/null &
        fi
}

mha_stop () {
        mha_processpid=`ps -ef |grep masterha_manager |grep -cv grep`
        if [ ${mha_processpid} -eq 1 ]; then
                masterha_stop --conf=${mha_cnf} > /dev/null 2>&1
        fi
}

mha_status () {
        mha_processpid=`ps -ef |grep masterha_manager |grep -cv grep`
        if [ ${mha_processpid} -eq 1 ]; then
                echo -e "\033[32mMHA is running ! \033[0m"
                masterha_check_status --conf=${mha_cnf}
        else
                echo -e "\033[31mMHA has stopped ! \033[0m"
                masterha_check_status --conf=${mha_cnf}
        fi
}

case "$1" in
    start)
    mha_start
    ;;
    stop)
    mha_stop
    ;;
    status)
    mha_status
    ;;
    *)
    echo "USAGE:$0 {start|stop|status}"
esac

[root@mha-manager ~]# chmod +x /usr/bin/application_mha
[root@mha-manager ~]# application_mha start

测试MHA主从复制高可用:
  • MySQL主库执行
[root@db01 ~]# systemctl stop mysqld
[root@mha-manager ~]# tail -f /var/log/masterha/app1/mha_manager.log
  • 查看MHA-manager服务日志

MHA其他操作:

MHA手动故障切换:
  • Manager节点
# 指定老主库状态为dead
# 指定MHA配置文件
# 老主库的主机名
# 老主库的端口
# 新主库的主机名
# 新主库的端口
[root@mha-manager ~]# masterha_master_switch --master_state=dead --conf=/etc/app1.cnf --dead_master_host=db01 --dead_master_port=3306 --new_master_ip=db02 --new_master_port=3306
MHA手动在线切换:
  • Manager节点

  • -orig_master_is_new_slave 切换时加上此参数是将原 master 变为 slave 节点,如果不加此参数,原来的 master 将不启动。

  • --running_updates_limit=10000,故障切换时,候选master 如果有延迟的话, mha 切换不能成 功,加上此参数表示延迟在此时间范围内都可切换(单位为s),但是切换的时间长短是由recover 时relay 日志的大小决定。

# 指定老主库状态为alive
# 指定新master的主机名
# 指定新master的端口
# 执行老master变为slave状态
# 指定`接受`新master 与 master的延迟时间是10000秒(当延迟大于10000秒是MHA切换失败)
[root@mha-manager ~]# masterha_master_switch --conf=/etc/app1.cnf --master_state=alive --new_master_host=db02 --new_master_port=3306 --orig_master_is_new_slave --running_updates_limit=10000
配置在线MHA VIP漂移:
  • Manager节点

  • 不要忘记修改VIP地址网卡名称

  • 第一次使用MHA-VIP功能时要先在Master节点开启VIP,然后再启动MHA服务。

  • 也就是 MHA在启动时不会创建 VIP,只会在切换时进行老Master VIP删除,新Master VIP创建。

#在[server default]模块下添加VIP漂移参数
[root@db01 ~]# vim /etc/app1.cnf

master_ip_failover_script=/usr/bin/master_ip_failover       # 代表执行该脚本
# 创建 VIP 漂移脚本
[root@db01 ~]# yum -y install net-tools
[root@db01 ~]# vim /usr/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 = '10.0.0.250/24';
my $key = '0';
my $ssh_start_vip = "/sbin/ifconfig eth0:$key $vip";
my $ssh_stop_vip = "/sbin/ifconfig eth0:$key down";

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

[root@db01 ~]# chmod +x /usr/bin/master_ip_failover
[root@db01 app1]# ifconfig eth0:0 10.0.0.250/24
[root@db01 app1]# application_mha start

# MHA启动后要自动生成该文件才可以实现高可用
[root@db01 app1]# ll -sh /var/log/masterha/app1/app1.master_status.health 
4.0K -rw-r--r--. 1 root root 27 Dec  3 10:24 /var/log/masterha/app1/app1.master_status.health

# 停止 MySQL Master节点,MHA自动检测后进行故障切换
[root@db01 app1]# systemctl stop mysqld

配置在线MHA Binlog服务器:

- db03节点

- 本次db03节点作为 binlog-server,永远不可以为 Master节点。

先决条件
- 实时备份master节点的binlog
- 可以在任意一台服务器上
- 一定要有mysql客户端命令(mysqlbinlog)

- 不可用

# binlog server创建 binlog日志存放路径
[root@db03 ~]# mkdir -p /mnt/mysql_binlog
# 增加binlog server服务器配置信息
[root@db01 ~]# vim /etc/app1.cnf

[binlog1]
no_master=1                              # 当前binlog节点永远不成为master
hostname=db03
master_binlog_dir=/mnt/mysql_binlog      # 日志存储到binlog server服务器的本地路径
「点点赞赏,手留余香」

    还没有人赞赏,快来当第一个赞赏的人吧!
0 条回复 A 作者 M 管理员
    所有的伟大,都源于一个勇敢的开始!
欢迎您,新朋友,感谢参与互动!欢迎您 {{author}},您在本站有{{commentsCount}}条评论