Mysql之高可用MHA架构

1.  MHA架构

    1.  MHA介绍

        MHA全称(Master High Availability),由perl脚本开发的

        官网地址:https://github.com/yoshinorim

    2.  MHA提供的功能

        1.  监控主数据库服务器是否可用

        2.  当主数据库服务器不可用,从多个主服务器选出新的主数据库服务器

        3.  提供了主从切换和故障转移功能

    3.  MHA主从切换过程

        1.  尝试从出现故障的主数据库保存二进制文件

        2.  从多个备选从服务器选出新的备选主服务器

        3.  在备选主服务器和其他从服务器之间同步差异二进制数据

    4.  架构图

           

        最好是基于GTID的复制模式                    

    5.  MHA服务有两种角色:MHA Manager(管理节点)和MHA Node(数据节点)

        1.  MHA Manager:通常单独部署在独立服务器或者node节点上

        2.  MHA Node:运行在master/slave/manager

    6.  MHA组件

        1.  manager节点:

            masterha_check_ssh:  MHA依赖的SSH环境检测工具

            masterha_check_repl:  Mysql复制环境检测工具

            masterha_manager:  MHA服务主程序

            masterha_stop:  关闭MHA服务的工具

            masterha_check_status:  MHA运行状态探测工具

            masterha_master_monitor:  Mysql master节点可用性监测工具

            masterha_master_switch:  master节点切换工具

            masterha_conf_host:  添加或删除节点工具 

        2.  node节点

            save_binary_logs:  保存和复制master的二进制日志

            apply_diff_relay_logs:  识别差异的中继日志事件并应用于其他slave

            filter_mysqlbinlog:  去除不必要的ROLLBACK事件

            purge_relay_logs:  清除中继日志(不会阻塞sql进程)

        3.  自定义扩展

            secondary_check_script:  通过多条网络路由检测master的可用性

            master_ip_failover_script:  更新application的masterip

            shutdown_script:  强制关闭master节点

            report_script:  发送报告

            init_conf_load_script:  加载初始配置参数

            master_ip_online_change_script:  更新master节点ip地址

2.  MHA配置过程简要

    1.  配置集群内所有主机的SSH免认证登陆

    2.  安装MHA-node软件包和MHA-manager软件包

    3.  建立主从复制集群

    4.  配置MHA管理节点

    5.  使用masterha_check_ssh和masterha_check_repl对配置进行检验

    6.  启动并测试MHA服务

3.  MHA详细配置过程

    1.  环境准备

        主  192.168.1.200  node节点

        从  192.168.1.2  node节点

        从  192.168.1.210  node节点

        管理  192.168.1.185  manager节点

    2.  配置四台机器相互之间免认证登录

        使用root做四台机器的免认证登录

    3.  安装MHA-node软件包和MHA-manager软件包

        yum install perl-DBD-MySQL -y  安装依赖包

        官网下载node安装包(在所有节点都安装node包)

          https://github.com/yoshinorim/mha4mysql-node/releases/download/v0.58/mha4mysql-node-0.58-0.el7.centos.noarch.rpm

          rpm -ivh mha4mysql-node-0.58-0.el7.centos.noarch.rpm

        官网下载manager安装包(在管理节点安装)

          https://github.com/yoshinorim/mha4mysql-manager/releases/download/v0.58/mha4mysql-manager-0.58-0.el7.centos.noarch.rpm

          yum install -y perl-Config-Tiny epel-release perl-Log-Dispatch perl-Parallel-ForkManager perl-Time-HiRes

          rpm -ivh mha4mysql-manager-0.58-0.el7.centos.noarch.rpm                              

    4.  配置mysql主从复制集群

        1.  所有节点都开启bin-log和relay-log

        2.  初始化主节点配置

            server_id=1

            relay-log=/server/mysql/log/relay-log

            log-bin=mysql-bin

        3.  所有slave节点的配置

            server_id=2

            relay-log=/server/mysql/log/relay-log

            log-bin=mysql-bin

            relay_log_purge=0

            read_only=1

        4.  配置主从复制

            在所有节点创建用户,用来同步数据

            grant replication slave on *.* to 'rep'@'192.168.0.%' identified by '123';         

    5.  MHA配置

        1.  创建MHA配置目录

            mkdir /etc/mha

            下载一个mha-manager的tar包,将其中的scripts目录拷贝到/etc/mha目录下

            cp -r scripts /etc/mha/

            cp app1.cnf /etc/mha/

        2.  修改app1.cnf的内容

