找回密码
 立即注册
首页 业界区 安全 Mysql + Keepalived 高可用架构(防脑裂版) ...

Mysql + Keepalived 高可用架构(防脑裂版)

懵诬哇 昨天 19:30
MySQL+Keepalived 主从高可用(无脑裂版)

文档说明

适配环境:CentOS 7+/Ubuntu 20.04+,MySQL 5.7/8.0

架构拓扑:

角色服务器 IP核心说明虚拟 VIP192.168.10.100业务统一接入地址主节点(Node1)192.168.10.15初始主库,故障后自动释放 VIP备节点(Node2)192.168.10.16初始备库,接管 VIP 后自动升主当前环境:Ubuntu 24.4操作系统 ,ARM架构 ,MySQL版本mysql-8.0.44

核心特性:

1、主库 MySQL 故障 → 自动停止本机 Keepalived,触发 VIP 漂移
2、备库接管 VIP 后 → 自动关闭只读、升主为可写主库
3、全链路防脑裂、防双主、
一、前置环境准备(两台节点全部执行)

1. 关闭防火墙(避免 VRRP 通信异常)
  1. systemctl disable --now ufw
复制代码
2. 时间同步(高可用必做)
  1. systemctl enable --now chronydchronyc sources
复制代码
3.安装基础依赖工具()
  1. apt update && apt install -y net-tools chrony libaio1 libncurses5-dev libnuma-dev
复制代码
二、MySQL 8.0.44 二进制包安装(两台节点全部执行)

1. 上传并解压 MySQL 安装包

假设你已将 mysql-8.0.44-linux-glibc2.28-aarch64.tar.xz 上传到 /usr/local/src/ 目录。
  1. cd /usr/local/src/# 解压tar -xf mysql-8.0.44-linux-glibc2.28-aarch64.tar.xz# 移动到标准目录并重命名mv mysql-8.0.44-linux-glibc2.28-aarch64 /usr/local/mysql
复制代码
2. 创建 MySQL 用户和数据目录
  1. # 创建用户组groupadd mysql# 创建用户useradd -r -g mysql -s /bin/false mysql# 创建数据目录mkdir -p /data/mysql# 授权chown -R mysql:mysql /data/mysqlchown -R mysql:mysql /usr/local/mysql
