基于 MHA 的 MySQL 高可用主从架构

1024px-MySQL.ff87215b43fd7292af172e2a5d9b844217262571

Author:Arsen
Date:2024/06/25



一、前言

MHA官网:https://code.google.com/archive/p/mysql-master-ha/
GitHub地址:https://github.com/yoshinorim/mha4mysql-manager
文档:https://github.com/yoshinorim/mha4mysql-manager/wiki

1.1 概述

MySQL 高可用性工具集(MySQL High Availability Toolkit,简称 MHA)是一个用于管理 MySQL 主从复制环境的工具集。它旨在提供自动化的故障检测和故障转移,以确保 MySQL 环境的高可用性和可靠性,MHA 的工作原理涉及以下关键步骤:

  1. MySQL 复制拓扑监控

    MHA 通过检查 Master 节点和 Slave 节点之间的复制状态来监控 MySQL 复制拓扑,它可以定期查询MySQL服务器的状态,包括主节点的 Binlog 位置和从节点的复制延迟等信息。

  2. 故障检测

    当 MHA 检测到主节点故障或者其他故障情况时,它会触发故障转移过程。这可能是由于 MySQL 服务器崩溃、网络中断、复制延迟等原因。

  3. 自动故障转移

    在发生故障时,MHA会自动选择一个最适合的从节点,并将其提升为新的主节点。它会自动更新其他从节点的配置,以将它们重新连接到新的主节点。这确保了服务的连续性,并最大限度地减少了服务中断时间。

  4. 触发故障转移的条件

    MHA 根据一定的条件来触发故障转移,例如:主节点失去连接、主节点的复制延迟超过预设的阈值、主节点上的 MySQL 进程崩溃、管理员手动触发故障转移。

  5. 健康检查和维护

    MHA 定期执行健康检查,并处理发现的问题。它可以检测到从节点的延迟、复制错误等,并采取适当的措施来解决问题,以确保环境的稳定性和可靠性。

  6. 自定义配置和脚本

    MHA 允许管理员根据实际需求定制各种配置选项和脚本。这使得 MHA 可以适应不同的环境和应用场景,并提供更灵活的管理和监控功能。

MHA 能做到在 0~30 秒之内自动完成数据库的故障切换操作,并且在进行故障切换的过程中,MHA能在最大程度上保证数据的一致性,以达到真正意义上的高可用。

1.2 组件

MHA主要由以下几个组件组成:

  1. MHA Manager

    运行在独立的管理服务器上,负责监控主库状态并在主库故障时执行自动故障切换。

  2. MHA Node

    部署在每个MySQL服务器上(包括主库和从库),负责管理MySQL服务器上的数据复制和日志处理。

  3. SSH

    用于各个节点之间的通信和命令执行。

  4. Replication Configuration

    MHA依赖于MySQL的复制机制,需要事先配置好主从复制。

1.3 流程

  1. 监控主库

    MHA Manager 持续监控主库的状态,通过检查复制状态、主库可达性等指标来判断主库是否健康。

  2. 检测到主库故障

    一旦 MHA Manager 检测到主库故障,它会立即暂停所有从库的复制进程,防止从库继续接收可能损坏的数据。

  3. 选择新的主库

    MHA Manager 从可用的从库中选择一个延迟最小的从库作为新的主库候选。

    MHA Manager 会检查每个从库的二进制日志,以确保数据的完整性和一致性。

  4. 应用中继日志

    MHA Node 会在新的主库候选上应用所有未处理的中继日志,以确保新主库的数据与故障主库的数据一致。

    如果中继日志不完整,MHA会尝试从其他从库中恢复丢失的二进制日志。

  5. 切换角色

    MHA Manager 更新复制配置,使得其他从库开始从新的主库进行复制。

    更新应用程序的连接信息,使其指向新的主库。

  6. 重新启动复制

    所有从库重新开始从新的主库进行复制,恢复正常的复制拓扑结构。

  7. 通知和日志

    MHA Manager 在故障切换完成后,记录日志并通过邮件或其他方式通知管理员。

二、环境

1、服务器环境

