MySQL高可用终极指南:Keepalived实战精讲,从VIP漂移到主从切换,一篇搞定!

兄弟们,高可用这东西,不出事时岁月静好,一出事就是P1级故障。还记得那次吗?某核心交易系统,MySQL主库的存储IOPS突然飙到100%,整个实例hang死,别说交易了,连登录都登不上去。按理说,咱们的MySQL主从复制是配了的,备库数据也跟得紧紧的。但最要命的是,业务访问的那个VIP(虚拟IP),像被502胶水焊死了一样,还死死地钉在故障机上,导致业务全断。

项目经理的电话比闹钟还准时,三点准时响起,那语气,恨不得从电话线里爬过来掐我脖子。

查了半天,根源找到了:只做了数据层的高可用(主从复制),却忽略了服务层的高可用(VIP自动漂移) 。高可用是个"木桶",最短的那块板决定你的睡眠质量。你的数据同步得再快,应用访问不到也是白搭。

今天这篇,就是要把这块最短的板补上。我带你用Keepalived这个"神器",从零开始搭建一个真正能自动切换、让你睡得安稳的MySQL高可用架构。

1 Keepalived是个啥?

别被那些复杂的文档吓到,这玩意的原理其实很简单。

通俗解释: 你可以把Keepalived比作两个时刻准备"抢公章"(也就是我们的VIP)的办公室主任(两台MySQL服务器)。谁的"声望"(priority 优先级)高,默认就由谁拿着公章对外提供服务。这个拿着公章的主任,为了证明自己还活着,会定期在办公室里"吼一嗓子"(发送VRRP心跳通告),告诉另一位主任:"我还行,公章还在我这!" 如果大家在规定时间内没听到他吼,那么另一位主任就会立刻站出来,把公章抢过来,继续对外服务。

核心概念:

  • VRRP协议 (Virtual Router Redundancy Protocol): 虚拟路由冗余协议,这就是Keepalived实现高可用的技术基础,刚才说的"吼一嗓子"就是通过这个协议来的。

  • VIP (虚拟IP): 对外统一的服务入口,高可用的灵魂。应用程序连接的是这个永不改变的IP,它底下是哪台机器在干活,应用层完全无感。

  • MASTER/BACKUP 角色: 一个VRRP实例中,同一时间只有一台是MASTER(主),负责持有VIP。其他都是BACKUP(备),时刻准备接管。这个角色是根据priority值动态选举出来的。

这张图把关系说透了:客户端只认VIP。VIP平时在MASTER身上。MASTER和BACKUP之间通过VRRP心跳互相知晓对方的存活状态。一旦MASTER挂了,心跳中断,BACKUP就会把VIP"抢"过来。

2 环境准备与安装

光说不练假把式,开整!

环境规划:

  • 服务器A (主节点): mysql-node1,物理IP 192.168.31.101
  • 服务器B (备节点): mysql-node2,物理IP 192.168.31.102
  • 虚拟IP (VIP): 192.168.31.1010
  • 操作系统: Red Hat 8.2
  • Keepalived版本: 2.0.10 (RHEL 8 自带)

安装步骤 (RHEL 8): 这个简单,两台机器上都执行就行了,属于"抄作业"环节。

yaml 复制代码
# dnf -y install keepalived

# 执行结果如下
Local Repository                                                                                      2.7 MB/s | 2.8 kB     00:00    
Local Repository                                                                                      3.1 MB/s | 3.2 kB     00:00    
Dependencies resolved.
======================================================================================================================================
 Package                        Architecture   Version                               Repository                                  Size
======================================================================================================================================
Installing:
 keepalived                     x86_64         2.0.10-10.el8                         local-AppStream                            466 k
Installing dependencies:
 lm_sensors-libs                x86_64         3.4.0-21.20180522git70f7e08.el8       local                                       59 k
 mariadb-connector-c            x86_64         3.0.7-1.el8                           local-AppStream                            148 k
 net-snmp-agent-libs            x86_64         1:5.8-14.el8                          local-AppStream                            747 k
 net-snmp-libs                  x86_64         1:5.8-14.el8                          local                                      821 k

