服务器双机热备实战:Keepalived 高可用架构与脑裂防护指南
简介这份《服务器双机热备解决方案》文档面向运维工程师、系统架构师及需要保障业务连续性的技术人员系统讲解如何通过两台服务器互为备份来避免单点故障导致的服务中断与数据丢失。内容涵盖双机热备的定义与适用场景、心跳机制与拓扑结构、active/standby热备、双机互备、双机双工三种工作模式以及共享存储与纯软件两种实现方式并给出方案设计中的高性能、高可用、安全性、监控直观与易维护等要点。资源包内共1个docx文档约71KB结构完整、条理清晰适合作为方案选型与实施参考。目前已有159人学习下载。读者可从中获取双机热备的完整知识框架、模式对比与实施思路快速理解RoseHA、RoseMirrorHA等双机软件的工作机制为实际项目中的高可用方案设计提供参考。1. 双机热备到底在保什么从一次凌晨三点的切换说起很多团队第一次认真考虑服务器双机热备解决方案都不是在架构评审会上而是在某个凌晨三点——业务方电话打过来说服务挂了你登上去一看主节点进程还在端口也通但数据库连接池满了或者磁盘 IO 卡死整个系统处于一种活着但没用的状态。这时候你才意识到所谓高可用不是服务器没宕机而是业务能持续响应。双机热备要解决的核心问题就是让两台服务器或两组节点在对外看来始终是一个可用的服务入口当主节点因为硬件故障、系统崩溃、网络抖动甚至人为误操作而无法正常提供服务时备用节点能在可接受的时间内接管并且数据不能丢、状态不能乱。这套方案适合谁适合那些业务中断成本远高于硬件成本的中小规模系统——比如内部管理系统、区域性的业务平台、中小型数据库服务。它不适合超大规模分布式场景那种场景下双机热备只是最底层的一块砖。但如果你手里只有两台物理机或者两台云主机又不想让业务在单点故障面前裸奔那双机热备就是性价比最高的选择。接下来我会把选型逻辑、心跳配置、数据同步、切换脚本和排错方法一层层拆开让你能照着搭出一套真正能扛事的双机热备。2. 先选型再动手双机热备的三种主流路线与适用边界2.1 主备、主主、双活到底怎么选双机热备在工程落地时通常有三种形态。第一种是主备模式Active-Standby一台对外服务另一台待命通过心跳检测判断主节点状态故障时切换。这种模式最简单、最不容易出数据冲突缺点是备用节点平时资源闲置。第二种是主主模式Active-Active两台同时对外服务通常配合负载均衡故障时流量自动切到存活节点。它资源利用率高但要求应用本身支持无状态或分布式锁否则会出现写冲突。第三种是双活严格来说双活不只是两台服务器而是两个站点同时承载业务数据双向同步对网络延迟和数据一致性要求极高一般需要数据库层或存储层支持多活复制。对于大多数只给了两台机器的场景我一般推荐主备模式。原因很直接数据一致性最容易保证切换逻辑最清晰排错时变量最少。主主模式听起来美好但一旦应用层没有做好幂等和分布式协调切换瞬间的重复请求就能把数据库写乱。双活则往往需要额外的仲裁节点或共享存储两台机器很难独立完成。2.2 共享存储还是数据复制数据同步的两种底层逻辑选完模式紧接着要决定数据怎么同步。常见做法有两类共享存储和数据复制。共享存储是两台服务器挂载同一个存储设备比如 SAN、NAS 或云盘数据只有一份主节点写入备节点直接读取。它的优点是数据强一致切换时不需要追数据缺点是存储本身成了单点而且成本高很多中小场景没有条件上。数据复制则是两台服务器各自有本地磁盘通过数据库主从复制、文件同步工具或块设备复制把数据从主节点传到备节点。它的优点是硬件成本低、部署灵活缺点是存在复制延迟切换时可能丢最后一部分数据。我通常建议如果业务对数据丢失零容忍且预算允许优先考虑共享存储或云厂商提供的高可用盘如果预算有限那就用数据库原生复制比如 MySQL 主从、PostgreSQL 流复制加上文件层 rsync 或 DRBD把 RPO 控制在秒级。这里的关键是不要试图用应用层双写来替代底层复制双写的一致性几乎不可能在故障时保证。2.3 心跳线怎么连串口、网线还是网络心跳心跳是双机热备的神经。没有心跳备节点就不知道主节点是死是活。常见心跳方式有三种串口心跳、直连网线心跳和网络心跳。串口心跳最可靠不受网络栈影响但现代服务器很多没有串口而且速率低。直连网线心跳用一根网线把两台机器的网卡直连走独立的子网不经过交换机避免了网络设备故障导致的双向误判。网络心跳则是通过现有业务网络发送心跳包部署最简单但一旦网络抖动或交换机故障可能出现双主——两台都以为对方挂了同时抢占资源。我的经验是至少做两条心跳线一条直连网线一条走业务网络。心跳软件如 Keepalived、Pacemaker支持多播或单播配置时把直连网线作为主心跳通道业务网络作为备用。这样即使交换机挂了直连心跳还能正常工作避免脑裂。如果只能走网络心跳那一定要在交换机上做好端口隔离和 STP 配置并且把心跳包优先级调高。2.4 用 Keepalived 搭最小可用的主备切换下面以 Keepalived 为例给一个最小可用的主备配置。假设两台服务器主节点 IP 192.168.1.10备节点 192.168.1.11对外提供虚拟 IPVIP192.168.1.100。直连心跳网段用 10.0.0.0/30主节点 10.0.0.1备节点 10.0.0.2。先在主备节点都安装 Keepalived# Debian/Ubuntu 系 apt-get update apt-get install -y keepalived # RHEL/CentOS 系 yum install -y keepalived然后写主节点配置/etc/keepalived/keepalived.confglobal_defs { router_id HA_NODE_MASTER # 节点标识主备要不同 enable_script_security } vrrp_script chk_nginx { script /usr/bin/killall -0 nginx # 检测 nginx 进程是否存在 interval 2 # 每 2 秒检测一次 weight -20 # 检测失败则优先级减 20 fall 2 # 连续失败 2 次才认为故障 rise 2 # 连续成功 2 次才恢复 } vrrp_instance VI_1 { state MASTER interface eth0 # 业务网卡 virtual_router_id 51 # 主备必须一致 priority 100 # 主节点优先级高 advert_int 1 # 心跳间隔 1 秒 authentication { auth_type PASS auth_pass 12345678 # 主备密码一致 } unicast_src_ip 10.0.0.1 # 直连心跳源地址 unicast_peer { 10.0.0.2 # 直连心跳对端地址 } virtual_ipaddress { 192.168.1.100/24 dev eth0 # VIP } track_script { chk_nginx } }备节点配置只需改三处router_id改成HA_NODE_BACKUPstate改成BACKUPpriority改成 90unicast_src_ip改成 10.0.0.2unicast_peer改成 10.0.0.1。启动 Keepalivedsystemctl enable keepalived systemctl start keepalived systemctl status keepalived逻辑说明Keepalived 通过 VRRP 协议在心跳通道上交换状态。主节点优先级高持有 VIP备节点监听主节点心跳一旦超时未收到就根据优先级抢占 VIP。track_script里的chk_nginx是关键——它让 Keepalived 不仅看网络还看业务进程。如果 nginx 挂了主节点优先级减 20备节点就会抢走 VIP实现业务级切换。参数上interval和fall决定了检测灵敏度设得太小容易误切设得太大切换慢一般 2 秒检测、连续 2 次失败比较平衡。2.5 切换脚本里必须做的三件事Keepalived 只负责搬 VIP但业务进程的启停、存储挂载、连接清理往往需要额外脚本。常见做法是在vrrp_instance里加notify_master和notify_backup分别指定切换成主节点和备节点时执行的脚本。#!/bin/bash # /etc/keepalived/notify.sh # 参数$1 master|backup|fault$2 实例名 case $1 in master) # 成为主节点启动业务进程挂载数据盘 systemctl start nginx systemctl start mysql mount /dev/sdb1 /data 2/dev/null echo $(date) 切换为主节点 /var/log/ha-switch.log ;; backup) # 成为备节点停止业务进程卸载数据盘 systemctl stop nginx systemctl stop mysql umount /data 2/dev/null echo $(date) 切换为备节点 /var/log/ha-switch.log ;; fault) # 本节点故障记录日志尝试自救 echo $(date) 节点故障 /var/log/ha-switch.log ;; esac这个脚本里三件事必须做停掉旧角色进程、挂载或卸载数据盘、记录切换日志。尤其是卸载数据盘如果备节点在接管时没有先确认主节点已经释放了文件系统锁直接挂载可能导致数据损坏。所以脚本里要加锁判断或者依赖存储层的 SCSI 预留机制。日志则是事后排查的唯一线索切换时间、触发原因、执行结果都要落盘。3. 数据同步的坑复制延迟、脑裂与文件锁3.1 数据库主从复制延迟怎么压到秒级双机热备里最容易被忽视的就是复制延迟。主节点写入成功备节点还没收到 binlog这时候主节点挂了切换后备节点就少了最后几条数据。对于 MySQL常见做法是开启半同步复制semi-sync主节点至少等一个从节点确认收到 binlog 才返回成功。配置方式是在主从都安装rpl_semi_sync_master和rpl_semi_sync_slave插件然后设置-- 主节点 SET GLOBAL rpl_semi_sync_master_enabled 1; SET GLOBAL rpl_semi_sync_master_timeout 1000; -- 超时 1 秒退化为异步 -- 从节点 SET GLOBAL rpl_semi_sync_slave_enabled 1;半同步能把丢失窗口压到毫秒级但代价是写入延迟增加。如果网络质量差超时后退化成异步又回到原状。所以更稳妥的做法是业务层做幂等切换后允许少量重复或丢失但核心交易表用半同步日志表用异步。另外监控Seconds_Behind_Master这个指标超过阈值就告警别等切换时才发现延迟已经几分钟了。3.2 脑裂是怎么发生的双主抢占的三种典型场景脑裂是双机热备最危险的状态两台都认为自己是主节点同时挂载数据盘、同时写数据库结果数据错乱。它通常发生在三种场景。第一种是心跳线全断主备互相收不到心跳备节点以为主节点挂了抢占 VIP而主节点还在正常运行也持有 VIP。第二种是交换机故障业务网络不通但直连心跳还通或者反过来导致状态判断不一致。第三种是防火墙误拦心跳包尤其是云环境里安全组规则变更把 VRRP 协议或心跳端口封了。避免脑裂的核心手段是仲裁。两台机器无法仲裁所以要么加第三台机器做 ping 仲裁Keepalived 支持vrrp_script里 ping 一个网关或第三方地址要么用共享存储的锁机制。我一般会在vrrp_script里加一个 ping 网关的检测vrrp_script chk_gateway { script /bin/ping -c 1 -W 1 192.168.1.1 interval 3 weight -30 fall 2 rise 2 }这样如果业务网络断了主节点优先级下降备节点即使收到心跳也不会轻易抢占。但注意ping 网关本身也可能误判所以最好再配合 STONITHShoot The Other Node In The Head机制比如通过 IPMI 或云 API 强制关闭对方节点。没有 STONITH 的双机热备本质上是在赌心跳永远可靠。3.3 文件同步用 rsyncinotify 还是 DRBD如果业务涉及大量文件读写比如图片、日志、附件数据库复制不够还得同步文件。常见方案是rsyncinotify和DRBD。rsyncinotify是应用层方案inotify 监控目录变化触发 rsync 增量同步。它部署简单但同步是异步的切换时可能丢最后几个文件而且大量小文件时 inotify 容易漏事件。DRBD是块设备级复制主节点写磁盘DRBD 在块层把数据同步到备节点备节点磁盘实时保持一致。它更底层、更可靠但配置复杂且备节点不能同时挂载文件系统必须切换后才能挂载。我的建议是数据库用原生复制文件用 DRBD。如果文件量不大且能容忍少量丢失rsyncinotify也能凑合但一定要在切换脚本里加一次全量 rsync 兜底。DRBD 的配置这里不展开但记住一个原则DRBD 的主节点角色必须和 Keepalived 的主节点角色绑定否则会出现文件系统双重挂载。3.4 切换后 VIP 不通ARP 缓存和路由表排查切换完成后最常见的问题是 VIP ping 不通。原因通常有两个ARP 缓存和路由表。局域网内其他机器还缓存着旧主节点的 MAC 地址VIP 虽然漂移了但流量还是发到旧机器。解决办法是在切换脚本里主动发送免费 ARPgratuitous ARP通知网络更新映射# 切换为主节点后发送免费 ARP arping -c 3 -I eth0 -s 192.168.1.100 192.168.1.1或者用ip命令ip addr add 192.168.1.100/24 dev eth0 ip link set eth0 arp on另一个原因是路由表。如果 VIP 不在业务网段或者有多网卡切换后路由可能指向错误接口。排查时用ip route get 192.168.1.100看路由走向用tcpdump -i eth0 arp看 ARP 请求有没有到达。云环境里还要检查安全组和虚拟网络是否允许 VIP 漂移有些云厂商默认禁止非绑定 IP 的流量。4. 避坑与排查双机热备上线后最容易翻车的五件事4.1 备节点磁盘满了导致复制中断现象主节点正常备节点突然不再同步切换时发现备节点数据落后几小时。原因备节点磁盘空间被日志、临时文件或旧备份占满数据库复制线程或 DRBD 同步进程因写入失败而停止。解决给备节点加磁盘监控设置 80% 告警定期清理 binlog 和临时文件DRBD 配置里设置disk和meta分区独立避免元数据写满。我一般会在备节点加一个 cron 任务每天检查磁盘并清理超过 7 天的日志。4.2 心跳包被防火墙拦截导致误切现象业务网络正常但备节点频繁抢 VIP切换日志里全是主节点心跳超时。原因防火墙或安全组规则变更把 VRRP 协议IP 协议号 112或心跳端口封了。解决检查iptables -L -n和云安全组确保心跳网段双向放行 VRRP 和自定义心跳端口如果走单播确认源地址和目的地址都在规则里。更稳妥的做法是心跳走独立 VLAN不经过业务防火墙。4.3 切换脚本执行超时导致 VIP 漂移但业务没起来现象VIP 已经漂到备节点但业务端口还是不通用户访问超时。原因notify_master脚本里启动数据库或挂载磁盘耗时过长Keepalived 默认等待时间不够或者脚本里某个命令卡住。解决把脚本里的启动命令改成异步或加超时比如timeout 30 systemctl start mysql在 Keepalived 配置里调大notify_master的超时时间通过vrrp_instance的notify_master配合script超时参数切换后加健康检查确认业务端口监听再返回成功。4.4 双主写入导致数据错乱现象切换后数据库出现重复主键、数据覆盖或者文件系统损坏。原因脑裂导致两台同时挂载数据盘或同时写数据库。解决加仲裁节点或 STONITH数据库层开启read_only从库保护切换时先确认主库已降级文件系统用flock或 SCSI 预留做锁。最根本的是永远不要相信心跳绝对可靠一定要有第三方仲裁。4.5 云主机不支持 VIP 漂移现象在云环境里配好 KeepalivedVIP 漂移后外部访问不通。原因云厂商的虚拟网络默认禁止非绑定 IP 的 ARP 响应VIP 无法通过 ARP 宣告。解决改用云厂商提供的高可用 VIP 服务如弹性 IP 漂移、负载均衡后端切换或者用unicast模式配合云 API 在切换时重新绑定弹性 IP。如果必须用 Keepalived需要提交工单申请允许 VIP 漂移或者改用 DNS 切换方案。5. 进阶技巧用健康检查脚本把切换精度提到业务层前面讲的 Keepalived 加vrrp_script只能检测进程是否存在但进程活着不代表业务正常。比如 nginx 进程在但 upstream 全挂了MySQL 进程在但连接数满了拒绝服务。这时候就需要更细的健康检查脚本把切换触发点从进程挂了提前到业务不可用。我一般会写一个 HTTP 健康检查脚本检测关键接口的返回码和响应时间#!/bin/bash # /etc/keepalived/chk_business.sh # 返回 0 表示健康非 0 表示故障 URLhttp://127.0.0.1:8080/health TIMEOUT3 RETRY2 for i in $(seq 1 $RETRY); do HTTP_CODE$(curl -s -o /dev/null -w %{http_code} --max-time $TIMEOUT $URL) if [ $HTTP_CODE 200 ]; then exit 0 fi sleep 1 done # 连续失败再检查一次数据库连接 mysql -h 127.0.0.1 -u health -pxxx -e SELECT 1 /dev/null 21 if [ $? -ne 0 ]; then exit 1 fi exit 0然后在 Keepalived 里引用这个脚本vrrp_script chk_business { script /etc/keepalived/chk_business.sh interval 5 weight -40 fall 3 rise 2 }这个脚本的逻辑是先检查 HTTP 接口连续两次失败后再检查数据库连接只有两者都异常才判定故障。weight -40意味着一旦判定故障主节点优先级从 100 降到 60备节点 90 就能抢占。fall 3表示连续 3 次检测失败才切换避免网络抖动误切。interval 5是 5 秒一次整体切换时间在 15 到 20 秒之间对大多数业务可以接受。参数调优上weight的绝对值要大于主备优先级差值。比如主 100、备 90差值 10那weight至少 -20 才能让备节点抢到。fall和rise要根据业务容忍度调金融类可以设fall 2、interval 2内部系统可以放宽到fall 5、interval 10。另外健康检查脚本本身要轻量别在里面做全量查询或大文件 IO否则脚本自己成了故障源。验证切换是否可靠不能只靠手动重启主节点。我习惯做三类测试模拟进程崩溃kill -9 业务进程、模拟网络隔离iptables 封心跳端口、模拟资源耗尽用 stress 压满 CPU 或磁盘。每次测试后检查切换日志、VIP 归属、数据一致性。尤其是网络隔离测试能直接暴露脑裂风险。如果条件允许用两台虚拟机加一个仲裁节点做全链路演练比在生产环境直接切要安全得多。最后说个血泪教训双机热备的配置一定要版本化每次改完 Keepalived 或同步脚本先在一台隔离环境验证再推生产。我见过太多因为改了一个priority值或者注释了一行心跳配置导致备节点永远抢不到 VIP故障时才发现备节点根本没生效。另外切换脚本里的日志要写到独立分区别和业务日志混在一起否则切换时磁盘 IO 被日志写满脚本自己先卡死。希望帮到你。本文还有配套的精品资源点击获取