Mysql-MHA集群 从概念到搭建

基本概念

由来

  • MHA(Master High Availability)目前在MySQL高可用方面是一个相对成熟的解决方案。
  • 它由日本DeNA公司youshimaton(现就职于Facebook公司)开发。

原理

组成

由两部分组成:MHA Manager(管理节点)和MHA Node(数据节点)

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

工作流程图

Pasted image 20230215101504.png

优势

  • 部署上
    • 适合多种存储引擎
    • 不改变现有MySQL集群的部署
  • 使用上
    • 高可用
      • 可以对集群进行监控
      • 在30秒内无缝的完成主从切换
        • 故障的发现、转移是自动进行的
        • 转移时数据最大程度保持完成
        • 转移失败自动重试

缺点

  • 部署上
    • 只支持一主多从
    • 最少需要三台机器
    • 不支持较新版本的MySQL
  • 使用上
    • 不支持大事务的复制
      • 因为它们可能被阻塞,影响其他事务的处理。
      • 此外,若要在源和目标两端都成功完成,需要很长时间;
    • 强依赖于MySQL的主从复制

TMHA

淘宝也在该基础上进行了改造,目前淘宝TMHA已经支持一主一从

软件内容

Manager工具包

masterha_check_ssh              检查MHA的SSH配置状况
masterha_check_repl             检查MySQL复制状况
masterha_manger                启动MHA
masterha_stop                  停止MHA
masterha_check_status           检测当前MHA运行状态
masterha_master_monitor         检测master是否宕机
masterha_master_switch          控制故障转移(自动或者手动)
masterha_conf_host              添加或删除配置的server信息

Node工具包

save_binary_logs        保存和复制master的二进制日志
apply_diff_relay_logs     识别差异的中继日志事件并将其差异的事件应用于其他的slave
filter_mysqlbinlog        去除不必要的ROLLBACK事件(MHA已不再使用这个工具)
purge_relay_logs       清除中继日志(不会阻塞SQL线程)

部署 MHA

基本环境部署

  1. 实验拓扑图 