Transaction Summary
======================================================================================================================================
Install  5 Packages

Total size: 2.2 M
Installed size: 7.2 M
Downloading Packages:
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
  Running scriptlet: mariadb-connector-c-3.0.7-1.el8.x86_64                            1/1 
  Preparing        :                                                                   1/1 
  Installing       : net-snmp-libs-1:5.8-14.el8.x86_64                                 1/5 
  Installing       : mariadb-connector-c-3.0.7-1.el8.x86_64                            2/5 
  Installing       : lm_sensors-libs-3.4.0-21.20180522git70f7e08.el8.x86_64            3/5 
  Running scriptlet: lm_sensors-libs-3.4.0-21.20180522git70f7e08.el8.x86_64            3/5 
  Installing       : net-snmp-agent-libs-1:5.8-14.el8.x86_64                           4/5 
  Installing       : keepalived-2.0.10-10.el8.x86_64                                   5/5 
  Running scriptlet: keepalived-2.0.10-10.el8.x86_64                                   5/5 
  Verifying        : lm_sensors-libs-3.4.0-21.20180522git70f7e08.el8.x86_64            1/5 
  Verifying        : net-snmp-libs-1:5.8-14.el8.x86_64                                 2/5 
  Verifying        : keepalived-2.0.10-10.el8.x86_64                                   3/5 
  Verifying        : mariadb-connector-c-3.0.7-1.el8.x86_64                            4/5 
  Verifying        : net-snmp-agent-libs-1:5.8-14.el8.x86_64                           5/5 
Installed products updated.

Installed:
  keepalived-2.0.10-10.el8.x86_64        lm_sensors-libs-3.4.0-21.20180522git70f7e08.el8.x86_64      
  mariadb-connector-c-3.0.7-1.el8.x86_64      net-snmp-agent-libs-1:5.8-14.el8.x86_64     
  net-snmp-libs-1:5.8-14.el8.x86_64     

Complete!


## 确认版本
[root@node101 ~]# keepalived --version

防火墙配置:

⚠️ 生产大坑: 兄弟们注意了,这是我踩过最大的坑!必须放行VRRP协议!Keepalived主备节点之间靠VRRP协议通信,你把防火墙挡住了,它俩就成了"聋子和瞎子",互相都以为对方挂了,结果就是两边都抢着声明自己是MASTER,都去绑定VIP。这就是传说中的"脑裂"!业务流量一会打到A,一会打到B,数据不一致,等着背锅吧。

如果服务器上防火墙是开着的,得在两台机器上都执行:

arduino 复制代码
# firewall-cmd --add-rich-rule='rule protocol value="vrrp" accept' --permanent
# firewall-cmd --reload

内核参数调整: Keepalived需要把一个不属于本机网卡的IP(也就是VIP)绑定上来,默认Linux内核是不允许的。所以需要调整一个内核参数。

ini 复制代码
# echo "net.ipv4.ip_nonlocal_bind = 1" >> /etc/sysctl.conf
# sysctl -p

## 结果如下
[root@node101 ~]# sysctl -p
net.ipv4.ip_nonlocal_bind = 1

这个操作也是两台机器都要做。

3 高可用方案对决:自动 vs 手动

讲到这里,就到了十字路口。Keepalived给我们提供了能力,但怎么用这个能力,是门大学问。下面我给你端上两盘菜,一盘是"入门级自动切换",另一盘是"生产级手动切换",咱们把优缺点掰扯清楚了,你再决定在你的环境里用哪一盘。

方案一:入门级自动切换 (Keepalived + Notify脚本)

这个方案追求的是"无人值守",一旦MySQL出问题,系统自动完成VIP和数据库角色的切换。

A. 核心思路

咱们利用Keepalived的notify_*系列指令。当Keepalived的状态从BACKUP变成MASTER时,就自动触发一个我们写好的mysql_role_switch.sh脚本,让这个脚本去完成数据库的read_only状态切换。

B. 配置文件 (主备有别)

vi /etc/keepalived/keepalived.conf

主节点 mysql-node1 (192.168.31.101):

