Mysql高可用

案例概述

目前 MySQL 已经成为市场上主流数据库之一,考虑到业务的重要性,MySQL 数据库单点问题已成为企业网站架构中最大的隐患。随着技术的发展,MHA 的出现就是解决 MySQL 单点的问题。另外随着企业数据量越来越庞大,数据库的压力又成为企业的另一个瓶颈,MySQL 多主多从架构的出现可以减轻 MySQL 本身的压力。本章将主要围绕 “MySQL 主主复制 + Keepalived + HAProxy” 这一经典高可用架构展开,通过理论结合实践,解析如何通过开源工具实现数据库的故障自动转移、负载均衡和读写分离。

案例前置知识点

1.1 什么是 MySQL 高可用

MySQL 高可用(High Availability)是指通过冗余设计,确保数据库服务在单节点故障、网络中断或硬件损坏等异常情况下,仍能持续对外提供服务,同时保证数据一致性。其核心目标是实现 “零停机、零数据丢失” 的业务连续性。

 方案组成

MySQL 主主复制 + Keepalived + HAProxy 的高可用方案由三部分组成:

MySQL 主主复制:两台 MySQL 实例互为主从,双向同步数据,均支持读写操作,提供冗余和扩展能力。

Keepalived:通过 VRRP 协议管理虚拟 IP(VIP),监控 MySQL 状态,故障时自动将 VIP 漂移至存活节点,确保服务地址不变。

HAProxy:作为反向代理和负载均衡器,将流量分发至 MySQL 节点,支持健康检查、读写分离(可选)和故障节点自动剔除。

 优势

高可用性:Keepalived 实现秒级故障切换,HAProxy 健康检查确保流量仅路由到正常节点,避免单点故障。

读写扩展:主主架构支持双节点并发写入,提升写入性能;HAProxy 可配置读写分离,利用备节点分担读压力。

灵活扩展:可横向扩展 HAProxy 或 MySQL 节点,支持动态调整负载均衡策略(如轮询、权重)。
运维友好:基于开源工具,无厂商锁定,社区支持丰富,适合自建数据库集群。

 案例环境

本案例环境

案例环境如表 7-1 所示。

主机 操作系统 IP 地址 应用
Master1 openEuler 24.03 192.168.10.101 Mysql8
Master2 openEuler 24.03 192.168.10.102 Mysql8
Keepalived1 openEuler 24.03 192.168.10.103 Keepalived、haproxy
Keepalived2 openEuler 24.03 192.168.10.104 Keepalived、haproxy

案例需求

本案例要求通过 MHA 监控 MySQL 数据库在故障时进行自动切换,不影响业务。

2.3 案例实现思路

(1)安装 MySQL 数据库;
(2)配置 MySQL 互为主从;
(3)安装 haproxy 软件并配置复制均衡;
(4)安装 keepalived 软件并配置故障转移;
(5)模拟 master 故障切换

二、案例实施

1. 安装 MySQL 数据库

在 Master1、Master2 服务器上安装 MySQL 数据库。本案例采用二进制安装

 基础环境准备

如果采用 OpenEuler minimal 安装的系统,在使用前需要安装一些基础软件包工具。

[root@localhost ~]# yum -y install gcc vim wget net-tools lrzsz

安装 MySQL 依赖的软件包

[root@localhost ~]# dnf install -y libaio numactl openssl ncurses-compat-libs

创建运行 MySQL 程序的用户

[root@localhost ~]# useradd -M -s /sbin/nologin mysql

关闭 SELinux 和防火墙

[root@localhost ~]# sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config
[root@localhost ~]# setenforce 0
[root@localhost ~]# systemctl disable firewalld
[root@localhost ~]# systemctl stop firewalld
二进制安装

二进制安装的版本采用跟上面编译安装的版本一样 MySQL 8.0.36。首先需要下载该软 件包或者提前上传,然后再解压进行配置。