主机名 IP 地址 角色
YY 192.168.45.10 Master
YY 1 192.168.45.11 Slave
YY 2 192.168.45.12 Slave
  1. [[11-MySQL 读写分离&mycat#基础环境准备|常规环境部署]]
  2. 配置所有主机秘钥免密登录
    1. 这里建议使用expect配合脚本
    2. 可以使用 Xshell 功能推送秘钥

软件环境部署

获取软件 RPM 包

上传软件包

  • 上传前在所有节点创建一个 MHA 的文件夹
mkdir ~/MHA

image.png

  • mha4mysql-node-0.57-0.el7.noarch.rpm
  • mha4mysql-manager-0.57-0.el7.noarch.rpm
  • mhapath.tar.gz

本地 yum 源准备

  • 这里也可以使用 epel 网络源
tar -zxvf mhapath.tar.gz
mkdir /etc/yum.repos.d/yumbackup
cp /etc/yum.repos.d/* /etc/yum.repos.d/yumbackup
rm -rf /etc/yum.repos.d/*.repo
cat<<EOF>/etc/yum.repos.d/mhapath.repo
[mha]
name=mhapath
baseurl=file:///root/MHA/mhapath
enabled=1
gpgcheck=0
EOF
cat<<EOF>/etc/yum.repos.d/CentOS7.repo
[centos7]
name=centos_7
baseurl=file:///mnt/cdrom
enabled=1
gpgcheck=0
EOF

mount /dev/sr0 /mnt/cdrom/
yum repolist

image.png

同步配置到其它节点

  • yum 配置文件同步
for ip in 11 12;do scp -r /etc/yum.repos.d/*.repo 192.168.45.$ip:/etc/yum.repos.d/ ; done
for ip in 11 12; do scp /root/MHA/mha4mysql-node-0.57-0.el7.noarch.rpm 192.168.45.$ip:~/MHA; done
for ip in 11 12; do scp -r /root/MHA/mhapath 192.168.45.$ip:~/MHA; done
  • 所有节点安装依赖包
    • 这里用 Xshell 远程,可以使用
      • 工具-发送键输入到-所有会话
  • 并检查安装情况
yum -y install perl-DBD-MySQL perl-Config-Tiny perl-Log-Dispatch perl-Parallel-ForkManager --skip-broken --nogpgcheck
rpm -ivh mha4mysql-node-0.57-0.el7.noarch.rpm
ll /usr/bin/{app*,filter*,purge*,save*}

安装 MHA Manager

  • 这一步只需要在 Manager 安装
  • 安装依赖包
yum install -y  perl-DBD-MySQL perl-Config-Tiny perl-Log-Dispatch perl-Parallel-ForkManager perl-Time-HiRes perl-ExtUtils-CBuilder perl-ExtUtils-MakeMaker perl-CPAN
  • 安装 MHA Manager
rpm -ivh mha4mysql-manager-0.57-0.el7.noarch.rpm

部署半同步复制模块

  • 使用 Xshell 工具在所有数据库节点上进行部署 
mysql -uroot -p123456  -e "install plugin rpl_semi_sync_master soname 'semisync_master.so';install plugin rpl_semi_sync_slave soname 'semisync_slave.so';"
  • 检查部署情况 
mysql -uroot -p123456  -e "show plugins;" | grep rpl_semi_sync*
mysql -uroot -p123456  -e "show variables like '%rpl_semi_sync%';"|grep master_enabled
  • 模块加载成功
    image.png
  • 半同步已安装未开启
    image.png

配置 Master

调整 my.cnf

vim /etc/my.cnf
  • server-id=1
    • ID 标识 MySQL 集群的节点,不能重复。
  •  rpl_semi_sync_master_enabled=1
    • 1 启用;0 关闭
  •  rpl_semi_sync_master_timeout=10000
    • 单位毫秒,表示主服务器等待确认消息的时长
    • 这里表示 10 秒后,不再等待,变为异步的方式。
  • binlog-do-db=HA
    • 被从服务器复制的库 。Binlog 同步的数据库名
  • log_slave_updates=1
    • 开启该参数, 从库的 binlog 才会记录主库的操作日志
server-id=1
log-bin=/data/mysql/log/mysql-bin
log-bin-index=/data/mysql/log/mysql-bin.index
binlog_format=mixed
rpl_semi_sync_master_enabled=1
rpl_semi_sync_master_timeout=10000
rpl_semi_sync_slave_enabled=1
relay_log_purge=0
relay-log = /data/mysql/log/relay-bin
relay-log-index = /data/mysql/log/slave-relay-bin.index
binlog-do-db=HA 
log_slave_updates=1 

image.png

  • 重启服务,生效配置文件
systemctl restart mysqld

MySQL 授权&建立测试库

  • 进入 MySQL 操作
mysql -uroot -p123456

授权

grant replication slave on *.* to slave@'192.168.45.%' identified by '123456';
grant all privileges on *.* to root@'192.168.45.%' identified by '123456';
flush privileges;
show master status;

image.png

  • 注意:这里的 binlog 节点在后面的 Slave 指定 Master 的时候需要用到

建库

  • 准备测试的库及数据
create database HA;
use HA;
create table test(id int,name varchar(20));
insert into test values(1,'YY');

同步库到 Slave

mysqldump -uroot -p123456 -B HA>HA.sql
scp HA.sql root@192.168.45.11:~
scp HA.sql root@192.168.45.12:~

配置 Slave

  • 这一环节也可使用 Xshell 工具完成
  • 使用中需要注意 Slave 节点之间不同的地方
    • 如 serverid ip 等

调整 my.cnf

注意:这里的 server-id 不能重复!

server-id=2
log-bin=/data/mysql/log/mysql-bin
log-bin-index=/data/mysql/log/mysql-bin.index
binlog_format=mixed
rpl_semi_sync_master_enabled=1
rpl_semi_sync_master_timeout=10000
rpl_semi_sync_slave_enabled=1
relay_log_purge=0
relay-log = /data/mysql/log/relay-bin
relay-log-index = /data/mysql/log/slave-relay-bin.index
binlog-do-db=HA
 log_slave_updates=1
systemctl restart mysqld

建立 MySQL 主从

导入数据库

mysql -uroot -p123456 <HA.sql

创建授权帐号

mysql -uroot -p123456
grant replication slave on *.* to slave@'192.168.45.%' identified by '123456';
grant all privileges on *.* to root@'192.168.45.%' identified by '123456';
flush privileges;

建立主从关系

stop slave;
change master to master_host='192.168.45.10',master_user='slave',master_password='123456',master_log_file='mysql-bin.000001',master_log_pos=1789;
start slave;
show slave status\G;

image.png

设置 read_only

  • 这里之所以设置为只读
    • MHA 会进行主从切换,不能将只读写入配置文件
    • slave 一般只做读操作
mysql -uroot -p123456 -e 'set global read_only=1'

Master 检查半同步情况

mysql -uroot -p123456 -e "show variables like '%rpl_semi_sync%';"

image.png

mysql -uroot -p123456 -e "show status like '%rpl_semi_sync%';"

image.png

参数说明
rpl_semi_sync_master_status :显示主服务是异步复制模式还是半同步复制模式  
rpl_semi_sync_master_clients :显示有多少个从服务器配置为半同步复制模式  
rpl_semi_sync_master_yes_tx :显示从服务器确认成功提交的数量 (即master成功接收到slave的回复的次数。)
rpl_semi_sync_master_no_tx :显示从服务器确认不成功提交的数量  (即master 等待超时的次数)
rpl_semi_sync_master_tx_avg_wait_time :事务因开启 semi_sync ,平均需要额外等待的时间 (即master 花在每个事务上的平均等待时间) 
Rpl_semi_sync_master_tx_wait_time  :master 花在所有事物上的等待时间
rpl_semi_sync_master_net_avg_wait_time :事务进入等待队列后,到网络平均等待时间(即master 等待slave 回复的平均等待时间。单位毫秒.)  
Rpl_semi_sync_master_net_wait_time  :master 总的等待时间
Rpl_semi_sync_master_net_waits  :master 等待slave 回复的的总的等待次数。
Rpl_semi_sync_master_no_times:master 关闭半同步复制的次数。
Rpl_semi_sync_master_timefunc_failures  :记录master调用类似 gettimeofday()等函数的失败次数
Rpl_semi_sync_master_tx_waits  :master总的等待次数
Rpl_semi_sync_master_wait_sessions  :当前有多少个session 因为slave 的回复而造成等待

配置 MHA

  • 这一步在实际工作环境中,需要配置在 manage 节点
    • 保障高可用
  • 在这里使用之前的 Master 节点进行部署

准备 MHA 工作目录

mkdir  /etc/masterha
mkdir -p /var/log/masterha/app1
vim /etc/masterha/app1.cnf
[server default]
manager_workdir=/var/log/masterha/app1
manager_log=/var/log/masterha/app1/manager.log
master_binlog_dir=/data/mysql/log

user=root
password=123456
ping_interval=1
remote_workdir=/tmp
repl_user=slave
repl_password=123456
report_script=/usr/local/send_report
shutdown_script=""
ssh_user=root



[server1]
hostname=DB1
port=3306
#candidata_master=1


[server2]
hostname=DB2
port=3306
#candidata_master=1

[server3]
hostname=DB3
port=3306

参数说明

由于在 app1.cnf 中不能有中文的存在,所以这里单独摘取配置文件进行注释说明。

[server default]
#不能有中文
manager_workdir=/var/log/masterha/app1 
#设置manager的工作目录

manager_log=/var/log/masterha/app1/manager.log 
#设置manager的日志
master_binlog_dir=/data/mysql/log  
#设置master 保存binlog的位置,以便MHA可以找到master的日志
#这里的也就是mysql的数据目录,
#注:所有mysql的binlog文件路径都要与该路径一致。

master_ip_failover_script= /usr/bin/master_ip_failover  
#设置自动故障切换时候的脚本
master_ip_online_change_script=/usr/bin/master_ip_online_change 
#设置手动切换时候的切换脚本
 
user=root  
#设置监控用户manager
password=123456   
#监控用户manager的密码
ping_interval=1  
#设置监控主库,发送ping包的时间间隔,默认是3秒,尝试三次没有回应的时候自动进行failover
remote_workdir=/tmp  
#设置远端mysql在发生切换时binlog的保存位置
repl_user=slave    
#设置复制环境中的复制用户名
repl_password=123456  
#设置复制用户的密码
report_script=/usr/local/send_report  
#设置发生切换后发送的报警的脚本
shutdown_script=""    
#设置故障发生后关闭故障主机脚本(该脚本的主要作用是关闭主机防止发生脑裂,这里没有使用)
ssh_user=root   
#设置ssh的登录用户名
 
[server1]
hostname=YY
port=3306
 
[server2]
hostname=YY1
port=3306

[server3]
hostname=YY2
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

检查配置情况

检查 SSH 免密登录情况

这里要注意的是 Master 本机也是需要进行免密的。

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

image.png

  • 没有 error ,通过检测

检查主从复制情况

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

image.png

启动 MHA Manager

启动命令
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 &
参数说明
  • --remove_dead_master_conf
    • 该参数代表当发生主从切换后,老的主库的 ip 将会从配置文件中移除
  • --manger_log
    • 日志存放位置
  • --ignore_last_failover
    • 在缺省情况下,如果 MHA 检测到连续发生宕机,且两次宕机间隔不足 8 小时的话,则不会进行 Failover 故障转移。
    • 该参数代表忽略上次 MHA 触发切换产生的文件。
      • 默认情况下,MHA 发生切换后会在日志目录,也就是上面设置的/data 产生 app1.Failover.Complete 文件。
      • 下次再次切换的时候如果发现该目录下存在该文件将不允许触发切换,除非在第一次切换后删除该文件.
    • 为了方便测试,这里设置为--ignore_last_failover
检查启动状态
masterha_check_status --conf=/etc/masterha/app1.cnf

image.png

  • 启动成功!
查看启动日志
tail -20 /var/log/masterha/app1/manager.log

image.png

Sun Mar  5 21:21:52 2023 - [info] Ping(SELECT) succeeded, waiting until MySQL doesn't respond..
  • 集群启动成功 

MHA 测试

模拟故障

观察 manager 的日志

tail -0f /var/log/masterha/app1/manager.log

手动停止 Master 的 MySQL 服务

systemctl stop mysqld

查看日志的变化情况

查看主从的状态变化

mysql -uroot -p123456 -e "show master status;"

配置 MHA 的 VIP

基本概念

  • MHA(Master High Availability)是一个 MySQL 高可用性解决方案,其中一个重要的特性是 VIP(Virtual IP Address)功能。
  • VIP 是虚拟 IP 地址的缩写,是指一个在网络中使用的虚拟 IP 地址,它不是实际存在的 IP 地址,而是一个可以被路由器或交换机识别并作为代理 IP 地址使用的 IP 地址。
  • 在 MHA 中,VIP 被用于提供无缝的故障转移。
  • 原理:
    • 当主数据库宕机时,MHA 会将 VIP 迅速地从主数据库切换到备份数据库,以便客户端应用程序可以继续通过该 VIP 访问数据库服务,而不需要修改连接字符串或重新连接到新的数据库。

优缺点

  • 优点
    • 提供无缝的故障转移:当主数据库宕机时,VIP可以迅速地从主数据库切换到备份数据库,以便客户端应用程序可以继续通过该VIP访问数据库服务,而不需要修改连接字符串或重新连接到新的数据库。
    • 简化配置:VIP可以代替实际的数据库IP地址,从而简化了客户端应用程序的配置。
    • 提高可用性:通过使用VIP,可以使数据库服务更加可靠和可用,降低系统停机时间。
  • 缺点
    • 需要额外的软件支持:使用VIP需要额外安装LVS或keepalived等软件,增加了系统的复杂度和维护成本。
    • 依赖于网络设备:VIP需要依赖于网络设备(如交换机或路由器)来实现故障转移和负载均衡,如果网络设备故障或配置不当,可能会导致VIP无法正常工作。
    • 可能会出现IP冲突:由于VIP并不是真实存在的IP地址,而是一个虚拟IP地址,因此在使用VIP时可能会出现IP地址冲突的问题,需要注意IP地址的分配和管理。

实现方式

  • VIP 的实现可以使用 Linux 自带的 ipvsadm 或 keepalived 等工具。
    • 在使用 ipvsadm 时,需要在 MHA 管理节点上安装 LVS 软件,并在 MHA 配置文件中指定 VIP 地址;
    • 在使用 keepalived 时,需要在 MHA 管理节点和 MySQL 数据库服务器上分别安装 keepalived 软件,然后在 MHA 配置文件中指定 VIP 地址和 keepalived 的相关配置参数。
    • 使用脚本时,可以防止脑裂的发生。

配置 VIP

Master 配置 VIP

 ifconfig ens33:1  192.168.45.88 netmask 255.255.255.0 up

主配置文件开启脚本

vim /etc/masterha/app1.cnf
master_ip_failover_script=/usr/bin/master_ip_failover
[server1]
hostname=192.168.1.11
port=3306

编写 perl 脚本

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 = '192.168.1.88/24';
my $key = '1';
my $ssh_start_vip = "/sbin/ifconfig ens33:$key $vip";
my $ssh_stop_vip = "/sbin/ifconfig ens33:$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";
        #`ssh $ssh_user\@cluster1 \" $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 $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";
}
chmod +x /usr/bin/master_ip_failover

环境检测

masterha_check_ssh --conf=/etc/masterha/app1.cnf
masterha_check_repl --conf=/etc/masterha/app1.cnf
  • 如果有安全检查相关的报错可以删除健康检查的文件后重试
  • image.png
rm -rf /var/log/masterha/app1/app1.master_status.health
  • MHA Manager 监控测试
masterha_check_status --conf=/etc/masterha/app1.cnf

故障模拟

观察日志文件

tail -0f /var/log/masterha/app1/manager.log

模拟主库宕机

systemctl stop mysqld
posted @ 2023-05-12 14:26  L_Hang  阅读(301)  评论(0)    收藏  举报