csharp 复制代码
! Configuration File for keepalived (Auto-Switch MASTER)

global_defs {
   # 路由ID,在一个局域网内,这个ID必须是唯一的,相当于Keepalived的身份证
   router_id MYSQL_HA_01
}

vrrp_script chk_mysql {
    script "/etc/keepalived/check_mysql.sh"  # 脚本路径
    interval 2                                # 每2秒执行一次
    weight -20                                # 如果脚本失败(退出码非0),则当前节点的优先级降低20
    fall 2                                    # 连续2次失败,才认为是真的失败
    rise 3                                    # 连续3次成功,才认为是真的恢复
}

vrrp_instance VI_MYSQL {
    state MASTER
    interface ens18
    virtual_router_id 51
    priority 101
    advert_int 1
    authentication { 
		auth_type PASS
		auth_pass 1111 
	}
    virtual_ipaddress { 
		192.168.31.100/24 dev ens18 label ens18:vip
	}
    track_script { 
		chk_mysql
	}

    # 状态变更时触发总司令脚本
    notify_master "/etc/keepalived/mysql_role_switch.sh MASTER"
    notify_backup "/etc/keepalived/mysql_role_switch.sh BACKUP"
    notify_fault "/etc/keepalived/mysql_role_switch.sh BACKUP"
}

备节点 mysql-node2 (192.168.31.102):

csharp 复制代码
! Configuration File for keepalived (Auto-Switch BACKUP)

global_defs {
   router_id MYSQL_HA_02
}

vrrp_script chk_mysql {
    # ... 配置与主节点完全一样 ...
}

vrrp_instance VI_MYSQL {
    state BACKUP
    interface ens18
    virtual_router_id 51
    priority 100
    advert_int 1
    nopreempt  # 关键!防止主库恢复后VIP来回抖动
    authentication { 
		auth_type PASS
		auth_pass 1111 
	}
    virtual_ipaddress { 
		192.168.31.100/24 dev ens18 label ens18:vip
	}
    track_script { 
		chk_mysql
	}

    # 状态变更时触发总司令脚本
    notify_master "/etc/keepalived/mysql_role_switch.sh MASTER"
    notify_backup "/etc/keepalived/mysql_role_switch.sh BACKUP"
    notify_fault "/etc/keepalived/mysql_role_switch.sh BACKUP"
}

核心参数讲解:

  • virtual_router_id: 主备的"接头暗号",必须一样,不然它俩不在一个频道,各玩各的。
  • priority: 选举的核心,谁的数字大谁就是MASTER。
  • vrrp_script & track_script: 这两个是黄金搭档。前者定义了"怎么检查",后者负责"把检查结果用起来"。当chk_mysql脚本执行失败,track_script就会让当前节点的priority减去weight定义的值(101 - 20 = 81)。81比备机的100低,于是VIP就漂移了。
  • nopreempt: 最佳实践 这个参数只在BACKUP节点上配。意思是"不抢占"。假设原来的主库mysql-node1只是网络抖动了一下,导致VIP切到了mysql-node2。几秒后mysql-node1恢复了,如果没有nopreempt,它的优先级(101)还是比mysql-node2(100)高,它会立刻把VIP抢回来。这一来一回的切换,对业务可能是致命的抖动。配置了nopreempt,就意味着只要mysql-node2还活着,即使mysql-node1恢复了,也得"靠边站",VIP不会切回去。这大大减少了不必要的切换,生产环境更稳定。

C. 核心脚本 (侦察兵 + 总司令)

check_mysql.sh负责高频侦察,mysql_role_switch.sh负责在收到Keepalived命令后,执行数据库角色切换的重操作。

/etc/keepalived/check_mysql.sh

bash 复制代码
#!/bin/bash

# 使用mysqladmin工具检查MySQL服务的可用性
mysqladmin ping -u root -p'YourComplexP@ssw0rd!_2025' > /dev/null 2>&1
# 检查上一条命令的退出码
if [ $? -eq 0 ]; then
    # 如果ping通,说明MySQL服务正常,脚本以退出码0结束
    exit 0