[root@localhost ~]# tar xJf mysql-8.0.36-linux-glibc2.28-x86_64.tar.xz
[root@localhost ~]# mv mysql-8.0.36-linux-glibc2.28-x86_64 /usr/local/mysql
2025-03-19T13:28:28.959651Z 0 [System] [MY-013169] [Server] /usr/local/mysql/bin/mysqld (mysqld 8.0.36) initializing of server in progress as process 6414
2025-03-19T13:28:28.968618Z 1 [System] [MY-013576] [InnoDB] InnoDB 
initialization has started.
2025-03-19T13:28:29.141927Z 1 [System] [MY-013577] [InnoDB] InnoDB initialization has ended.
2025-03-19T13:28:30.473508Z 6 [Note] [MY-010454] [Server] A temporary password is generated for root@localhost: Xr6:Ggnu8?/8

此次初始化没有采用无密码模式,因此会生成初始随机密码,需要保存,用以后续登录 mysql 数据库使用

(3) 设定配置文件

MySQL 的配置文件跟上面编译安装的配置文件类似。

[root@localhost ~]# vim /etc/my.cnf
[client]
socket=/usr/local/mysql/data/mysql.sock

[mysqld]
socket=/usr/local/mysql/data/mysql.sock
bind-address = 0.0.0.0
skip-name-resolve
port = 3306
basedir=/usr/local/mysql
datadir=/usr/local/mysql/data
max_connections=2048
character-set-server=utf8
default-storage-engine=INNODB
max_allowed_packet=16M

将 MySQL 的可执行文件写入环境变量中。

[root@localhost ~]# echo "export PATH=$PATH:/usr/local/mysql/bin">> /etc/profile
[root@localhost ~]# . /etc/profile        //使配置在当前 Shell 中生效

(4) 配置 systemctl 方式启动

将 MySQL 添加成为系统服务,通过使用 systemctl 来管理。在 /usr/local/mysql/support-files 目录下找到 mysql.server 文件,将其复制到 /etc/rc.d/init.d 目录下,改名为 mysqld 并赋予可执行权限。

[root@localhost ~]# cp /usr/local/mysql/support-files/mysql.server /etc/rc.d/init.d/mysqld
[root@localhost ~]# chmod +x /etc/rc.d/init.d/mysqld

编辑生成 mysqld.service 服务,通过 systemctl 方式来管理。

[root@localhost ~]# vim /lib/systemd/system/mysqld.service
[Unit]
Description=mysqld
After=network.target

[Service]
Type=forking
ExecStart=/etc/rc.d/init.d/mysqld start
ExecReload=/etc/rc.d/init.d/mysqld restart
ExecStop=/etc/rc.d/init.d/mysqld stop
PrivateTmp=true

[Install]
WantedBy=multi-user.target
[root@localhost ~]# systemctl daemon-reload
[root@localhost ~]# systemctl enable mysqld
[root@localhost ~]# systemctl start mysqld
[root@localhost ~]# netstat -tunlp |grep 3306
tcp        0      0 0.0.0.0:3306            0.0.0.0:*               LISTEN      1785/mysqld        
[root@localhost ~]# mysqladmin -u root -p password 'pwd123' //为 root 用户设置密码

登录 MySQL 程序,创建测试用户,后续验证实验时使用。(Master1、Master2 都执行)

[root@localhost ~]#mysql -u root -p
mysql> CREATE USER 'test'@'192.168.10.%' IDENTIFIED BY '123456';
Query OK, 0 rows affected (0.01 sec)
mysql> GRANT ALL ON *.* TO 'test'@'192.168.10.%';
Query OK, 0 rows affected (0.01 sec)
mysql> ALTER  USER  'test'@'192.168.10.%'  IDENTIFIED  WITH mysql_native_password BY '123456';
#MySQL 8.0 默认使用 caching_sha2_password 认证插件,将 mysql_native_password 替换为旧版认证插件,确保从库能兼容
mysql> FLUSH PRIVILEGES;

 配置 mysql 双主复制

对于 MySQL 的主主架构,其实原理就是两台服务器 Master1、Master2 互为主从,双向复制

在 Master1 /etc/my.cnf 中修改或者增加下面内容。