MHA manager 最好是单独一台机器部署,尽量不要混部。

系统配置IP备注
--192.168.56.30VIP
CentOS 7.92C/2G 20G192.168.56.20MHA-Manage
CentOS 7.92C/2G 20G192.168.56.10mysql-master,MHA-Node
CentOS 7.92C/2G 20G192.168.56.11mysql-slave1,MHA-Node
CentOS 7.92C/2G 20G192.168.56.12mysql-Slave2,MHA-Node

2、MySQL 环境

版本备注
5.7.41GTID 的主从复制

3、MySQL 主从架构

image-20240414021727265

目前 MHA 主要支持一主多从的架构,要搭建 MHA,要求一个复制集群中必须最少有三台数据库服务器,一主二从,即一台充当master,一台充当备用 master,另外一台充当从库,因为至少需要三台服务器,出于机器成本的考虑,淘宝也在该基础上进行了改造,目前淘宝 TMHA 已经支持一主一从。

本次实验,处了一主二从的三台服务器外,还有额外有一台来作为 MHA Manager,用于管理多个 master-slave 集群,当然,如果你的服务器不富裕,也可以部署在一台 slave 节点上,MHA 功能:主库失效 、备选主库成为主库 、源故障主库恢复重新加入到MHA成为从库。

4、MHA 架构

  • 管理一个 MySQL 集群

    即 MHA 可管理单个 MySQL 集群。

    image-20240625095624059

  • 管理多个 MySQL集群

    即 MHA 可管理多个 MySQL 集群。

    image-20240625100226559

三、部署

3.1 基本环境

3.1.1 hosts 配置
# mha-manager服务器配置
192.168.56.10 mysql-master mha-node1
192.168.56.11 mysql-slave1 mha-node2
192.168.56.12 mysql-slave2 mha-node3
192.168.56.20 mha-manager  mha-node4

# mysql-master服务器配置
192.168.56.10 mysql-master mha-node1
192.168.56.11 mysql-slave1 mha-node2
192.168.56.12 mysql-slave2 mha-node3
192.168.56.20 mha-manager  mha-node4

# mysql-slave1服务器配置
192.168.56.10 mysql-master mha-node1
192.168.56.11 mysql-slave1 mha-node2
192.168.56.12 mysql-slave2 mha-node3
192.168.56.20 mha-manager  mha-node4

# mysql-slave2服务器配置
192.168.56.10 mysql-master mha-node1
192.168.56.11 mysql-slave1 mha-node2
192.168.56.12 mysql-slave2 mha-node3
192.168.56.20 mha-manager  mha-node4
3.1.2 配置 SSH 免密访问

免密的目的:在 Master 故障时,MHA-Manage 才能 SSH 连接进去,实现主备切换。

1、MHA manager 节点上生成密钥

ssh-keygen

image-20240427230547179

2、将密钥分发至 MySQL 集群节点

# mha-manager服务器上执行 - 主机名形式
ssh-copy-id mysql-master    # 分发给mysql-master
ssh-copy-id mysql-slave1    # 分发给mysql-slave1
ssh-copy-id mysql-slave2    # 分发给mysql-slave2

# mha-manager服务器上执行 - IP形式
ssh-copy-id 192.168.56.10   # 分发给mysql-master
ssh-copy-id 192.168.56.11   # 分发给mysql-slave1
ssh-copy-id 192.168.56.12   # 分发给mysql-slave2

3、MySQL 集群节点间 SSH 互做免密,否则将会报如下错

因为 MySQL 节点间也要进行 SSH 通信。

image-20240625153443958

# 生成密钥(在mysql-master、mysql-slave1、mysql-slave2执行)
ssh-keygen
# 分发密钥(mysql集群间互相分发)- 主机名形式
# [mysql-master节点执行分发]
ssh-copy-id mysql-slave1
ssh-copy-id mysql-slave2
# [mysql-slave1节点执行分发]
ssh-copy-id mysql-master
ssh-copy-id mysql-slave2
# [mysql-slave2节点执行分发]
ssh-copy-id mysql-master
ssh-copy-id mysql-slave1