else
    # 如果ping不通,说明MySQL服务异常,脚本以退出码1结束
    exit 1
fi

/etc/keepalived/mysql_role_switch.sh

bash 复制代码
#!/bin/bash

STATE=$1
LOG_FILE="/var/log/keepalived-mysql-state.log"

echo "$(date): Script called with state $STATE" >> $LOG_FILE

case $STATE in
    "MASTER")
        echo "Transitioning to MASTER..." >> $LOG_FILE
        # 1. 停止从属关系
        mysql -u root -p'YourComplexP@ssw0rd!_2025' -e "STOP SLAVE;"
        
        # 2. 将数据库设置为可写
        mysql -u root -p'YourComplexP@ssw0rd!_2025' -e "SET GLOBAL read_only = OFF;"
        
        # 3. 如果需要,可以重置主库信息(在某些场景下需要)
        # mysql -u root -p'YourComplexP@ssw0rd!_2025' -e "RESET MASTER;"

        echo "Transition to MASTER finished." >> $LOG_FILE
        ;;
    "BACKUP")
        echo "Transitioning to BACKUP..." >> $LOG_FILE
        # 1. 将数据库设置为只读
        mysql -u root -p'YourComplexP@ssw0rd!_2025' -e "SET GLOBAL read_only = ON;"
        
        # 2. (可选但推荐) 尝试重新配置并启动与新主库的同步
        # 这一步比较复杂,通常需要外部脚本或人工介入来获取新主库的binlog位点
        # 在一个简单的自动切换场景中,可以暂时只做降级为只读的操作
        # mysql -u root -p'YourComplexP@ssw0rd!_2025' -e "START SLAVE;"

        echo "Transition to BACKUP finished." >> $LOG_FILE
        ;;
    *)
        echo "Unknown state. No action taken." >> $LOG_FILE
        exit 1
        ;;
esac

exit 0

注意:这两个脚本的权限和属主是否正确?脚本里的数据库密码是否做了安全处理?

bash 复制代码
chmod +x /etc/keepalived/check_mysql.sh /etc/keepalived/mysql_role_switch.sh
ls -l /etc/keepalived/check_mysql.sh /etc/keepalived/mysql_role_switch.sh

## 启动服务
systemctl enable --now keepalived
systemctl start keepalived
systemctl status keepalived


## 确认vip地址
ip addr dev ens18

## 查看日志
tail -f /var/log/messages | grep Keepalived

D. 切换演练

在主节点mysql-node1上执行systemctl stop mysqld,你会观察到VIP在几秒内自动漂移到mysql-node2,同时mysql-node2的数据库read_only状态自动变为OFF

运行脚本"模拟交易往数据库中插入数据,并检查vip飘逸情况

ini 复制代码
## 模拟交易,连接100
[root@node101 ~]# ./simulate_trx.sh 
开始模拟交易,按 CTRL+C 停止...
插入新交易: trx_id = 15048884, cust_id = 674, amt = 232.11,  耗时: .037132763s
插入新交易: trx_id = 15048885, cust_id = 752, amt = 116.62,  耗时: .035379153s

## 停止节点1 mysqld
[root@node101 ~]# systemctl stop mysqld


## 节点2上监听 VRRP协议的包
[root@node102 ~]# tcpdump -i any -n vrrp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
19:05:29.651565 IP 192.168.31.101 > 224.0.0.18: VRRPv2, Advertisement, vrid 51, prio 81, authtype simple, intvl 1s, length 20
19:05:30.651689 IP 192.168.31.101 > 224.0.0.18: VRRPv2, Advertisement, vrid 51, prio 81, authtype simple, intvl 1s, length 20
19:05:31.651886 IP 192.168.31.101 > 224.0.0.18: VRRPv2, Advertisement, vrid 51, prio 81, authtype simple, intvl 1s, length 20

## 观察节点1 keepalived日志
Nov 15 19:00:00 node101 Keepalived_vrrp[48612]: Script `chk_mysql` now returning 1
Nov 15 19:00:02 node101 Keepalived_vrrp[48612]: VRRP_Script(chk_mysql) failed (exited with status 1)
Nov 15 19:00:02 node101 Keepalived_vrrp[48612]: (VI_MYSQL) Changing effective priority from 101 to 81