[server default]
manager_workdir=/var/log/masterha/app1  //设置manager的工作目录
manager_log=/var/log/masterha/app1/manager.log   //设置manager的日志

ssh_user=root     //ssh免密钥登录的账号名
ssh_port=11984
repl_user=rep //mysql复制帐号,用来在主从机之间同步二进制日志等 repl_password=123 //mysql复制账号的密码 ping_interval=1 //发送ping包的时间间隔,默认是3秒 master_ip_failover_script= /usr/local/bin/master_ip_failover //设置自动failover时候的切换脚本 master_ip_online_change_script= /usr/local/bin/master_ip_online_change //设置手动切换时候的切换脚本 user=root //用来管理mha的mysql用户
password=**** //管理mha的mysql用户的密码
[server1] hostname=host1 master_binlog_dir=/server/mysql/log/ //指定master的binlog的目录 candidate_master=1
[server2] hostname=host2 candidate_master=1 //设置为备用master [server3] hostname=host3 [server4] hostname=host4 no_master=1 //不允许成为master

        3.  检查ssl

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

            报错:因为我的服务器没有使用默认的22端口,所以需要修改一些配置

            /etc/mha/app1.cnf中添加:ssh_port=11984

        4.  检查repl

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

            报错:Tue Aug 23 16:19:25 2022 - [error][/usr/share/perl5/vendor_perl/MHA/Server.pm, ln180] Got MySQL error when connecting 192.168.2.191(192.168.2.191:3306) :1045:Access denied for user 'root'@'node3' (using password: NO), but this is not a MySQL crash. Check MySQL server settings.

            /etc/mha/app1.cnf中添加: 

              user=root
              password=*****

            

            再次执行,又出现新的报错:

              Can't exec "mysqlbinlog": 没有那个文件或目录 at /usr/share/perl5/vendor_perl/MHA/BinlogManager.pm line 106.

            在对应的服务器上执行:

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

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

 

            再次执行,又出现新的报错:Bareword "FIXME_xxx" not allowed while "strict subs" in use at /etc/mha/scripts/master_ip_failover l

            在脚本master_ip_failover中屏蔽:FIXME_xxx;

            

            再次执行,显示MySQL Replication Health is OK.

        5.  配置VIP

            1.  通过keepalive管理VIP

            2.  通过脚本方式管理VIP

                1.  在master上绑定VIP

                    ifconfig eth0:1 192.168.2.195

                2.  manager节点修改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.2.195/24';