log - bin = /usr/local/mysql/data/mysql - bin #启用二进制日志(Binary Log)并指定其存储路径
binlog_format = MIXED #定义二进制日志的记录格式为混合模式
server - id = 1 #为 mysql 实例分配一个唯一的服务器标识符

在 Master2 /etc/my.cnf 中修改或者增加下面内容。

log - bin = /usr/local/mysql/data/mysql - bin #启用二进制日志(Binary Log)并指定其存储路径
binlog_format = MIXED #定义二进制日志的记录格式为混合模式
server - id = 2 #为 mysql 实例分配一个唯一的服务器标识符

重启 MySQL 服务。(Master1、Master2 都执行)

[root@localhost ~]# systemctl restart mysqld

登录 MySQL 程序,给从服务器授权。(Master1、Master2 都执行)

[root@localhost ~]# mysql -u root -p
mysql> CREATE USER 'myslave'@'192.168.10.%' IDENTIFIED BY '123456';
Query OK, 0 rows affected (0.01 sec)
mysql> GRANT REPLICATION SLAVE ON . TO 'myslave'@'192.168.10.%';
Query OK, 0 rows affected (0.01 sec)
mysql> ALTER USER 'myslave'@'192.168.10.%' IDENTIFIED WITH mysql_native_password BY '123456';

MySQL 8.0 默认使用 caching_sha2_password 认证插件,将 mysql_native_password 替换为旧版认证插件,确保从库能兼容

mysql> FLUSH PRIVILEGES;
mysql> show master status;

其中 File 列显示日志名,Position 列显示偏移量,这两个值在后面配置从服务器的时候需要。Slave 应该从该点上进行新的更新。

登录 MySQL,配置同步。(Master1、Master2 都执行)

Master1
按主服务器结果更改下面命令中 master_log_file 和 master_log_pos 参数。

[root@localhost ~]# mysql -uroot -p
mysql> change master to master_host='192.168.10.102',master_user='myslave', master_password='123456',master_log_file='mysql - bin.000001',master_log_pos=157;
Query OK, 0 rows affected, 8 warnings (0.01 sec)

启动同步。

mysql> start slave;
Query OK, 0 rows affected (0.00 sec)

查看 Slave 状态,确保以下两个值为 YES

[root@localhost ~]# mysql -uroot -p -e "show slave status\G" | grep Yes
Enter password:
             Slave_IO_Running: Yes
             Slave_SQL_Running: Yes

Master2

按主服务器结果更改下面命令中 master_log_file 和 master_log_pos 参数。

[root@localhost ~]# mysql -uroot -p
mysql> change master to master_host='192.168.10.101',master_user='myslave', master_password='123456',master_log_file='mysql-bin.000001',master_log_pos=157;
Query OK, 0 rows affected, 8 warnings (0.01 sec)

启动同步。

mysql> start slave;
Query OK, 0 rows affected (0.00 sec)

查看 Slave 状态,确保以下两个值为 YES

[root@localhost ~]# mysql -uroot -p -e "show slave status\G" | grep Yes
Enter password:
             Slave_IO_Running: Yes
             Slave_SQL_Running: Yes
安装 haproxy

HAProxy 是一个开源的高性能负载均衡器和代理工具,支持 TCP/HTTP 应用的流量分发,具备健康检查、SSL 终止、会话保持等功能,广泛应用于 Web 服务器集群、数据库读写分离及 API 网关场景,以高效稳定的特性提升系统可用性和扩展能力。

该阶段操作在 Keepalived1、Keepalived2 都要执行

关闭 SELinux 和防火墙
[root@localhost ~]# sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config
[root@localhost ~]# setenforce 0
[root@localhost ~]# systemctl disable firewalld
[root@localhost ~]# systemctl stop firewalld
安装 haproxy
[root@localhost ~]# dnf install haproxy
编辑 haproxy 配置文件

内容如下,更改部分红色标注(Keepalived1、Keepalived2 配置相同)

