MySQL-MHA搭建

发布时间 2023-06-12 21:41:28作者: 原来是你~~~
1、测试环境

目前MHA主要支持一主多从的架构,要搭建MHA,要求一个复制集群中必须最少有三台数据库服务器,一主二从,即一台充当master,一台充当备用master,另外一台充当从库.

一主两从的环境,通过GTID方式配置主从复制同步环境

用途 IP地址 安装软件 MySQL版本
主库 db01 192.168.3.112 mha-node mysql 8.0.24
从库 db02 192.168.3.113 mha-node mysql 8.0.24
从库 db03 192.168.3.114 mha-manager、mha-node mysql 8.0.24

创建MySQL相关命令软链接

## 三台服务器都需执行
# ln -s /opt/mysql/bin/mysqlbinlog /usr/bin/
# ln -s /opt/mysql/bin/mysql /usr/bin/

配置三台主机之间ssh免密互信登录,配置完成三台主机验证确认无误

## 三台服务器都需执行
# rm -rf /root/.ssh/
## 只在主库上执行
# cd /root/.ssh
# mv id_rsa.pub authorized_keys
# ssh-keygen
# scp -r /root/.ssh 192.168.3.114:/root  
# scp -r /root/.ssh 192.168.3.113:/root

mha软件下载

mha版本

  • 0.56 适用于 mysql5.6 版本系列

  • 0.57 适用于 mysql5.7 版本系列

  • 0.58 适用于 mysql8.0 版本系列

安装mha软件

## 三台服务器都需执行
# yum install perl-DBD-MySQL -y
# rpm -ivh mha4mysql-node-0.58-0.el7.centos.noarch.rpm

## 在db01上创建需要的mha数据库用户 
db01 [(none)]>create user mha@'192.168.3.%' identified with mysql_native_password by 'mha';

db01 [(none)]>grant all privileges on *.* to mha@'192.168.3.%';

## 在db03安装mha-manger软件
# yum install -y perl-Config-Tiny epel-release perl-Log-Dispatch perl-ParallelForkManager perl-Time-HiRes
# yum install mha4mysql-manager-0.58-0.el7.centos.noarch.rpm -y

# mkdir -p /etc/mha
# mkdir -p /var/log/mha/app1
vim /etc/mha/app1.cnf
[server default]
manager_log=/var/log/mha/app1/manager
manager_workdir=/var/log/mha/app1
master_binlog_dir=/opt/mysql/binlog/
user=mha
password=mha
ping_interval=2
repl_password=repl
repl_user=repl
ssh_user=root
[server1]
hostname=192.168.3.112
port=3306
[server2]
hostname=192.168.3.113
candidate_master=1
port=3306
[server3]
hostname=192.168.3.114
port=3306

## 互信检查
masterha_check_ssh --conf=/etc/mha/app1.cnf
## 主从状态检查
masterha_check_repl --conf=/etc/mha/app1.cn
## 启动mha
# 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_check_status --conf=/etc/mha/app1.cnf

配置 VIP 过程

## 配置脚本
# 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.3.111/24';
my $key = '1';
my $ssh_start_vip = "/sbin/ifconfig ens33:$key $vip";
my $ssh_stop_vip = "/sbin/ifconfig ens33:$key down";
my $ssh_Bcast_arp= "/sbin/arping -I ens33 -c 3 -A 192.168.3.111";
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";
}

## 添加脚本路径到manager配置文件
# vim /etc/mha/app1.cnf
master_ip_failover_script=/usr/local/bin/master_ip_failover

## 重启mha
# masterha_stop --conf=/etc/mha/app1.cnf

## 手动添加VIP
# masterha_check_status --conf=/etc/mha/app1.cnf
# ifconfig ens33:1 192.168.3.111/24

配置邮件提醒

# more send_report 
#!/usr/bin/perl
#  Copyright (C) 2011 DeNA Co.,Ltd.
#
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#   along with this program; if not, write to the Free Software
#  Foundation, Inc.,
#  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 
## 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.qq.com';        # smtp服务器
my $mail_from='@qq.com';       # 发件箱
my $mail_user='';              # QQ号
my $mail_pass='';              # 授权码
#my $mail_to=['to1@qq.com','to2@qq.com'];  # 多个收件箱
my $mail_to='@qq.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,
);
 
# Do whatever you want here
mailToContacts($smtp,$mail_from,$mail_user,$mail_pass,$mail_to,$subject,$body);
 
sub mailToContacts {
	my ($smtp, $mail_from, $mail_user, $mail_pass, $mail_to, $subject, $msg ) = @_;
	open my $DEBUG, ">/tmp/mail.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		=> $mail_user,
		authpwd		=> $mail_pass,
		to		=> $mail_to,
		subject		=> $subject,
		debug		=> $DEBUG
	};
	$sender->MailMsg(
		{
			msg => $msg,
			debug => $DEBUG
		}
	) or print $Mail::Sender::Error;
	return 1;
}
 
exit 0;

## manager配置文件中添加,重启mha
report_script=/usr/local/bin/send_report

对于异步复制方式,可以添加 binlog 的日志补偿,减少数据丢失。

## db03 创建保存binlog日志文件目录 
# mkdir -p /data/binlog_master/
# chown -R mysql.mysql /data/*
# cd /data/binlog_master/
# mysql -e "show slave status \G"|grep "Master_Log"
# masterha_check_status --conf=/etc/mha/app1.cnf

# mysqlbinlog -R --host=192.168.3.112 --user=mha --password=mha --raw --stop-never mysql-bin.000002 &

# vim /etc/mha/app1.cnf
[binlog1]
no_master=1
hostname=192.168.3.114
master_binlog_dir=/data/binlog_master/

# masterha_stop --conf=/etc/mha/app1.cnf
# 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 &

binlog server不是100%可靠的。他模拟的是从库IO线程的功能(异步)。

替代方案: 5.7+GTID+增强半同步。

注意的是,当master数据库出现故障后,切换主库后,mha程序自动停止,只能监测切换一次,需要手动进行恢复mha高可用。

数据一致性保证同步配置

#*************** rpl_semi_sync ***************
rpl_semi_sync_master_enabled =ON
rpl_semi_sync_master_timeout =5000
rpl_semi_sync_master_wait_for_slave_count =1
rpl_semi_sync_master_wait_no_slave =ON
rpl_semi_sync_master_wait_point =AFTER_SYNC
rpl_semi_sync_slave_enabled =ON
#*************** group commit ***************
binlog_group_commit_sync_delay =1
binlog_group_commit_sync_no_delay_count =1000
#*************** gtid ***************
gtid_mode =ON
enforce_gtid_consistency =ON
log_slave_update =1
#*************** gtid ***************
slave_parallel_type =LOGICAL_CLOCK
slave_parallel_workers =4
master_info_repository =TABLE
relay_log_info_repository =TABLE