# 分发密钥(mysql集群间互相分发)- IP形式
# [mysql-master节点执行分发]
ssh-copy-id 192.168.56.11
ssh-copy-id 192.168.56.12
# [mysql-slave1节点执行分发]
ssh-copy-id 192.168.56.10
ssh-copy-id 192.168.56.12
# [mysql-slave2节点执行分发]
ssh-copy-id 192.168.56.10
ssh-copy-id 192.168.56.11

3.2 MySQL 主从

本次使用 GTID 的方式配置主从。

从 MHA 0.56 开始,MHA 支持基于 GTID 的故障转移和传统的基于中继日志的故障转移。 MHA 自动区分选择哪个故障转移。要执行基于 GTID 的故障转移,需要满足以下所有条件:

  • 使用 MySQL 5.6(或更高版本)

  • 所有 MySQL 实例都使用 gtid_mode=1

  • 至少其中一个实例启用了 Auto_Position

    在 MySQL 5.6 及更高版本中,启用 GTID 模式后,自动位置分配会自动生效(无需配置)。

路径规范问题:

  • MySQL 集群中路径尽量保持一致,尤其是 Binlog 日志路径(因为 MHA 配置文件中会指定)
  • 数据路径:/data/mysql_install/data
  • 配置路径:/data/mysql_install/conf
  • 日志路径:/data/mysql_install/logs
3.2.1 基础环境配置

56.10 主机

1、修改主机名

hostnamectl set-hostname mysql-master

2、Docker 环境部署

Docker version 23.0.6, build ef23cbc

3、创建数据持久化目录

mkdir -p /data/mysql_install/{data,logs,conf}

4、data/logs 目录授权

chmod -R 777 /data/mysql_install/{data,logs}

5、准备 MySQL 配置文件

# 看附件
/data/mysql_install/conf/my.cnf

56.11 主机

1、修改主机名

hostnamectl set-hostname mysql-slave1

2、Docker 环境部署

同上!

3、创建数据持久化目录

同上!

4、data/logs 目录授权

同上!

5、准备 MySQL 配置文件

看附件!

56.12 主机

1、修改主机名

hostnamectl set-hostname mysql-slave2

2、Docker 环境部署

同上!

3、创建数据持久化目录

同上!

4、data/logs 目录授权

同上!

5、准备 MySQL 配置文件

看附件!

3.2.2 启动 MySQL 实例

1、mysql-master

vim /data/mysql_install/docker-compose.yml
version: '3'
services:
  mysql-master-service:
    image: mysql:5.7.41
    container_name: mysql-master
    restart: always
    network_mode: "host"
    environment:
      - MYSQL_ROOT_PASSWORD=Zhurs@123!
      - TZ=Asia/Shanghai
    volumes:
      - /data/mysql_install/conf:/etc/mysql/conf.d
      - /data/mysql_install/logs:/var/log/mysql
      - /data/mysql_install/data:/var/lib/mysql
cd /data/mysql_install/ && docker compose up -d

image-20240414115610313

2、mysql-slave1

vim /data/mysql_install/docker-compose.yml
version: '3'
services:
  mysql-slave1-service:
    image: mysql:5.7.41
    container_name: mysql-slave1
    restart: always
    network_mode: "host"
    environment:
      - MYSQL_ROOT_PASSWORD=Zhurs@123!
      - TZ=Asia/Shanghai
    volumes:
      - /data/mysql_install/conf:/etc/mysql/conf.d
      - /data/mysql_install/logs:/var/log/mysql
      - /data/mysql_install/data:/var/lib/mysql
cd /data/mysql_install/ && docker compose up -d

image-20240414115546406

3、mysql-slave2

vim /data/mysql_install/docker-compose.yml
version: '3'
services:
  mysql-slave2-service:
    image: mysql:5.7.41
    container_name: mysql-slave2
    restart: always
    network_mode: "host"
    environment:
      - MYSQL_ROOT_PASSWORD=Zhurs@123!
      - TZ=Asia/Shanghai
    volumes:
      - /data/mysql_install/conf:/etc/mysql/conf.d
      - /data/mysql_install/logs:/var/log/mysql
      - /data/mysql_install/data:/var/lib/mysql