[root@localhost ~]# vim /etc/haproxy/haproxy.cfg
global
    log         127.0.0.1 local2
    chroot      /var/lib/haproxy
    pidfile     /var/run/haproxy.pid
    user        haproxy
    group       haproxy
    daemon
    maxconn     4000

defaults
    mode                    tcp
    log                     global
    option                  tcplog
    option                  dontlognull
    retries                 3
    timeout http-request    10s
    timeout queue           1m
    timeout connect         10s
    timeout client          1m
    timeout server          1m
    timeout http-keep-alive 10s
    timeout check           10s
    maxconn                 3000

listen mysql
    bind 0.0.0.0:3306               # 显式指定监听地址和端口
    balance leastconn              # 负载均衡算法
    server mysql1 192.168.10.101:3306 check port 3306 maxconn 300
    server mysql2 192.168.10.102:3306 check port 3306 maxconn 300

注释:

  • mode tcp:表示 tcp 代理
  • listen mysql 0.0.0.0:3306:表示创建一个名为 mysql 的监听服务,bind 0.0.0.0:3306 绑定到所有网卡的 3306 端口(MySQL 默认端口),作为流量入口。
  • balance leastconn:指定使用 “最少连接数算法” 分配请求,将新连接导向当前活跃连接数最少的后端服务器,避免单点过载
  • server mysql1 192.168.10.101:3306 和 server mysql2 192.168.10.102:3306:分别指向 192.168.10.101:3306 和 192.168.10.102:3306。
  • check port 3306:表示通过检查节点的 3306 端口是否响应,判断其存活状态

maxconn 300

限制每个后端节点的最大并发连接数为 300,防止节点被压垮

(4) 检测配置文件,并启动服务

plaintext

[root@localhost ~]# haproxy -c -f /etc/haproxy/haproxy.cfg
[root@localhost ~]# systemctl restart haproxy

(5) 测试

使用测试用户 test,访问 haproxy 的代理端口登录 mysql

[root@localhost ~]# mysql -u test -p123456 -h192.168.10.103 -P3306
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 26
Server version: 8.0.36 Source distribution

Copyright (c) 2000, 2025, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> 

Mysql高可用_第1张图片

提取文字

4. 安装 keepalived

Keepalived 是一个用于实现系统高可用性和负载均衡的工具,通过 VRRP(Virtual Router Redundancy Protocol)等协议管理虚拟 IP 地址,持续监测服务器健康状态,当主节点故障时自动将流量切换至备用节点,确保服务不中断,常用于数据库、Web 服务等集群环境,提升系统可靠性并简化故障恢复流程。

该阶段操作在 Keepalived1、Keepalived2 都要执行

关闭 SELinux 和防火墙
[root@localhost ~]# sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config
[root@localhost ~]# setenforce 0
[root@localhost ~]# systemctl disable firewalld
[root@localhost ~]# systemctl stop firewalld
 安装 keepalived
[root@localhost ~]# dnf install keepalived
编辑 haproxy 配置文件

Keepalived1 配置,红色标注为两台不同之处,需要注意

[root@localhost ~]# cp /etc/keepalived/keepalived.conf.sample /etc/keepalived/keepalived.conf
[root@localhost ~]# vim /etc/keepalived/keepalived.conf
!Configuration File for keepalived

global_defs {
    router_id r1
}

vrrp_script chk_haproxy {
    script "/etc/keepalived/chk.sh"
    interval 2
}

vrrp_instance VI_1 {
    state BACKUP
    nopreempt
    interface ens33
    virtual_router_id 51
    priority 100
    advert_int 1
 authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        192.168.10.100
    }

    track_script {
        chk_haproxy
    }

    notify_backup "/etc/init.d/haproxy restart"
    notify_fault "/etc/init.d/haproxy stop"
}

启用 nopreempt 的作用:
节点 A(优先级 100,配置 nopreempt)故障 → 节点 B 成为 Master。
节点 A 恢复 → 不触发抢占,节点 B 继续作为 Master,VIP 不切换。
仅当节点 B 故障时,节点 A 才会重新成为 Master。

添加监控脚本并启动 Keepalived

