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 通信异常)
- systemctl disable --now ufw
复制代码 2. 时间同步(高可用必做)
- systemctl enable --now chronydchronyc sources
复制代码 3.安装基础依赖工具()
- 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/ 目录。
- 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 用户和数据目录
- # 创建用户组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 主节点配置文件
- 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)
- # 复制上面的脚本,仅修改这一行PEER_IP="192.168.10.15"
复制代码 3、脚本赋权与初始化(两台节点都执行)
- # 赋权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. 先启动两台节点的MySQLsystemctl start mysqld# 2. 再启动两台节点的Keepalivedsystemctl daemon-reloadsystemctl enable --now keepalived
复制代码 2、初始状态检查项
- # 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:主库(10.15)MySQL 故障切换
预期:
1、VIP成功转移到192.168.10.16节点
2、日志有完整的故障以及接管记录
3、192.168.10.16选举为主,读写正常。
- #操作步骤#主库(10.15)执行:systemctl stop mysqld#新开两个窗口,分别查看两台节点的日志# 主库窗口tail -f /var/log/check_mysql.log# 备库窗口tail -f /var/log/check_mysql.log
复制代码
VIP 已漂移到备库(10.16),备库可正常写入数据。
- #进到从库,进行查看目前从库是否已经切换为主,仅读模式是否关闭SHOW VARIABLES LIKE '%read_only%';SHOW MASTER STATUS \G;#创建测试库成功CREATE DATABASE test555;
复制代码
进行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 "
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |