服务器双机热备解决方案:从心跳配置到切换脚本的完整指南
简介这份《服务器双机热备解决方案》文档面向运维工程师、系统架构师及需要保障业务连续性的技术人员系统讲解如何通过两台服务器互为备份来避免单点故障导致的服务中断与数据丢失。内容涵盖双机热备的定义与适用场景、心跳机制与拓扑结构、active/standby热备、双机互备、双机双工三种工作模式以及共享存储与纯软件两种实现方式并给出RoseHA、RoseMirrorHA等软件的具体部署思路与软硬件清单。资源包共1个docx文件约71KB结构紧凑适合作为方案选型与实施参考。文档还从高性能、高可用性、安全性、监控直观、易维护等角度总结方案设计特点并附有Dell R730服务器参数与实施清单便于读者快速理解双机容错系统的搭建逻辑与关键配置要点。目前已有159人学习下载适合需要提升网络服务可靠性的运维人员参考借鉴。1. 服务器双机热备解决方案从“一台挂了全完”到“切换时业务无感”凌晨两点监控告警响了主库那台机器 SSH 连不上业务接口 502。你手忙脚乱登上备机发现数据落后了 40 分钟配置文件还是上个月的版本。这种场景我见过太多次问题从来不是“有没有备机”而是“备机到底能不能顶上去”。服务器双机热备解决方案要解决的核心就一件事让两台机器对外表现为一个持续可用的服务主机故障时备机接管且数据丢失和中断时间都在可接受范围内。它适合所有跑着数据库、Web 服务、中间件但又没有预算上集群的中小规模业务。这篇笔记不讲虚的从心跳怎么配、数据怎么同步、切换脚本怎么写到真实踩过的坑一步步拆开。2. 双机热备的三种模式先选对架构再动手2.1 主备、主主、双活到底差在哪很多人一上来就问“用 Keepalived 还是 Pacemaker”其实更该先问的是你的业务能接受多长的中断数据允许丢多少这两个问题决定了架构模式。主备模式Active-Standby是最常见的做法。一台机器承载全部流量另一台待命。主机心跳丢失后备机通过 VIP 漂移接管服务。优点是逻辑简单、数据一致性容易保证缺点是备机平时闲着资源利用率低。适合数据库这类“写操作必须单点”的场景。主主模式Active-Active两台都跑服务但通常只对无状态服务可行比如 Nginx 反向代理层。数据库层面做双主写入需要处理冲突复杂度陡增没有强需求不建议碰。双活模式严格来说要求两端同时承载读写流量且数据实时双向同步这需要分布式共识协议支撑比如基于 Raft 的方案。对大多数团队来说这已经超出“双机热备”的范畴属于分布式数据库要解决的问题。我一般建议Web/应用层用主主 负载均衡数据层用主备 半同步复制。这样既利用了备机资源又保证了数据不丢。2.2 心跳检测Keepalived 的 VRRP 怎么配才不脑裂选定了主备模式接下来就是心跳。心跳的本质是备机要能判断“主机是真的死了还是只是我联系不上它”。Keepalived 基于 VRRP 协议通过组播或单播发送心跳包是最轻量的方案。先看一个最小可用的 Keepalived 配置。主备两台机器上各装一个 Keepalived配置文件放在/etc/keepalived/keepalived.conf# 主机MASTER配置 global_defs { router_id node_master # 节点标识主备必须不同 enable_script_security # 允许执行自定义检查脚本 } vrrp_script check_nginx { script /usr/bin/killall -0 nginx # 检测 nginx 进程是否存在 interval 2 # 每 2 秒检查一次 weight -30 # 检查失败时优先级减 30 fall 2 # 连续失败 2 次才判定为 down rise 2 # 连续成功 2 次才判定为 up } vrrp_instance VI_1 { state MASTER # 备机改为 BACKUP interface eth0 # 心跳网卡必须与实际网卡名一致 virtual_router_id 51 # 主备必须相同同一网段内不能冲突 priority 100 # 主机优先级备机设为 90 advert_int 1 # 心跳间隔 1 秒 authentication { auth_type PASS auth_pass 1234abcd # 主备密码必须一致 } virtual_ipaddress { 192.168.1.100/24 # 对外提供服务的 VIP } track_script { check_nginx # 关联上面的检查脚本 } notify_master /etc/keepalived/notify.sh master # 切换时执行 notify_backup /etc/keepalived/notify.sh backup notify_fault /etc/keepalived/notify.sh fault }备机配置只需要改三处state改为BACKUPpriority改为 90router_id改为node_backup。其余保持一致。这里有几个参数直接决定切换行为。advert_int是心跳间隔设得太短会增加网络负担太长则故障发现慢1 秒是常用值。fall和rise控制状态判定的“迟钝程度”设成 2 意味着连续两次检测失败才切换能过滤掉偶发的网络抖动。weight -30配合priority 100当 nginx 挂掉时主机优先级降到 70低于备机的 90触发切换——这就是“服务级”健康检查比单纯 ping 通更有意义。注意virtual_router_id在同一广播域内绝对不能重复否则会出现两个节点抢同一个 VIP 的诡异现象排查起来非常头疼。2.3 数据同步rsync inotify 还是 DRBD心跳解决了“谁来接管”但备机接管后数据是不是最新的这是双机热备里最容易翻车的地方。常见做法有三种方案原理适用场景数据丢失风险rsync inotify文件变更触发增量同步配置文件、静态资源、小文件秒级延迟可能丢最后几个文件DRBD块设备级实时镜像数据库文件、需要强一致的场景几乎为零但配置复杂数据库原生复制MySQL 半同步 / PostgreSQL 流复制数据库专用可控取决于复制模式我一般会分层处理配置文件用 rsync inotify 做准实时同步数据库用原生半同步复制。DRBD 虽然强但脑裂后的恢复流程极其痛苦没有专职运维不建议上。先看 rsync inotify 的落地。备机上跑一个 rsync 守护进程主机上用 inotifywait 监听目录变化并触发推送# 备机启动 rsync 守护进程编辑 /etc/rsyncd.conf [app_config] path /data/app/config read only false auth users syncuser secrets file /etc/rsyncd.secrets # 主机安装 inotify-tools 后编写同步脚本 /opt/sync.sh #!/bin/bash SRC/data/app/config/ DESTsyncuser192.168.1.101::app_config PASSWORD_FILE/etc/rsync.pass inotifywait -mrq --timefmt %Y-%m-%d %H:%M --format %T %w%f %e \ -e modify,create,delete,move $SRC | while read DATE TIME FILE EVENT; do rsync -avz --delete --password-file$PASSWORD_FILE $SRC $DEST echo [$DATE $TIME] $FILE $EVENT synced /var/log/sync.log doneinotifywait的-m表示持续监听-r递归子目录-q安静模式只输出事件。-e指定关注的事件类型这里覆盖了修改、创建、删除、移动四种。rsync的--delete保证备机目录和主机完全一致删掉的文件在备机也会删掉——这个参数要慎用如果备机目录里有人工放置的文件会被清掉。数据库层面以 MySQL 为例半同步复制配置如下-- 主机 my.cnf [mysqld] server-id 1 log-bin mysql-bin binlog_format ROW sync_binlog 1 innodb_flush_log_at_trx_commit 1 -- 主机执行安装半同步插件 INSTALL PLUGIN rpl_semi_sync_master SONAME semisync_master.so; SET GLOBAL rpl_semi_sync_master_enabled 1; SET GLOBAL rpl_semi_sync_master_timeout 3000; -- 3 秒无应答降级为异步 -- 备机 my.cnf [mysqld] server-id 2 relay-log relay-bin read_only 1 -- 备机执行 INSTALL PLUGIN rpl_semi_sync_slave SONAME semisync_slave.so; SET GLOBAL rpl_semi_sync_slave_enabled 1; CHANGE MASTER TO MASTER_HOST192.168.1.100, MASTER_USERrepl, MASTER_PASSWORDRepl1234, MASTER_LOG_FILEmysql-bin.000001, MASTER_LOG_POS0; START SLAVE;rpl_semi_sync_master_timeout是关键参数。半同步意味着主机提交事务时要等备机确认收到 binlog 才算成功。如果备机迟迟不响应主机会在超时后自动降级为异步复制避免业务被拖死。3000 毫秒是个折中值设太短容易误降级设太长故障时业务卡顿明显。3. 切换脚本与 VIP 漂移让业务真正无感3.1 notify 脚本里该做什么Keepalived 的notify_master、notify_backup、notify_fault三个钩子是切换时执行自定义逻辑的入口。很多人只配了 VIP 漂移就以为完事了结果备机接管后服务没起来VIP 挂在备机上但端口不通业务照样挂。一个完整的 notify 脚本至少要做四件事启动/停止本地服务、挂载/卸载数据目录、发送告警通知、记录切换日志。#!/bin/bash # /etc/keepalived/notify.sh STATE$1 LOG/var/log/keepalived_switch.log DATE$(date %Y-%m-%d %H:%M:%S) case $STATE in master) echo [$DATE] 切换为 MASTER启动服务 $LOG systemctl start nginx systemctl start mysql # 如果用了 DRBD这里执行挂载 # mount /dev/drbd0 /data ;; backup) echo [$DATE] 切换为 BACKUP停止服务 $LOG systemctl stop nginx systemctl stop mysql # umount /data ;; fault) echo [$DATE] 进入 FAULT 状态请立即检查 $LOG # 发送告警比如调用 webhook curl -s -X POST http://192.168.1.200:9090/alert \ -d {\msg\:\双机热备节点故障\,\time\:\$DATE\} ;; esac脚本必须加执行权限且 Keepalived 默认以 root 运行脚本里的命令路径要写绝对路径否则可能因为 PATH 环境变量不同而找不到命令。3.2 用自定义检查脚本替代简单的进程检测killall -0 nginx只能检测进程是否存在但进程活着不代表服务正常。比如 nginx 进程在但 worker 全部卡死端口不响应这时候 Keepalived 不会切换。更可靠的做法是写一个健康检查脚本真正去请求本地服务#!/bin/bash # /etc/keepalived/check_service.sh # 返回 0 表示健康非 0 表示异常 # 检查 HTTP 接口 HTTP_CODE$(curl -s -o /dev/null -w %{http_code} --max-time 3 http://127.0.0.1:8080/health) if [ $HTTP_CODE ! 200 ]; then exit 1 fi # 检查数据库连接 mysql -urepl -pRepl1234 -e SELECT 1 /dev/null 21 if [ $? -ne 0 ]; then exit 1 fi exit 0然后在 Keepalived 配置里把vrrp_script的script指向这个脚本。--max-time 3限制 curl 超时时间避免脚本本身卡住导致检测间隔失准。这个脚本每 2 秒跑一次对服务本身有轻微开销但换来的是更准确的故障判断。3.3 切换时间能压到多少从主机故障到备机接管总切换时间由三部分组成故障检测时间 VIP 漂移时间 服务启动时间。故障检测时间 advert_int × fall按上面的配置是 1 秒 × 2 2 秒。VIP 漂移在局域网内通常 1 秒以内。服务启动时间取决于服务本身nginx 通常 1 秒内MySQL 可能需要 5 到 30 秒取决于 InnoDB 恢复。所以整体切换时间在 5 到 35 秒之间。如果业务要求 5 秒以内恢复数据库层需要做额外优化比如预热、调整 InnoDB 恢复参数或者改用真正的主主架构。不要相信“零切换”的宣传任何主备方案都有中断窗口区别只在于窗口多长。4. 避坑指南双机热备最常见的五个翻车现场4.1 脑裂两台机器都认为自己是主机现象VIP 同时出现在两台机器上客户端请求时而通时而不通数据库出现双写导致数据错乱。原因心跳网络中断但两台机器之间的服务网络是通的。备机收不到主机心跳认为主机挂了把自己升为 MASTER主机那边觉得自己还活着继续持有 VIP。这就是脑裂。解决加冗余心跳链路。如果服务器有两块网卡用独立网卡跑心跳不要和业务流量混在一起。更稳妥的做法是引入第三方仲裁比如用一台独立机器跑一个简单的 ping 检测或者用 Pacemaker Corosync 的 quorum 机制。Keepalived 本身没有仲裁能力只能靠nopreempt和优先级来降低概率不能根除。4.2 备机数据落后太多接管后业务读到旧数据现象切换后备机起来了但用户发现最近几分钟的订单不见了。原因异步复制下主机 binlog 还没传到备机就挂了。或者 rsync 同步脚本因为某个大文件卡住后续变更全部堆积。解决数据库用半同步复制至少保证一个备机确认收到 binlog。文件同步加监控/var/log/sync.log里超过 10 秒没有新记录就告警。另外备机的数据目录权限要和主机一致否则 MySQL 启动时会因为权限问题失败这个坑很隐蔽。4.3 VIP 漂移了但服务没起来现象ip addr看到 VIP 在备机上但curlVIP 的端口不通。原因notify 脚本没配或者脚本执行失败。Keepalived 只负责漂移 VIP不负责启动服务。另外如果服务启动需要挂载数据盘而数据盘没挂上服务也会启动失败。解决notify 脚本里加日志每次切换都记录执行结果。脚本里用set -x临时开启调试确认每一步都执行成功。服务启动命令后面加 echo start ok $LOG失败时能快速定位。4.4 防火墙挡住了 VRRP 组播现象主备配置完全一样但备机始终是 BACKUP主机挂了也不切换。原因VRRP 默认使用组播地址 224.0.0.18如果防火墙没放行备机收不到心跳但主机发的心跳备机也收不到——等等这样备机应该会认为主机挂了才对。实际情况更微妙如果防火墙只单向拦截可能出现主机能收到备机心跳、备机收不到主机心跳的情况导致备机一直以为主机活着不切换。解决iptables -I INPUT -p vrrp -j ACCEPT或者改用单播模式。Keepalived 支持unicast_peer配置直接指定对端 IP不走组播更可控vrrp_instance VI_1 { ... unicast_src_ip 192.168.1.100 # 本机 IP unicast_peer { 192.168.1.101 # 对端 IP } }4.5 切换后旧主机恢复数据被覆盖现象主机修好后重新上线Keepalived 把它加回集群结果备机同步过来的数据被主机上的旧数据覆盖了。原因主机恢复后如果配置的state是 MASTER 且优先级更高它会抢回 VIP。但此时主机上的数据可能比备机旧如果同步方向没控制好旧数据会反向覆盖新数据。解决主机恢复后不要自动抢回配置nopreempt让备机继续做 MASTER人工确认数据一致后再手动切换。或者用notify_backup脚本在主机降为 BACKUP 时先从备机拉一次全量数据再启动服务。5. 进阶用 Pacemaker Corosync 做更精细的资源管理Keepalived 适合“VIP 服务”这种简单模型但如果你的双机热备涉及多个资源比如 VIP、文件系统、数据库、自定义服务且资源之间有依赖关系Pacemaker Corosync 是更专业的选择。Corosync 负责心跳通信和成员管理Pacemaker 负责资源调度和故障转移。它支持资源组、顺序约束、位置约束能表达“先挂载文件系统再启动数据库最后漂移 VIP”这种逻辑。一个典型的配置流程# 安装 yum install -y pacemaker corosync pcs systemctl enable --now pcsd # 设置 hacluster 密码两台机器都要执行 echo Hacluster123 | passwd --stdin hacluster # 在任意一台机器上认证并创建集群 pcs cluster auth node1 node2 -u hacluster -p Hacluster123 pcs cluster setup --name mycluster node1 node2 pcs cluster start --all pcs cluster enable --all # 关闭 STONITH实验环境生产环境应配置 pcs property set stonith-enabledfalse pcs property set no-quorum-policyignore # 创建资源 pcs resource create VIP ocf:heartbeat:IPaddr2 ip192.168.1.100 cidr_netmask24 op monitor interval10s pcs resource create FS ocf:heartbeat:Filesystem device/dev/sdb1 directory/data fstypeext4 op monitor interval20s pcs resource create DB ocf:heartbeat:mysql binary/usr/bin/mysqld config/etc/my.cnf datadir/data/mysql op monitor interval15s # 创建资源组按顺序启动 pcs resource group add appgroup VIP FS DB # 设置资源粘性避免频繁切换 pcs resource defaults resource-stickiness100resource-stickiness100表示资源倾向于留在当前节点只有当前节点确实不可用时才切换。这个值设得太低会导致网络抖动时资源来回漂移设得太高则故障后不切换100 是个常用起点。Pacemaker 的优势在于它知道资源之间的依赖切换时会按正确顺序停止和启动。比如 VIP 会先漂移走然后文件系统卸载最后数据库停止——在备机上反向操作。Keepalived 做不到这种编排。但 Pacemaker 的复杂度也高得多。配置错误时集群可能进入不可预测的状态排查需要看/var/log/cluster/corosync.log和pcs status的输出。我的习惯是先用 Keepalived 跑通基本的主备切换确认业务能接受这个中断窗口再考虑要不要上 Pacemaker。不要一上来就追求“完美方案”能解决问题的简单方案就是好方案。验证切换是否可靠不能只看一次成功。我一般会做三轮测试第一轮手动systemctl stop keepalived模拟服务退出第二轮iptables -A INPUT -p vrrp -j DROP模拟心跳中断第三轮直接echo c /proc/sysrq-trigger强制内核崩溃模拟最极端的宕机。每轮都记录切换时间和数据丢失量反复调到满意为止。这个习惯帮我省掉了好几次生产环境的后悔药。希望帮到你。本文还有配套的精品资源点击获取