复制代码
3.配置 MySQL 主节点配置文件
  1. cat > /etc/my.cnf  /etc/my.cnf > /etc/profile  /etc/systemd/system/mysqld.service  /etc/keepalived/check_mysql.sh > $LOG_FILE}# ====================== 【前置自动校验】防止PEER_IP配置错误 ======================if [ "$PEER_IP" = "$LOCAL_IP" ]; then    log "【配置错误】PEER_IP不能和本机IP相同!当前本机IP=$LOCAL_IP,PEER_IP=$PEER_IP,请修改为对方节点的IP!"    exit 0fiif [ -z "$PEER_IP" ]; then    log "【配置错误】PEER_IP不能为空,请填写对方节点的IP!"    exit 0fi# ====================== 第一步:先检测VIP是否在本机(区分主备) ======================$IP_CMD addr show | $GREP_CMD -qw "$VIP/24" >/dev/null 2>&1HAS_VIP=$?# ====================== 第二步:MySQL健康检测 ======================$MYSQL_CMD -hlocalhost -P$MYSQL_PORT -u$MYSQL_USER -p$MYSQL_PASS --connect-timeout=$MYSQL_CONN_TIMEOUT -e "SELECT 1" >/dev/null 2>&1LOCAL_MYSQL_OK=$?# ====================== 第三步:核心逻辑:主库故障处理 ======================# 情况1:本机是主库(持有VIP)+ MySQL故障 → 先打全日志,再后台执行stopif [ $HAS_VIP -eq 0 ] && [ $LOCAL_MYSQL_OK -ne 0 ]; then    log "【主库故障】本机$LOCAL_IP持有VIP:$VIP,MySQL故障,即将停止keepalived触发VIP漂移"    log "【主库故障】VIP:$VIP将从本机$LOCAL_IP漂移到对方节点$PEER_IP"        # 后台执行stop操作,主脚本先退出,保证日志完整    (        sleep 0.5        systemctl stop keepalived        sleep 1        systemctl stop keepalived        echo "[$($DATE_CMD "+%Y-%m-%d %H:%M:%S")] 【主库故障】keepalived已停止,VIP:$VIP已完成漂移到$PEER_IP" >> $LOG_FILE    ) >> $LOG_FILE 2>&1 &        exit 1fi# 情况2:本机是备库(无VIP)+ MySQL故障 → 只记录日志,不停止keepalivedif [ $HAS_VIP -ne 0 ] && [ $LOCAL_MYSQL_OK -ne 0 ]; then    log "【备库告警】本机$LOCAL_IP无VIP,MySQL故障,仅记录告警,不触发切换"    exit 0fi# ====================== 第四步:MySQL正常时,执行防脑裂+升主逻辑 ======================# 获取MySQL只读状态MYSQL_STATUS=$($MYSQL_CMD -hlocalhost -P$MYSQL_PORT -u$MYSQL_USER -p$MYSQL_PASS --connect-timeout=$MYSQL_CONN_TIMEOUT -e "SHOW VARIABLES LIKE 'read_only';SHOW VARIABLES LIKE 'super_read_only';" -sN 2>/dev/null)READ_ONLY=$(echo "$MYSQL_STATUS" | $GREP_CMD -w read_only | $AWK_CMD '{print $2}')SUPER_READ_ONLY=$(echo "$MYSQL_STATUS" | $GREP_CMD -w super_read_only | $AWK_CMD '{print $2}')# 防脑裂逻辑:VIP不在本机但本机可写 → 强制降主if [ $HAS_VIP -ne 0 ] && [ "$SUPER_READ_ONLY" = "OFF" ] && [ "$READ_ONLY" = "OFF" ]; then    log "【防脑裂】VIP:$VIP不在本机$LOCAL_IP,但本机是可写主库!强制降主为只读!"    $MYSQL_CMD -hlocalhost -P$MYSQL_PORT -u$MYSQL_USER -p$MYSQL_PASS --connect-timeout=$MYSQL_CONN_TIMEOUT -e "SET GLOBAL read_only=ON;SET GLOBAL super_read_only=ON;" >/dev/null 2>&1    if [ $? -eq 0 ]; then        log "【防脑裂】强制降主成功,本机$LOCAL_IP已变为只读"    fifi# 自动升主逻辑:VIP在本机且是只读 → 升主if [ $HAS_VIP -eq 0 ]; then    log "VIP:$VIP已绑定在本机$LOCAL_IP"    if [ "$SUPER_READ_ONLY" = "ON" ] || [ "$READ_ONLY" = "ON" ]; then        log "检测到本机$LOCAL_IP为只读状态,开始执行升主操作"        $MYSQL_CMD -hlocalhost -P$MYSQL_PORT -u$MYSQL_USER -p$MYSQL_PASS --connect-timeout=$MYSQL_CONN_TIMEOUT -e "STOP REPLICA;RESET REPLICA ALL;SET GLOBAL read_only=OFF;SET GLOBAL super_read_only=OFF;" >/dev/null 2>&1        if [ $? -eq 0 ]; then            log "升主命令执行成功"            NEW_STATUS=$($MYSQL_CMD -hlocalhost -P$MYSQL_PORT -u$MYSQL_USER -p$MYSQL_PASS --connect-timeout=$MYSQL_CONN_TIMEOUT -e "SHOW VARIABLES LIKE 'read_only';SHOW VARIABLES LIKE 'super_read_only';" -sN 2>/dev/null)            NEW_READ_ONLY=$(echo "$NEW_STATUS" | $GREP_CMD -w read_only | $AWK_CMD '{print $2}')            NEW_SUPER_READ_ONLY=$(echo "$NEW_STATUS" | $GREP_CMD -w super_read_only | $AWK_CMD '{print $2}')            if [ "$NEW_SUPER_READ_ONLY" = "OFF" ] && [ "$NEW_READ_ONLY" = "OFF" ]; then                log "升主成功,本机$LOCAL_IP已成为可写主库,VIP:$VIP已成功接管"            fi        fi    else        log "本机$LOCAL_IP已是可写主库,跳过升主操作"    fifilog "本机$LOCAL_IP MySQL运行正常,所有检查通过"exit 0EOF
复制代码
2、192.168.10.16检测脚本(仅修改 PEER_IP)
  1. # 复制上面的脚本,仅修改这一行PEER_IP="192.168.10.15"
复制代码
3、脚本赋权与初始化(两台节点都执行)
  1. # 赋权chmod +x /etc/keepalived/check_mysql.shchown root:root /etc/keepalived/check_mysql.sh# 初始化日志文件touch /var/log/check_mysql.logchmod 644 /var/log/check_mysql.log