cd /data/mysql_install/ && docker compose up -d

image-20240414115454544

3.2.3 配置 MySQL 主从

1、mysql-master 创建主从同步账号

docker exec mysql-master mysql -u root -p'Zhurs@123!' -e "create user 'repl_master'@'%' identified by 'zhurs@123.com';grant replication  slave,reload,super on *.* to 'repl_master'@'%' with grant option;flush privileges;"

2、mysql-slave1 同步 mysql-master

docker exec mysql-slave1 mysql -u root -p'Zhurs@123!' -e "CHANGE MASTER TO master_host='192.168.56.10', master_port=3306, master_user='repl_master', master_password='zhurs@123.com', master_auto_position=1;start slave;"

查看主从状态:

docker exec mysql-slave1 mysql -u root -p'Zhurs@123!' -e "show slave status\G"

image-20240414122250956

3、mysql-slave2 同步 mysql-master

docker exec mysql-slave2 mysql -u root -p'Zhurs@123!' -e "CHANGE MASTER TO master_host='192.168.56.10', master_port=3306, master_user='repl_master', master_password='zhurs@123.com', master_auto_position=1;start slave;"

查看主从状态:

docker exec mysql-slave2 mysql -u root -p'Zhurs@123!' -e "show slave status\G"

image-20240414122339087

3.2.4 MySQL 主从同步验证

在 mysql-master 上创建一个测试数据库,看 mysql-slave1、mysql-slave2 是否同步。

mysql-master:

docker exec mysql-master mysql -u root -p'Zhurs@123!' -e "create database tmptest;"

mysql-slave1 验证:

docker exec mysql-slave1 mysql -u root -p'Zhurs@123!' -e "show databases;"

image-20240414123112744

mysql-slave2 验证:

docker exec mysql-slave2 mysql -u root -p'Zhurs@123!' -e "show databases;"

image-20240414123201528

至此,主从同步配置完成!

3.3 MHA 部署

参考文档:https://www.cnblogs.com/liugp/p/16500022.html

参考文档:https://www.cnblogs.com/sunnytomorrow/p/15794946.html

3.3.1 MHA node

所有节点都需要安装 MHA node(即 56.10、56.11、56.12、56.20 节点都要部署)

1、安装相关依赖

yum install perl-DBD-MySQL -y

2、MHA node 安装

rpm 包下载地址:https://github.com/yoshinorim/mha4mysql-node/releases

# 下载
wget 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
3.3.2 MHA manager

MHA manager 节点部署(即 56.20 节点部署)

1、安装相关依赖

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

2、MHA manager 安装

rpm 包下载地址:https://github.com/yoshinorim/mha4mysql-manager/releases/

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

# 安装
rpm -ivh mha4mysql-manager-0.58-0.el7.centos.noarch.rpm

3.4 MHA 配置

3.4.1 为 MHA 创建一个帐户

在 mysql-master 主节点上执行,执行后 mha 账户会同步到 slave 上。

docker exec mysql-master mysql -u root -p'Zhurs@123!' -e "CREATE USER mha@'%' IDENTIFIED BY 'Security0527';"
docker exec mysql-master mysql -u root -p'Zhurs@123!' -e "GRANT ALL PRIVILEGES ON *.* TO mha@'%';"
docker exec mysql-master mysql -u root -p'Zhurs@123!' -e "FLUSH PRIVILEGES;"
3.4.2 mha-manager 创建配置文件

在 mha-manager 上创建配置文件目录并创建配置 app1.cnf

1、创建 MHA 相关目录

# 在mha-manager上创建相关工作目录
mkdir -p /data/masterha/{conf,logs,scripts}

# 在所有mha-node上创建相关工作目录
mkdir -p /data/nodeha

2、在 mha-manager 上创建配置文件