## 观察节点2 keepalived日志
Nov 15 19:09:53 node102 Keepalived_vrrp[13558]: (VI_MYSQL) Backup received priority 0 advertisement
Nov 15 19:09:53 node102 Keepalived_vrrp[13558]: (VI_MYSQL) Receive advertisement timeout
Nov 15 19:09:53 node102 Keepalived_vrrp[13558]: (VI_MYSQL) Entering MASTER STATE
Nov 15 19:09:53 node102 Keepalived_vrrp[13558]: (VI_MYSQL) setting VIPs.
Nov 15 19:09:53 node102 Keepalived_vrrp[13558]: Sending gratuitous ARP on ens18 for 192.168.31.100
Nov 15 19:09:53 node102 Keepalived_vrrp[13558]: (VI_MYSQL) Sending/queueing gratuitous ARPs on ens18 for 192.168.31.100
Nov 15 19:09:53 node102 Keepalived_vrrp[13558]: Sending gratuitous ARP on ens18 for 192.168.31.100
Nov 15 19:09:53 node102 Keepalived_vrrp[13558]: Sending gratuitous ARP on ens18 for 192.168.31.100
Nov 15 19:09:53 node102 Keepalived_vrrp[13558]: Sending gratuitous ARP on ens18 for 192.168.31.100
Nov 15 19:09:53 node102 Keepalived_vrrp[13558]: Sending gratuitous ARP on ens18 for 192.168.31.100
Nov 15 19:09:58 node102 Keepalived_vrrp[13558]: Sending gratuitous ARP on ens18 for 192.168.31.100
Nov 15 19:09:58 node102 Keepalived_vrrp[13558]: (VI_MYSQL) Sending/queueing gratuitous ARPs on ens18 for 192.168.31.100
Nov 15 19:09:58 node102 Keepalived_vrrp[13558]: Sending gratuitous ARP on ens18 for 192.168.31.100
Nov 15 19:09:58 node102 Keepalived_vrrp[13558]: Sending gratuitous ARP on ens18 for 192.168.31.100
Nov 15 19:09:58 node102 Keepalived_vrrp[13558]: Sending gratuitous ARP on ens18 for 192.168.31.100
Nov 15 19:09:58 node102 Keepalived_vrrp[13558]: Sending gratuitous ARP on ens18 for 192.168.31.100

## 查看vip情况
[root@node101 ~]# ip addr show dev ens18
2: ens18: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether bc:24:11:33:db:80 brd ff:ff:ff:ff:ff:ff
    inet 192.168.31.101/24 brd 192.168.31.255 scope global noprefixroute ens18
       valid_lft forever preferred_lft forever
    inet6 240e:3a1:4a76:d360:9017:c87b:599f:5/128 scope global dynamic noprefixroute 
       valid_lft 6744sec preferred_lft 3144sec
    inet6 240e:3a1:4a76:d360:4360:afd0:895b:8930/64 scope global dynamic noprefixroute 
       valid_lft 7006sec preferred_lft 3406sec
    inet6 fe80::6bfb:14c8:d785:33ba/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever

[root@node102 ~]# ip addr show dev ens18
2: ens18: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether bc:24:11:70:62:0d brd ff:ff:ff:ff:ff:ff
    inet 192.168.31.102/24 brd 192.168.31.255 scope global noprefixroute ens18
       valid_lft forever preferred_lft forever
    inet 192.168.31.100/24 scope global secondary ens18:vip
       valid_lft forever preferred_lft forever
    inet6 240e:3a1:4a76:d360:766b:5fde:6699:9c81/64 scope global dynamic noprefixroute 
       valid_lft 7021sec preferred_lft 3421sec
    inet6 fe80::6bfb:14c8:d785:33ba/64 scope link dadfailed tentative noprefixroute 
       valid_lft forever preferred_lft forever
    inet6 fe80::dd3d:a0e0:db46:cca0/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever

## 查看节点2的状态
mysql> show variables like 'read_only';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| read_only     | OFF   |
+---------------+-------+
1 row in set (0.00 sec)

E. 方案弱点 (一针见血)

⚠️ 老兵提醒: 这个方案看起来很美,但在复杂的生产环境,它的"自动"可能会变成"自动惹祸":

  1. 没有"仲裁"机制: 如果主备之间的心跳网络断了(比如交换机故障),但两台服务器都活着,就会导致"脑裂"。双方都认为对方挂了,都抢着当MASTER,都会把自己变成可写,数据会彻底写乱

  2. 数据一致性隐患: 切换只依赖于简单的健康检查,没有MHA那种"捞数据"的过程。如果主库宕机前有一笔事务的binlog没来得及传到备库,这笔数据就永久丢失了。

  3. 恢复流程复杂: 老的主库修好后,怎么让它重新以SLAVE的身份加入集群?这个过程自动化脚本很难做得完美,大概率需要DBA手动介入,反而增加了操作风险。

正是因为有这些"坑",所以很多严谨的团队,特别是金融行业,会选择下面这种看起来"笨",但实际上更稳妥的方案。

方案二:生产级手动切换 (SOP保障)

这个方案的哲学是:机器负责监控和漂移VIP,但切换决策由人来做。 我们把Keepalived当成一个手动的、高效率的VIP切换工具,而不是一个自动决策系统。

A. 核心思路

两台服务器上的Keepalived配置文件完全一样 !并且,在任何时候,只允许一台服务器上的Keepalived服务是运行状态。切换时,我们严格按照标准操作流程(SOP),先手动完成数据库角色的确认和变更,然后再"一停一启"Keepalived服务,完成VIP的切换。

B. 统一配置文件 (两边完全一样)

把下面这份配置原封不动地放到mysql-node1mysql-node2/etc/keepalived/keepalived.conf

perl 复制代码
! Configuration File for keepalived (Manual-Switch)

global_defs {
   # 名字可以根据你的业务来,但两边要一样
   router_id MYSQL_HA_CLUSTER
}

vrrp_instance VI_MYSQL {
    # 默认都写MASTER,谁先启动谁就是MASTER
    state MASTER
    interface ens192             # 根据你的实际网卡修改
    virtual_router_id 51         # 必须一样
    priority 100                 # 优先级一样,谁先启动谁优先
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        192.168.31.100       # 根据你的VIP修改
    }
    # 注意!这个方案里,我们不使用任何的track_script或notify脚本!
}

⚠️ 关键点: 这个配置里没有track_script!Keepalived不再关心MySQL的死活,它只做一个纯粹的VIP管理工具。它的启停,完全由DBA掌控。

C. 标准切换流程

假设当前主库是mysql-node1,我们要切换到mysql-node2

第1步:在旧主库 mysql-node1 上操作

bash 复制代码
# 1. 停止Keepalived服务,释放VIP
systemctl stop keepalived
echo "Keepalived on old master stopped."

# 2. 确认VIP已释放
ip a | grep "192.168.31.100"  # 确保这条命令没有任何输出

# 3. 将旧主库设置为只读,防止新数据写入
mysql -e "SET GLOBAL read_only = ON;"
echo "Old master is now read-only."

第2步:在新主库 mysql-node2 上操作

bash 复制代码
# 1. 确认与旧主库的数据同步已完成 (非常重要!)
# 登录MySQL,执行 SHOW SLAVE STATUS\G,查看 Seconds_Behind_Master 是否为 0
# 在确认同步无延迟后,再进行下一步

# 2. 停止同步并提升为新主
mysql -e "STOP SLAVE; SET GLOBAL read_only = OFF;"
echo "New master promoted."

# 3. 启动Keepalived服务,接管VIP
systemctl start keepalived
echo "Keepalived on new master started."

第3步:验证

perl 复制代码
# 1. 在新主库 `mysql-node2` 上确认VIP已绑定
ip a | grep "192.168.31.100"  # 应该能看到VIP