[root@localhost ~]# vim /etc/keepalived/chk.sh
#!/bin/bash
if [ `ps -C haproxy --no-header | wc -l` -eq 0 ]; then
    /etc/init.d/keepalived stop
fi
[root@localhost ~]# chmod +x /etc/keepalived/chk.sh
[root@localhost ~]# systemctl start keepalived

Keepalived2 配置,红色标注为两台不同之处,需要注意

[root@localhost ~]# cp /etc/keepalived/keepalived.conf.sample /etc/keepalived/keepalived.conf
[root@localhost ~]# vim /etc/keepalived/keepalived.conf
!Configuration File for keepalived

global_defs {
    router_id r2
}
vrrp_script chk_haproxy {
    script "/etc/keepalived/chk.sh"
    interval 2
}

vrrp_instance VI_1 {
    state BACKUP
    interface ens33
    virtual_router_id 51
    priority 99
    advert_int 1

    authentication {
        auth_type PASS
        auth_pass 1111
    }

    virtual_ipaddress {
        192.168.10.100
    }

    track_script {
        chk_haproxy
    }

    notify_backup "/etc/init.d/haproxy restart"
    notify_fault "/etc/init.d/haproxy stop"
}

添加监控脚本并启动keepalived

[root@localhost ~]# vim /etc/keepalived/chk.sh
#!/bin/bash
#
if [ `ps -C haproxy --no-header | wc -l` -eq 0 ]; then
    /etc/init.d/keepalived stop
fi
[root@localhost ~]# chmod +x /etc/keepalived/chk.sh
[root@localhost ~]# systemctl restart keepalived

此处两台主机均配置为 BACKUP,因此哪台先运行 keepalived,VIP 就在哪台上。
本案例刚开始 VIP 运行在 Keepalived1 上。

在 Keepalived1 测试查看 VIP(注意查看 VIP 只能用 ip 命令,ifconfig 不显示 VIP)

[root@localhost ~]# ip a
1: lo:  mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: ens33:  mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 00:0c:29:ac:a8:01 brd ff:ff:ff:ff:ff:ff
    inet 192.168.10.103/24 brd 192.168.10.255 scope global noprefixroute ens33
       valid_lft forever preferred_lft forever
    inet 192.168.10.100/32 scope global link
       valid_lft forever preferred_lft forever
    inet6 fe80::20c:29ff:feac:a801/64 scope link 
       valid_lft forever preferred_lft forever

 测试使用 VIP 连接 mysql

[root@localhost ~]# mysql -utest -p123456 -h192.168.10.100
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 28
Server version: 8.0.36 Source distribution

Copyright (c) 2000, 2025, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> \q
Bye

测试故障转移

1. 关闭 master1 主机,测试使用 vip 能否正常访问 mysql 数据库

关闭 master1 后,haproxy 检测其状态异常,会从负载中移除,不进行流量转发;依然可以通过 vip 访问 mysql,实现 mysql 的高可用

[root@localhost ~]# ping 192.168.10.101   # ping master1 发现已离线  
PING 192.168.10.101 (192.168.10.101) 56(84) bytes of data.  
来自 192.168.10.104 icmp_seq=1 目标主机不可达  

[root@localhost ~]# mysql -utest -p123456 -h192.168.10.100  
mysql: [Warning] Using a password on the command line interface can be insecure.  
Welcome to the MySQL monitor.  Commands end with ; or \g.  
Your MySQL connection id is 22  
Server version: 8.0.36 Source distribution  

Copyright (c) 2000, 2024, Oracle and/or its affiliates.  

Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners.  

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.  

mysql>  

接着关闭 keepalived1,测试使用 vip 能否正常访问 mysql 数据库

关闭 keepalived1 后,keepalived 检测到主节点离线,VIP 192.168.10.100 会漂移至 keepalived2 节点,mysql 依然可以访问

[root@localhost ~]# mysql -utest -p123456 -h192.168.10.100
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 22
Server version: 8.0.36 Source distribution

Copyright (c) 2000, 2024, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>

你可能感兴趣的:(mysql,数据库)