vim /data/masterha/conf/mysql_mha.cnf
[server default]
# 指定mha-manager访问MySQL数据库信息
user=mha
password=Security0527
port=3306
# 指定 MHA-manage 的工作目录
manager_workdir=/data/masterha
# 指定 MHA-node 工作目录(即 mha 在远程 mha-node 节点的工作目录)
remote_workdir=/data/nodeha
# 指定 MHA-manage 的日志路径
manager_log=/data/masterha/logs/manager.log
# 指定存放 MySQL master 的 binlog 的日志文件所在目录
master_binlog_dir=/data/mysql_install/data
# 指定主从复制的 mysq 用户和密码
repl_user=repl_master
repl_password=zhurs@123.com
# SSH 连接用户(我们已经做了免密)
ssh_user=root
# 指定检测间隔时间
ping_interval=1
# 指定一个脚本,该脚本实现了在主从切换之后,将虚拟ip漂移到新的master上
master_ip_failover_script=/data/masterha/scripts/master_ip_failover
# 指定检查的从服务器IP地址的脚本,有几个,就用-s选项加几个(这个脚本可手动修改,比如ssh用户名/MySQL端口等,根据实际修改)
secondary_check_script=/usr/bin/masterha_secondary_check -s mysql-master -s mysql-slave1 -s mysql-slave2
# 用于故障切换的时候发送邮件提醒(先暂时不用)
#report_script=/data1/mysql-mha/send_mail
# mysql 集群节点
# mysql-master
[server1]
hostname=mysql-master
port=3306
ssh_user=root
ssh_port=22
candidate_master=1
check_repl_delay=0
# mysql-slave1
[server2]
hostname=mysql-slave1
port=3306
ssh_user=root
ssh_port=22
candidate_master=1
check_repl_delay=0
# mysql-slave2
[server3]
hostname=mysql-slave2
port=3306
ssh_user=root
ssh_port=22
candidate_master=1
check_repl_delay=0

参数说明:

  • candidate_master=1

    参数用于标识候选主库。候选主库是指在当前主库发生故障时,可以被提升为新主库的从库节点。配置此参数可以帮助 MHA 在进行主库故障转移时,优先选择合适的候选主库进行切换。

  • check_repl_delay=0

    该参数用于控制在主库故障转移时是否检查从库的复制延迟。

    0 表示不检查从库的复制延迟。

    1 表示检查从库的复制延迟,默认值,如果复制延迟较大,从库不会被选为新的主库。

    使用场景:

    • check_repl_delay=0 在非常紧急的情况下,你需要尽快恢复业务,而不考虑数据延迟问题。这个参数对于设置了candidate_master=1的主机非常有用,因为这个候选主在切换的过程中一定是新的 master。
    • check_repl_delay=1 通常情况下,建议保持默认值,以确保提升为新主库的从库数据尽量与原主库保持一致,减少数据不一致的风险。
  • 上面配置文件中有 [server default]、[server1]、[server2]…等字段,这些字段中的参数是一种包含关系。

    • 比如你的 [server default] 字段中指定了参数 port=3306
    • [server1] 字段也指定了参数 port=13306
    • 那此时的 port 值以 [server1] 为准,即 13306,如果没有指定参数,则以 [server default] 中的参数值为准。

3、编写 master_ip_failover 脚本

在 /data/masterha/conf/mysql_mha.cnf 配置中提到的虚拟IP漂移脚本

vim /data/masterha/scripts/master_ip_failover
#!/usr/bin/env perl
use strict;
use warnings FATAL => 'all';
 
use Getopt::Long;
 
my (
    $command, $orig_master_host, $orig_master_ip,$ssh_user,
    $orig_master_port, $new_master_host, $new_master_ip,$new_master_port,
    $orig_master_ssh_port,$new_master_ssh_port,$new_master_user,$new_master_password
);
 
