简介这份资源面向运维工程师与VoIP通信系统开发者聚焦Freeswitch高可用架构的落地实践通过Keepalived实现主备节点故障自动切换解决单点故障导致通信服务中断的问题。压缩包共4个文件约38KB包含2个Shell脚本、1份安装手册文本和1张Visio逻辑图分别用于健康检查与SSH辅助操作、Keepalived安装配置说明以及主备切换流程的可视化呈现。资源围绕主备节点配置、虚拟IP绑定、健康检查脚本、故障切换与逻辑图分析等环节展开读者可据此理解Keepalived监控Freeswitch状态并在异常时转移VIP的完整设计思路同时借助安装手册与脚本快速搭建实验环境、排查切换故障。目前已有668人学习下载适合需要构建可靠通信平台HA方案的技术人员参考。1. 文件服务高可用为什么单机 NFS 迟早会变成事故现场文件共享服务fs用 keepalived 做 HA本质上是把「一台机器挂掉所有人干不了活」这件事压缩成「VIP 漂移几秒业务几乎无感」。我见过太多团队把 NFS 或 Samba 单机部署在生产环境平时跑得好好的直到某天那块系统盘或者网卡抽风整个 CI 流水线、渲染农场、K8s 的 RWX 存储全部卡死。文件服务不像无状态 Web它是有状态的客户端已经建立了 TCP 连接、持有文件锁、缓存了目录项切换不是简单换个 IP 就完事。这套方案适合谁适合那些用 NFS/Samba 给内部几十到几百台机器提供共享存储、又不想上商业 NAS 或分布式文件系统的团队。keepalived 负责 VIP 和健康检查后端存储用 DRBD 或者共享 LUN 保证数据一致。设计逻辑图的核心就三块VIP 在哪、数据在哪、脑裂怎么防。下面我把这套东西从选型到配置到踩坑按我实际落地的顺序讲一遍。2. 先定架构再写配置VIP、存储与健康检查的三条线2.1 为什么是 keepalived DRBD 而不是 keepalived rsync文件服务 HA 的难点从来不是 VIP 漂移而是数据怎么跟着走。常见做法有三种共享 LUNSAN/iSCSI、DRBD 块级同步、rsync 文件级同步。我一般会先排除 rsync原因很直接rsync 是异步的主挂掉的瞬间从节点上缺的那部分数据就是永久丢失而且大目录首次同步能跑几个小时RTO 根本不可控。共享 LUN 是最干净的方案两台节点同时看到同一块盘但同一时刻只能有一台 mount。keepalived 切 VIP 的同时用 notify 脚本去 mount/umount。问题是很多中小环境没有 SAN这时候 DRBD 就是替代品。DRBD 在主从之间做块设备级实时同步协议 C 模式下主节点写操作要等从节点确认落盘才返回数据丢失窗口接近零。代价是写延迟增加千兆网下大概多 0.5 到 1ms万兆可以忽略。健康检查这条线容易被忽视。keepalived 默认只检查自己进程活没活但文件服务挂了 keepalived 还活着VIP 就不会切。所以必须写自定义 check 脚本去实际验证 NFS 或 Samba 能不能响应。我一般用showmount -e 127.0.0.1或者smbclient -L localhost做探针超时就降权。2.2 用 keepalived 配置 VIP 与 NFS 健康探针先看 keepalived 的主配置文件。下面这段是主节点MASTER的写法从节点把 state 改成 BACKUP、priority 调低即可。# /etc/keepalived/keepalived.conf global_defs { router_id fs_ha_node1 # 节点标识主从要不同 script_user root # 执行检查脚本的用户 enable_script_security } # 自定义健康检查验证 NFS 服务是否真的可用 vrrp_script chk_nfs { script /etc/keepalived/check_nfs.sh interval 3 # 每 3 秒检查一次 timeout 2 # 脚本 2 秒没返回算失败 fall 2 # 连续失败 2 次才认为服务挂了 rise 2 # 连续成功 2 次才恢复 weight -30 # 失败时优先级减 30触发切换 } vrrp_instance VI_FS { state MASTER interface eth0 # 承载 VIP 的网卡按实际改 virtual_router_id 51 # 主从必须一致 priority 100 # 主节点高从节点设 90 advert_int 1 # VRRP 通告间隔 1 秒 authentication { auth_type PASS auth_pass FsHa2024 # 主从一致别用弱密码 } virtual_ipaddress { 192.168.10.100/24 dev eth0 # 对外提供服务的 VIP } track_script { chk_nfs } notify_master /etc/keepalived/notify.sh master notify_backup /etc/keepalived/notify.sh backup notify_fault /etc/keepalived/notify.sh fault }逻辑说明vrrp_script定义了一个探针keepalived 按 interval 周期执行脚本脚本返回非 0 就累计失败次数达到 fall 阈值后按 weight 调整优先级。主节点优先级 100 减 30 变成 70低于从节点的 90VIP 就会漂移过去。track_script把探针绑定到实例上这是整个健康检查生效的关键漏写这行等于白写脚本。参数上最容易翻车的是weight。如果设成正数失败时优先级反而升高逻辑就反了。另外fall和rise别设太小网络抖动会导致 VIP 乒乓切换我一般 fall 至少 2、rise 至少 2配合 interval 3 秒整体切换判定在 6 到 9 秒之间。2.3 健康检查脚本与 VIP 切换时的存储挂载动作探针脚本要真的去问文件服务而不是看进程。#!/bin/bash # /etc/keepalived/check_nfs.sh # 返回 0 表示健康非 0 表示异常 # 方式一检查 NFS 导出列表能否正常返回 timeout 2 showmount -e 127.0.0.1 /dev/null 21 if [ $? -ne 0 ]; then exit 1 fi # 方式二实际挂载点是否可读更贴近业务 if ! mountpoint -q /srv/nfs_share; then exit 1 fi # 方式三尝试列目录验证 IO 通路 timeout 2 ls /srv/nfs_share /dev/null 21 exit $?逻辑说明三种检查从浅到深showmount验证 NFS 服务进程和导出配置mountpoint验证本地存储是否挂上ls验证实际 IO 能不能走通。生产上我建议至少保留前两种第三种在存储压力大时可能误报可以放到独立脚本里降低频率。VIP 切换时存储的挂载和卸载必须跟着走否则会出现两台同时写同一块盘文件系统直接损坏。notify 脚本负责这件事#!/bin/bash # /etc/keepalived/notify.sh STATE$1 DRBD_RESfs_data # DRBD 资源名 MOUNT_POINT/srv/nfs_share case $STATE in master) # 提升为 DRBD 主节点并挂载 drbdadm primary $DRBD_RES mount /dev/drbd0 $MOUNT_POINT systemctl start nfs-server ;; backup) # 停止服务卸载降为从节点 systemctl stop nfs-server umount $MOUNT_POINT 2/dev/null drbdadm secondary $DRBD_RES ;; fault) # 故障状态尽量卸载避免双写 systemctl stop nfs-server umount $MOUNT_POINT 2/dev/null ;; esac逻辑说明notify_master在节点成为主时触发顺序必须是先提升 DRBD 为主、再挂载、最后起 NFS。notify_backup顺序相反先停 NFS、再卸载、最后降 DRBD。这个顺序错了就是血泪经验先降 DRBD 再卸载会卡死先挂载再提升 DRBD 会报设备忙。notify_fault是保险尽量把挂载摘掉防止脑裂时双写。3. 设计逻辑图怎么画把状态机、数据流和故障域画在一张图上3.1 逻辑图必须包含的四个层次很多人画 HA 架构图只画两个框加一条虚线评审的时候被问「脑裂了怎么办」就答不上来。我画这类图一般分四层接入层、VIP 层、服务层、存储层。接入层是客户端标注它们通过 VIP 访问不感知后端。VIP 层画 keepalived 实例和 VRRP 通告关系标出 virtual_router_id 和优先级。服务层画 NFS/Samba 进程和健康探针。存储层画 DRBD 的主从关系和底层磁盘。四层之间用箭头标数据流向VIP 漂移用虚线标控制流。关键是故障域要标出来。比如主节点整机断电故障域是「节点1 全部」恢复动作是「VIP 漂移 DRBD 提升 挂载」。如果只是 NFS 进程挂了故障域是「服务层」恢复动作是「探针降权 切换」。这两种场景在图上要用不同颜色或线型区分否则运维拿到图还是不知道先看哪。3.2 用表格把状态迁移写清楚比画箭头更实用逻辑图是给人看的但真正落地时状态迁移表比图更不容易出错。下面这张表我一般会附在图的旁边。当前状态触发事件节点1 动作节点2 动作VIP 归属正常主从无MASTERDRBD Primary已挂载BACKUPDRBD Secondary未挂载节点1节点1 服务挂探针连续失败优先级降 30释放 VIP优先级胜出升为 MASTER节点2节点1 整机挂VRRP 超时无响应3 秒内未收到通告抢占节点2节点1 恢复探针恢复优先级回升但低于节点2保持 BACKUP保持 MASTER节点2双节点失联网络分区保持 MASTER可能脑裂保持 MASTER可能脑裂双活危险这张表的价值在于它逼你把「恢复后要不要抢回」想清楚。默认配置下节点1 恢复后优先级回到 100会抢回 VIP这会导致又一次切换。生产上我一般设nopreempt让节点2 继续持有避免频繁漂移。但nopreempt只在 state 为 BACKUP 的节点上生效主节点配置里写了没用这个坑我踩过。3.3 脑裂防护ping 网关 双路心跳脑裂是 HA 最危险的状态两个节点都认为自己是主同时挂载同一块盘文件系统几分钟内就会损坏。keepalived 本身不防脑裂得自己加。第一道防线是vrrp_script里加网关探测。如果节点 ping 不通网关说明本节点网络可能有问题主动降权甚至放弃 MASTER。vrrp_script chk_gateway { script /bin/ping -c 1 -W 1 192.168.10.1 interval 2 weight -40 # 网关不通大幅降权 fall 2 rise 2 }第二道防线是 DRBD 自身的 quorum。DRBD 9 支持quorum配置当节点数不足时拒绝提升为 Primary。配置里加quorum on和quorum-minimum 1这样即使 keepalived 误判DRBD 也不会让两个节点同时可写。第三道是 fencing也就是 STONITH。当确认对方失联但不确定死活时用 IPMI 或电源控制器强制断电对方。这个需要硬件支持中小环境不一定有但逻辑图上要标出这个位置评审时说明「当前环境无 fencing依赖 DRBD quorum 兜底」。4. 避坑与排查VIP 漂移不生效、双写和挂载卡死的真实记录4.1 VIP 不漂移先看 VRRP 通告和防火墙现象主节点 NFS 挂了探针也返回失败但 VIP 死活不切。原因最常见的是防火墙挡了 VRRP 协议。VRRP 用的是 IP 协议号 112不是 TCP/UDP 端口很多防火墙默认规则只放行 TCP/UDP把 VRRP 当未知协议丢了。另一个原因是virtual_router_id主从不一致或者auth_pass不一致导致通告被丢弃。解决在两端执行tcpdump -i eth0 -nn vrrp看有没有通告包。如果没有检查iptables -I INPUT -p vrrp -j ACCEPT或者 firewalld 的 rich rule。确认virtual_router_id和auth_pass完全一致注意 auth_pass 超过 8 位会被截断主从截断后要一样。4.2 切换后挂载失败DRBD 状态没跟上现象VIP 切到从节点了但 NFS 起不来日志报mount: /dev/drbd0: cant read superblock。原因notify 脚本执行顺序错了或者 DRBD 还没完成 Primary 提升就执行了 mount。DRBD 提升是异步的drbdadm primary返回不代表设备已经可读。解决在 notify 脚本里加等待循环用drbdadm status确认角色变成 Primary 再挂载。# 等待 DRBD 提升完成最多等 10 秒 for i in $(seq 1 10); do ROLE$(drbdadm role $DRBD_RES 2/dev/null | awk {print $1}) if [ $ROLE Primary ]; then break fi sleep 1 done mount /dev/drbd0 $MOUNT_POINT另外检查/proc/drbd或drbdadm status里的连接状态如果显示StandAlone说明同步链路断了这时候提升会失败得先修复网络再手动drbdadm connect。4.3 双写导致文件系统损坏只能从备份恢复现象某次网络分区两个节点都成了 MASTER都挂载了 DRBD几分钟后文件系统报大量 inode 错误目录结构错乱。原因没配nopreempt节点恢复后抢回 VIP同时 DRBD quorum 没开两边都允许 Primary。这是最严重的事故数据基本救不回来只能从备份恢复。解决三件事必须做。第一DRBD 配quorum on从内核层面阻止双 Primary。第二keepalived 从节点加nopreempt避免恢复后抢回。第三加网关探测脚本网络异常时主动降权。这三条是组合拳少一条都可能翻车。4.4 客户端缓存导致切换后读到旧数据现象VIP 切换成功服务也正常但部分客户端访问到的还是旧数据甚至报Stale file handle。原因NFS 客户端有属性缓存和目录项缓存VIP 漂移后客户端不知道后端换了节点缓存的 file handle 在新节点上无效。解决NFS 挂载参数加noac或者缩短acregmin/acregmax/acdirmin/acdirmax。但noac会严重影响性能我一般只在切换后手动在客户端执行umount -f再重新挂载或者用exportfs -rav刷新服务端导出。更彻底的做法是客户端挂载时加hard,intr配合监控在切换后触发客户端重挂。4.5 探针脚本权限问题导致检查永远失败现象探针脚本手动执行返回 0但 keepalived 里一直判定失败VIP 频繁切换。原因keepalived 以script_user指定的用户执行脚本默认可能是keepalived_script或nobody这个用户没有权限执行showmount或者读取挂载点。解决在global_defs里设script_user root和enable_script_security并确保脚本权限是 700、属主 root。如果不想用 root就把脚本需要的命令加 sudo 白名单但配置更麻烦。我一般直接 root内网环境可接受。5. 进阶技巧用 notify 脚本做切换后的客户端通知与状态自检5.1 切换后主动通知客户端刷新挂载VIP 漂移对客户端是透明的但 NFS 的 file handle 不是。切换后客户端可能还拿着旧节点的 handle访问报错。我一般会在 notify_master 脚本里加一段通过 SSH 或者消息队列通知客户端刷新。# 在 notify_master 里追加通知客户端重新挂载 CLIENT_LIST/etc/keepalived/clients.txt if [ -f $CLIENT_LIST ]; then while read -r client; do ssh -o StrictHostKeyCheckingno -o ConnectTimeout2 \ $client umount -f /mnt/fs_share mount -t nfs 192.168.10.100:/srv/nfs_share /mnt/fs_share \ /dev/null 21 done $CLIENT_LIST fi逻辑说明clients.txt里放客户端 IP每行一个。用后台执行避免阻塞 notify 脚本ConnectTimeout2防止某台客户端不可达拖慢整体。这个做法适合客户端数量可控的场景几百台以上建议用配置管理工具或者监控系统触发。5.2 用状态自检脚本定期验证 HA 有效性HA 方案最怕的是「配了但没验证过」。我习惯写一个自检脚本每周跑一次模拟主节点故障看切换是否正常、数据是否一致。#!/bin/bash # ha_selfcheck.sh - 在从节点执行模拟主节点故障 VIP192.168.10.100 MASTER192.168.10.11 echo [1] 检查当前 VIP 归属 ip addr show eth0 | grep -q $VIP echo VIP 在本节点 || echo VIP 不在本节点 echo [2] 检查 DRBD 状态 drbdadm status fs_data echo [3] 模拟主节点服务停止需在维护窗口执行 ssh $MASTER systemctl stop nfs-server sleep 10 echo [4] 检查 VIP 是否漂移 ip addr show eth0 | grep -q $VIP echo 切换成功 || echo 切换失败检查探针和防火墙 echo [5] 验证数据可读 ls /srv/nfs_share /dev/null 21 echo 数据可读 || echo 数据异常 echo [6] 恢复主节点 ssh $MASTER systemctl start nfs-server逻辑说明这个脚本把切换流程拆成六步每步都有明确输出。第 3 步停服务是破坏性操作必须在维护窗口跑。第 4 步是核心验证点如果 VIP 没漂移回去查探针和 VRRP。第 5 步验证数据通路防止「VIP 切了但存储没挂上」的假成功。跑完一轮整套 HA 的健康状况就清楚了。5.3 参数调优的几个经验值最后说几个我调过的参数。advert_int默认 1 秒内网可以保持跨机房建议 2 到 3 秒减少误判。fall和rise我一般设 2 到 3配合 interval 2 到 3 秒整体切换时间在 6 到 12 秒。DRBD 的protocol用 C除非跨机房延迟高才降 B。sndbuf-size和rcvbuf-size在万兆环境调到 1M 以上千兆保持默认。还有一点nopreempt只在 BACKUP 节点生效而且要求state必须是 BACKUP。如果主节点配置里写了state MASTER恢复后一定会抢回 VIP。我现在的习惯是两端都写state BACKUP用priority区分配合nopreempt这样恢复后不会来回切。这个配置方式不直观但稳定。这套方案我用了几年最大的教训是HA 不是配完就完事得定期演练。有一次半年没动真出故障时发现探针脚本因为系统升级后showmount路径变了一直返回失败VIP 在主节点上反复横跳业务比单机还惨。从那以后我养成了每月跑一次自检脚本的习惯参数改动都记在变更日志里。希望帮到你。本文还有配套的精品资源点击获取