my $key = '1';
#my $ssh_start_vip = "/sbin/ifconfig em2:$key $vip";      //注意网卡的名称
#my $ssh_stop_vip = "/sbin/ifconfig em2:$key down";
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();
         Replicate_Rewrite_DB: 
    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 -p11984 $ssh_user\@$new_master_host \" $ssh_start_vip \"`;    //注意ssh的端口
}
sub stop_vip() {
    return 0 unless ($ssh_user);
    `ssh -p11984 $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";
}                                                                                                                             

        6.  启动mha

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

            启动参数介绍:           

--remove_dead_master_conf      该参数代表当发生主从切换后,老的主库的ip将会从配置文件中移除。
--manger_log                   日志存放位置
--ignore_last_failover         在缺省情况下,如果MHA检测到连续发生宕机,且两次宕机间隔不足8小时的话,则不会进行Failover,之所以这样限制是为了
                               避免ping-pong效应。该参数代表忽略上次MHA触发切换产生的文件,默认情况下,MHA发生切换后会在日志目录,也就是上面我
                               设置的/data产生app1.failover.complete文件,下次再次切换的时候如果发现该目录下存在该文件将不允许触发切换,除非
                               在第一次切换后收到删除该文件,为了方便,这里设置为--ignore_last_failover。      

        7.  关闭mha

            masterha_stop --conf=/etc/mha/app1.cnf 

        8.  查看mha状态

            masterha_check_status --conf=/etc/mha/app1.cnf

4.  mha故障转移测试

    1.  先在管理服务器上启用mha

    2.  在主服务器上启用vip

    3.  将主服务器的mysql停掉

    4.  vip会自动飘到备用主机上

    5.  备用主机也从只读变为可写

    6.  其它从库也会指向新的主服务器

5.  故障邮件报警

    需要在mha的配置文件中,调用:report_script=/etc/mha/scripts/send_report   

#!/usr/bin/perl
 
## Note: This is a sample script and is not complete. Modify the script based on your environment.
 
use strict;
use warnings FATAL => 'all';
use Mail::Sender;
use Getopt::Long;
 
#new_master_host and new_slave_hosts are set only when recovering master succeeded
my ( $dead_master_host, $new_master_host, $new_slave_hosts, $subject, $body );
my $smtp='smtp.zhen.com';
my $mail_from='yangjianbo@zhen.com';
my $mail_user='yangjianbo@zhen.com';
my $mail_pass='*****';
my $mail_to=['15810982260@139.com','yangjianbo@zhen.com'];
GetOptions(
  'orig_master_host=s' => \$dead_master_host,
  'new_master_host=s'  => \$new_master_host,
  'new_slave_hosts=s'  => \$new_slave_hosts,
  'subject=s'          => \$subject,
  'body=s'             => \$body,
);
 
mailToContacts($smtp,$mail_from,$mail_user,$mail_pass,$mail_to,$subject,$body);
 
sub mailToContacts {
    my ( $smtp, $mail_from, $user, $passwd, $mail_to, $subject, $msg ) = @_;
    open my $DEBUG, "> /tmp/monitormail.log"
        or die "Can't open the debug      file:$!\n";
    my $sender = new Mail::Sender {
        ctype       => 'text/plain; charset=utf-8',
        encoding    => 'utf-8',
        smtp        => $smtp,
        from        => $mail_from,
        auth        => 'LOGIN',
        TLS_allowed => '0',
        authid      => $user,
        authpwd     => $passwd,
        to          => $mail_to,
        subject     => $subject,
        debug       => $DEBUG
    };
 
    $sender->MailMsg(
        {   msg   => $msg,
            debug => $DEBUG
        }
    ) or print $Mail::Sender::Error;
    return 1;
}
 
 
 
# Do whatever you want here
 
exit 0;

6.  修复宕机后的master节点

    查看manager节点的manager.log日志

    grep -i "All other slaves should start" manager.log

    找到相应的语句,并在旧的主服务器上执行

    CHANGE MASTER TO MASTER_HOST='192.168.2.192', MASTER_PORT=3306, MASTER_LOG_FILE='mysql-bin.000005', MASTER_LOG_POS=154, MASTER_USER='rep', MASTER_PASSWORD='123';   

7.  手动切换mha     

    1.  确保mha manager关闭

        masterha_stop --conf=/etc/mha/app1.cnf

    2.  原主下线

    3.  切换主

        masterha_master_switch --master_state=dead --conf=/etc/mha/app1.cnf --dead_master_host=192.168.1.200 --dead_master_port=3306 --new_master_host=192.168.1.210  --new_master_port=3306 --ignore_last_failover                                 

posted @ 2022-08-19 09:28  奋斗史  阅读(134)  评论(0)    收藏  举报