# 2. 尝试用VIP连接数据库,并执行写操作,确认服务正常
# mysql -h 192.168.31.100 -u ... -p... -e "CREATE TABLE test_switch (id int); INSERT INTO test_switch VALUES (1);"

这个流程清晰、可控,每一步都有明确的检查点,最大限度地避免了自动切换带来的不确定性。

4 运维最佳实践

针对上面两种方案,我们的运维监控重点也不同。

监控:

  • 对于方案一 (自动): 必须重点监控/var/log/keepalived-mysql-state.log这个自定义日志文件。任何状态切换都应该触发最高级别的告警,通知DBA立即介入检查。同时,要监控主备两边read_only的状态是否符合预期。
  • 对于方案二 (手动): 监控的重点是 "Keepalived进程的唯一性" 。必须有一个监控项,确保集群中永远只有一个keepalived进程在运行。一旦发现两个都在运行,必须立即告警,这是脑裂的前兆!
  • 通用监控: VIP的归属、MySQL主从复制延迟(Seconds_Behind_Master)是两种方案都必须死盯的指标。

日志分析:

  • tail -f /var/log/messages | grep Keepalived 依然是排错第一神器。要学会看懂Entering MASTER stateEntering BACKUP state等关键日志。
  • 在方案一中,mysql_role_switch.sh脚本的输出日志是判断切换是否成功、哪里卡住的关键依据。

"脑裂" (Split-Brain) 防治:

  • 方案一 (自动): 脑裂风险较高,唯一的物理缓解措施就是使用独立、可靠的心跳网络,比如两台服务器用一根网线直连,专门跑VRRP协议。
  • 方案二 (手动): 从机制上杜绝了脑裂的发生。因为我们严格遵守"只启一个"的原则,只要SOP被严格执行,就不会出现两个节点都认为自己是主的混乱局面。这就是它"笨"却"稳"的核心优势。

5 总结

好了,兄弟们,今天我们把Keepalived配合MySQL的两种玩法都掰扯清楚了。

  • 方案一 (自动切换): 像一辆"自动驾驶汽车"。适合那些对RTO(恢复时间目标)要求极高,但对数据一致性容忍度稍高(比如允许丢失几秒数据)的非核心业务。优点是快,缺点是"方向盘"不在你手里,极端情况下可能失控。
  • 方案二 (手动切换): 像一辆"手动挡的越野车"。它把切换的最终决定权牢牢地交还给了DBA。每一步操作都在你的掌控之中。它牺牲了一点点切换速度,但换来的是极高的可靠性和数据安全性。这在金融、核心交易等场景,是毋庸置疑的选择。

技术方案没有绝对的"最好",只有"最合适"。你问我推荐哪个?在你不完全确定你的业务能承受自动切换带来的风险之前,我强烈建议你从方案二开始。 先用最稳的方法把高可用搭起来,把SOP流程跑到滚瓜烂熟。等你对整个系统的脾气都摸透了,再考虑是否需要向自动化演进。

记住,作为一个生产环境的DBA,"稳"字永远是第一位的。

相关推荐
青云计划9 小时前
知光项目知文发布模块
java·后端·spring·mybatis
Victor3569 小时前
MongoDB(9)什么是MongoDB的副本集(Replica Set)?
后端
Victor3569 小时前
MongoDB(8)什么是聚合(Aggregation)?
后端
yeyeye11110 小时前
Spring Cloud Data Flow 简介
后端·spring·spring cloud
Tony Bai11 小时前
告别 Flaky Tests:Go 官方拟引入 testing/nettest,重塑内存网络测试标准
开发语言·网络·后端·golang·php
+VX:Fegn089511 小时前
计算机毕业设计|基于springboot + vue鲜花商城系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
程序猿阿伟11 小时前
《GraphQL批处理与全局缓存共享的底层逻辑》
后端·缓存·graphql
小小张说故事12 小时前
SQLAlchemy 技术入门指南
后端·python
识君啊12 小时前
SpringBoot 事务管理解析 - @Transactional 的正确用法与常见坑
java·数据库·spring boot·后端
想用offer打牌13 小时前
MCP (Model Context Protocol) 技术理解 - 第五篇
人工智能·后端·mcp