复制代码
六、服务启动与初始状态验证

1、 服务启动顺序
  1. # 1. 先启动两台节点的MySQLsystemctl start mysqld# 2. 再启动两台节点的Keepalivedsystemctl daemon-reloadsystemctl enable --now keepalived
复制代码
2、初始状态检查项
  1. # 1. 检查VIP是否在主节点(10.15)ip a | grep 192.168.10.100# 2. 检查Keepalived状态systemctl status keepalived# 3. 检查脚本日志,无报错tail -20 /var/log/check_mysql.log
复制代码
1.png

2.png

七、故障切换模拟测试

测试场景 1:主库(10.15)MySQL 故障切换

预期:
1、VIP成功转移到192.168.10.16节点
2、日志有完整的故障以及接管记录
3、192.168.10.16选举为主,读写正常。
  1. #操作步骤#主库(10.15)执行:systemctl stop mysqld#新开两个窗口,分别查看两台节点的日志# 主库窗口tail -f /var/log/check_mysql.log# 备库窗口tail -f /var/log/check_mysql.log
复制代码
3.png

4.png

5.png

6.png

7.png

VIP 已漂移到备库(10.16),备库可正常写入数据。
  1. #进到从库,进行查看目前从库是否已经切换为主,仅读模式是否关闭SHOW VARIABLES LIKE '%read_only%';SHOW MASTER STATUS \G;#创建测试库成功CREATE DATABASE test555;
复制代码
8.png

9.png

进行192.168.10.15恢复模拟。

因为每一次启动故障节点都要设置为可读模式,以及同步信息配置;所以我在这里写了一个脚本,方便每次启动MySQL进行可读、从库配置;直接执行这个脚本就行啦。
[code]root@fsdong:~# cat /root/mysql_to_slave_15.sh #!/bin/bash# 【修复GTID版】15节点自动配置为16节点从库# 新增:RESET MASTER重置GTID,解决GTID不一致导致的同步失败LOG_FILE="/var/log/mysql_slave_init.log"DATE=$(date "+%Y-%m-%d %H:%M:%S")MYSQL_CMD="/usr/bin/mysql"MYSQL_USER="root"MYSQL_PASS="Root@123456"echo "[$DATE] 开始将15节点配置为16节点从库..." >> $LOG_FILE# 1. 设置只读,禁止写入$MYSQL_CMD -hlocalhost -u$MYSQL_USER -p$MYSQL_PASS -e "SET GLOBAL read_only = ON;SET GLOBAL super_read_only = ON;" >/dev/null 2>&1echo "[$DATE] 已开启数据库只读模式" >> $LOG_FILE# 2. 停止并清理旧同步$MYSQL_CMD -hlocalhost -u$MYSQL_USER -p$MYSQL_PASS -e "STOP SLAVE;RESET SLAVE ALL;" >/dev/null 2>&1echo "[$DATE] 已清理旧主从同步配置" >> $LOG_FILE# 3. 重置GTID(核心修复:解决GTID不一致问题)$MYSQL_CMD -hlocalhost -u$MYSQL_USER -p$MYSQL_PASS -e "RESET MASTER;" >/dev/null 2>&1echo "[$DATE] 已重置GTID集合,解决切换后GTID不一致问题" >> $LOG_FILE# 4. 配置新主库(16节点)$MYSQL_CMD -hlocalhost -u$MYSQL_USER -p$MYSQL_PASS -e "CHANGE MASTER TOMASTER_HOST='192.168.10.16',MASTER_USER='repl',MASTER_PASSWORD='Repl@123456',MASTER_PORT=3306,MASTER_AUTO_POSITION=1;" >/dev/null 2>&1echo "[$DATE] 已指向新主库 192.168.10.16" >> $LOG_FILE# 5. 启动同步$MYSQL_CMD -hlocalhost -u$MYSQL_USER -p$MYSQL_PASS -e "START SLAVE;" >/dev/null 2>&1echo "[$DATE] 已启动主从同步" >> $LOG_FILE# 6. 输出同步状态(验证结果)sleep 2STATUS=$($MYSQL_CMD -hlocalhost -u$MYSQL_USER -p$MYSQL_PASS -e "SHOW SLAVE STATUS\G" 2>/dev/null | grep -E "Slave_IO_Running|Slave_SQL_Running")echo "[$DATE] 同步状态:$STATUS" >> $LOG_FILEecho "========================================" >> $LOG_FILEecho "✅ 15节点配置为从库完成!"echo "
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册