# 这里定义的虚拟IP配置要注意,这个ip必须要与你自己的集群在同一个网段,否则无效
my $vip = '192.168.56.30/24';
my $key = '1';
# 这里的网卡名称 “ens33” 需要根据你机器的网卡名称进行修改
# 如果多台机器直接的网卡名称不统一,有两种方式,一个是改脚本,二是把网卡名称修改成统一
# 我这边实际情况是修改成统一的网卡名称
my $ssh_start_vip = "sudo /sbin/ifconfig ens33:$key $vip";
my $ssh_stop_vip = "sudo /sbin/ifconfig ens33:$key down";
my $ssh_Bcast_arp= "sudo /sbin/arping -I bond0 -c 3 -A $vip";

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,
    'orig_master_ssh_port=i' => \$orig_master_ssh_port,
    'new_master_host=s'  => \$new_master_host,
    'new_master_ip=s'    => \$new_master_ip,
    'new_master_port=i'  => \$new_master_port,
    'new_master_ssh_port' => \$new_master_ssh_port,
    'new_master_user' => \$new_master_user,
    'new_master_password' => \$new_master_password
 
);
 
exit &main();
 
sub main {
    $ssh_user = defined $ssh_user ? $ssh_user : 'root';
    print "\n\nIN SCRIPT TEST====$ssh_user|$ssh_stop_vip==$ssh_user|$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();
        &start_arp();
            $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() {
    `ssh $ssh_user\@$orig_master_host \" $ssh_stop_vip \"`;
}
 
sub start_arp() {
    `ssh $ssh_user\@$new_master_host \" $ssh_Bcast_arp \"`;
}
sub usage {
    print
    "Usage: master_ip_failover --command=start|stop|stopssh|status --ssh_user=user --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 a+x /data/masterha/scripts/master_ip_failover
3.4.3 mysql-slave 中继日志关闭自动清除

重要:在 mysql-slave1、mysql-slave2 上设置从库 relay_log_purge 参数,MHA在发生主从切换的过程中,从库的恢复过程依赖于 relay log,所以这里要将 relay log 的自动清除设置为 OFF,即采用手动清除 relay log 的方式。在默认情况下,从服务器上的中继日志会在SQL线程执行完毕后被自动删除。但是在MHA环境中,这些中继日志在恢复其他从服务器时可能会被用到,因此需要禁用中继日志的自动删除功能。

当然,当你的 mysql-master 宕机下线后,如果要重新成为 MySQL 集群的 slave 节点时,其中继日志 relay_log_purge 参数也应该设置为 OFF。

[mysqld]
relay_log_purge=OFF

设置 relay_log_purge=OFF 后,MySQL 将不会自动清除不再需要的中继日志文件,而是会保留它们直到手动删除或者达到了存储限制。请注意,手动管理中继日志文件可能会增加磁盘空间的使用,并且需要定期检查和清理不再需要的文件。

3.4.4 mysql-master 启用 VIP
# 在当前的mysql-master上配置
# 标签要和master_ip_faioverl配置文件中my $key = '1'; 一样
ifconfig ens33:1 192.168.56.30/24

image-20240625134157614

3.5 MHA 可用性测试

3.5.1 测试 ssh 免密认证
masterha_check_ssh -conf=/data/masterha/conf/mysql_mha.cnf

image-20240625154711008

SSH 免密认证通过!

3.5.2 测试 mysql 主从状态
masterha_check_repl -conf=/data/masterha/conf/mysql_mha.cnf

image-20240625170637726

MySQL 主从健康认证通过!

3.6 启动 MHA

1、启动

nohup masterha_manager  \
--conf=/data/masterha/conf/mysql_mha.cnf \
--remove_dead_master_conf \
--ignore_last_failover < /dev/null > /var/log/mha_manager.log 2>&1 &

2、检查 MHA 状态

masterha_check_status --conf=/data/masterha/conf/mysql_mha.cnf

image-20240625171458254

3、查看 MHA 日志文件

image-20240625171620698

4、如何关闭 MHA ?

masterha_stop --conf=/opt/mysql-mha/mysql_mha.cnf

四、故障模拟与恢复

至此,所有环境都准备完毕,接下来就是模拟故障及恢复了。

4.1 故障

这里模拟 mysql-master 宕机的场景。

1、停止 mysql-master 服务

docker compose down

image-20240625172355975

2、此时 VIP 从 mysql-master 漂移到 mysql-slave1 了

image-20240625172506280

3、我们去 mysql-slave2 验证一下 mysql-slave1 是否为 master 节点

docker exec mysql-slave2 mysql -u root -p'Zhurs@123!' -e "show slave status\G"

image-20240625173116346

可看到 mysql-slave2 上可看到,此时他的 master 节点为 mysql-slave1,证明故障自动转移。

4、这个时候我在 mysql-slave1 上创建一个测试数据库

docker exec mysql-slave1 mysql -u root -p'Zhurs@123!' -e "create database hello_mha;"

5、看看 mysql-slave2 是否正常同步

docker exec mysql-slave2 mysql -u root -p'Zhurs@123!' -e "show databases;"

image-20240625173756298

没问题,正常同步!

4.2 恢复

此时,我启动 mysql-master 实例,并进行主从配置,看又是否能同步 mysql-slave1 的数据。

1、启动 mysql-master 实例

docker compose up -d
docker ps

image-20240625173924255

2、配置主从同步

docker exec mysql-master mysql -u root -p'Zhurs@123!' -e "CHANGE MASTER TO master_host='192.168.56.11', master_port=3306, master_user='repl_master', master_password='zhurs@123.com', master_auto_position=1;start slave;"

3、查看主从状态

docker exec mysql-master mysql -u root -p'Zhurs@123!' -e "show slave status\G"

image-20240625174215762

4、验证 mysql-master 数据完整性

看看是否进行了数据同步

docker exec mysql-master mysql -u root -p'Zhurs@123!' -e "show databases;"

image-20240625174343336

没问题,主从数据正常同步。

五、应用程序如何连接?

在 MHA 的配置处,我们指定了虚拟 IP(VIP),其实这就是我们应用程序的连接地址,因为 VIP 总是跟随主节点的移动而移动,即 VIP 所在节点就是 master 节点,且实际生产中,我们应用程序的写肯定是 master 节点,至于读当然也可以是 master,同时也支持对 slave 节点的只读,可做读写分离。

验证一下通过 VIP 是否能正常连接数据库,如下图,可正常连接:

image-20240625174734220

看看是否有数据:

image-20240625175335662

至此,基于 MHA 的 MySQL 高可用主从架构部署结束。

总结

通过以上的点滴部署,实际上你会发现,在 MHA 的世界其实没有主从,都是平等的 MySQL 节点,因为这些节点可能会根据恶劣的环境随时跟换主节点,因此,我们在设计这种 MySQL 主从架构时,应保持 MySQL 集群节点的规格/配置一致,这样就不会因为发生主从切换时,数据的写入即复制延迟,导致对外提供服务发生异常(尤其是生产环境下)。

MHA 不足之处在于它只保证了 master 的高可用,并没有监控 slave 的状态,如果某 slave 出现复制中断、延迟增加等问题,都是不知道的。同时,MHA Manager 本身可能成为单点故障,因此需要进行高可用配置,如通过 Heartbeat 或 Pacemake r等高可用软件进行保护。

附件

my.cnf

注意:master、slave1 和 slave2 的 server-id 要唯一,所以下面的这个配置文件分发给 MySQL Slave 时注意 server-id 唯一性问题

[client]
port = 3306

[mysqld]
#innodb_force_recovery = 6  # 数据恢复参数,在数据表结构异常时使用(缺省值为0)
port = 3306
pid-file        = /var/run/mysqld/mysqld.pid
socket          = /var/run/mysqld/mysqld.sock
datadir         = /var/lib/mysql
log-error       = /var/log/mysql/error.log
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
max_connections = 2000
max_user_connections = 1900
max_connect_errors = 100000
max_allowed_packet = 50M
lower_case_table_names=1
# datetime
default-time_zone = 'Asia/Shanghai'
log_timestamps = SYSTEM
# GTID
server-id=2
gtid_mode = ON
enforce_gtid_consistency=1
master-info-repository=TABLE
relay-log-info-repository=TABLE
relay_log_purge=OFF
# Binlog
log-bin = mysql-binlog
# relay-log
relay-log=relay-bin

[mysqld]
skip-name-resolve
sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION

—END

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

云计算-Security

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值