FreeSWITCH高可用实战:keepalived双节点主备与VIP漂移

发布时间:2026/10/18 10:45:01
FreeSWITCH高可用实战:keepalived双节点主备与VIP漂移
简介这是一份面向运维工程师与VoIP系统架构人员的Freeswitch高可用方案实践资料围绕Keepalived构建主备切换机制解决通信服务单点故障导致的中断问题。压缩包共4个文件约38KB包含2个Shell脚本、1份安装手册文本和1张Visio逻辑图分别用于健康检查与故障切换辅助、Keepalived部署配置说明以及主备切换全流程的可视化梳理。资源重点呈现主备节点配置、虚拟IP绑定、自定义健康检查脚本触发故障转移等核心设计并配有逻辑图帮助理解从检测到接管的完整链路。目前已有669人学习下载适合需要快速搭建Freeswitch HA环境、理清切换逻辑并落地部署的技术人员参考。1. 从一次凌晨三点的告警说起FreeSWITCH 高可用到底要解决什么凌晨三点监控群里弹出一条告警核心语音节点进程还在但 SIP 注册全部超时呼叫接通率掉到零。值班同事重启服务花了六分钟这六分钟里所有外呼、坐席签入、IVR 全部中断。事后复盘发现问题不在 FreeSWITCH 本身而在于这套系统从一开始就是单点——没有 VIP 漂移没有备节点接管连健康检查都是靠人肉盯监控。这件事之后我把 FreeSWITCH 的 HA 方案重新做了一遍核心目标很明确让主节点故障时备用节点能在秒级接管虚拟 IP 和信令端口业务侧几乎无感知。这套方案适合正在做语音平台毕设、呼叫中心课设或者需要给现有 FreeSWITCH 集群补高可用能力的同学和工程师。它不追求大厂级别的多活架构而是用 keepalived 双节点主备把「单点故障」这个最致命的问题先解决掉方案完整、可复现、能写进设计文档也能直接照着搭环境。2. 需求拆解与技术选型为什么是 keepalived 而不是其他方案2.1 先明确 FreeSWITCH 的故障边界做 HA 之前得先想清楚到底要防哪些故障。FreeSWITCH 的故障大致分三层。第一层是进程级比如 sofia 模块崩溃、内存泄漏导致进程被 OOM kill这类问题重启进程就能恢复。第二层是节点级比如整台机器宕机、网卡故障、系统盘写满这时候进程重启没用必须换节点。第三层是网络级比如交换机抖动、上行链路中断这种最麻烦因为节点本身活着但对外不可达。keepalived 能覆盖的是第二层和部分第三层。它通过 VRRP 协议在多个节点之间选举出一个 MASTER由 MASTER 持有虚拟 IPVIP所有 SIP 信令和 RTP 媒体都往这个 VIP 上送。MASTER 挂了BACKUP 在几百毫秒到几秒内检测到并抢占 VIPFreeSWITCH 继续在备节点上服务。这里有个关键认知keepalived 管的是「IP 层面的接管」它不负责 FreeSWITCH 进程本身的重启所以健康检查脚本必须自己写把进程状态、端口监听、甚至 SIP 响应都纳入检查范围。2.2 选型对比keepalived、CorosyncPacemaker 还是 DNS 轮询常见的几种 HA 思路放在一起比一下选型逻辑就清楚了。方案切换速度配置复杂度对 FreeSWITCH 的侵入性适用规模keepalived VRRP秒级低无纯网络层双节点主备Corosync Pacemaker秒级高需要资源代理多节点集群DNS 轮询分钟级受 TTL 影响低无无状态服务应用层双写注册取决于实现很高强侵入超大规模DNS 轮询的问题在于 TTL 缓存客户端可能几分钟都还指着旧 IP对语音这种实时业务不可接受。Corosync Pacemaker 功能强但配置和维护成本对中小规模项目来说过重而且 FreeSWITCH 的资源代理脚本要自己写坑不少。keepalived 的优势是轻、稳、文档多双节点主备场景下几乎是最优解。我一般会建议节点数不超过四个、以主备或一主多备为目标的项目直接用 keepalived别上 Pacemaker 给自己找麻烦。2.3 网络与端口规划VIP 方案要落地网络规划必须先定。假设主节点 IP 是 192.168.10.11备节点是 192.168.10.12VIP 用 192.168.10.100。FreeSWITCH 默认的 SIP 端口 5060UDP/TCP、TLS 端口 5061、RTP 端口段 16384-32768这些都要跟着 VIP 走。也就是说FreeSWITCH 的 sofia profile 里要绑定 VIP 而不是物理网卡 IP或者绑定 0.0.0.0 让所有地址都监听再由 keepalived 决定 VIP 在谁身上。这里有个容易忽略的点RTP 媒体流。SIP 信令走 VIP 没问题但 RTP 是端到端协商的如果 FreeSWITCH 在 SIP 里通告的是物理 IP切换后媒体路径就断了。所以 profile 里的ext-sip-ip和ext-rtp-ip必须配置成 VIP或者用auto配合正确的网络环境。这一步没做对会出现「信令通了但没声音」的经典翻车现场。3. 总体架构设计双节点主备与 VIP 漂移的职责划分3.1 架构分层与数据流整套架构分三层。最底层是网络层由 keepalived 的 VRRP 实例维护 VIP 归属MASTER 节点周期性发送 VRRP 通告BACKUP 节点监听超时未收到就触发选举。中间层是服务层FreeSWITCH 实例绑定 VIP 或 0.0.0.0配合健康检查脚本向 keepalived 汇报自身状态。最上层是业务层SIP 客户端、网关、坐席话机统一配置 VIP 作为注册和呼叫地址它们不关心背后是哪台机器。数据流是这样的话机向 VIP:5060 发 REGISTERMASTER 上的 FreeSWITCH 处理并回 200 OK呼叫建立时SIP 信令走 VIPRTP 媒体按 SDP 协商的地址传输。MASTER 故障时keepalived 把 VIP 漂到 BACKUP话机下一轮 REGISTER 或呼叫请求就落到新 MASTER 上。已经建立的呼叫会断这是主备方案的固有代价要保通话得做媒体中继或会话复制那是另一个量级的工程。3.2 健康检查脚本的设计逻辑keepalived 自带的MISC_CHECK或VRRP_SCRIPT可以调用外部脚本脚本返回 0 表示健康非 0 表示异常。检查脚本要分层次写不能只看进程在不在。#!/bin/bash # freeswitch_health_check.sh # 返回 0 表示健康非 0 表示异常触发 keepalived 降权或切换 # 第一层进程是否存在 if ! pgrep -x freeswitch /dev/null; then echo FreeSWITCH process not found exit 1 fi # 第二层SIP 端口是否监听 if ! ss -lun | grep -q :5060; then echo SIP port 5060 not listening exit 1 fi # 第三层fs_cli 是否能正常响应 if ! fs_cli -x status 2/dev/null | grep -q UP; then echo FreeSWITCH status check failed exit 1 fi # 第四层检查 sofia profile 是否处于 RUNNING if ! fs_cli -x sofia status 2/dev/null | grep -q RUNNING; then echo Sofia profile not running exit 1 fi exit 0这个脚本的关键在于分层递进。进程在但端口没监听说明启动卡住了端口在但 fs_cli 无响应说明事件系统挂了fs_cli 正常但 sofia profile 没起来说明 SIP 栈有问题。每一层都对应不同的故障模式脚本里用echo输出原因方便在/var/log/messages里定位。脚本执行频率建议 2 到 3 秒一次超时时间设 5 秒这样故障检测能在 10 秒内完成。3.3 keepalived 配置的核心参数keepalived 的配置文件分全局段和 VRRP 实例段。全局段定义通知机制和脚本路径实例段定义 VIP、优先级、认证和检查脚本。# /etc/keepalived/keepalived.conf global_defs { router_id FS_HA_NODE # 节点标识主备要不同 script_user root # 执行检查脚本的用户 enable_script_security # 启用脚本安全检查 } vrrp_script chk_freeswitch { script /etc/keepalived/freeswitch_health_check.sh interval 3 # 每 3 秒检查一次 timeout 5 # 脚本超时 5 秒 fall 2 # 连续失败 2 次才判定异常 rise 2 # 连续成功 2 次才恢复 weight -30 # 检查失败时优先级减 30 } vrrp_instance VI_FS { state MASTER # 备节点改为 BACKUP interface eth0 # 物理网卡名按实际改 virtual_router_id 51 # 主备必须一致 priority 100 # 主节点 100备节点 90 advert_int 1 # VRRP 通告间隔 1 秒 authentication { auth_type PASS auth_pass FsHa2024 # 主备密码一致 } virtual_ipaddress { 192.168.10.100/24 dev eth0 } track_script { chk_freeswitch } notify_master /etc/keepalived/notify.sh master notify_backup /etc/keepalived/notify.sh backup notify_fault /etc/keepalived/notify.sh fault }priority是选举的核心主节点 100、备节点 90差值要大于weight的绝对值否则健康检查失败降权后可能不足以触发切换。fall和rise控制抖动设太小会频繁切换设太大切换迟钝2 到 3 是比较稳的区间。notify_master等脚本用来在状态变化时做额外动作比如发告警、记录日志、或者触发 FreeSWITCH 重新加载配置。4. 落地实现从环境准备到主备切换验证4.1 双节点环境准备与 FreeSWITCH 配置调整两台机器装好同版本 FreeSWITCH配置尽量保持一致。关键改动在 sofia profile 里把 SIP 和 RTP 的对外地址指向 VIP。!-- /etc/freeswitch/sip_profiles/external.xml 片段 -- param nameext-sip-ip value192.168.10.100/ param nameext-rtp-ip value192.168.10.100/ param namesip-port value5060/ param namertp-start-port value16384/ param namertp-end-port value32768/ext-sip-ip决定 SIP 消息里 Via 和 Contact 头带哪个地址ext-rtp-ip决定 SDP 里通告的媒体地址。两个都设成 VIP切换后对端不需要改任何配置。如果内网外网都有还要配ext-sip-ip和internal-sip-ip分别对应不同 profile。改完用fs_cli -x reloadxml和fs_cli -x sofia profile external restart生效。4.2 主备切换的完整验证流程搭好之后必须做切换测试不能等真出事。验证分四步。第一步确认初始状态。在主节点执行ip addr show eth0应该能看到 VIP 192.168.10.100。在备节点执行同样命令看不到 VIP。用fs_cli -x sofia status确认 profile 是 RUNNING。第二步模拟进程故障。在主节点执行systemctl stop freeswitch观察 keepalived 日志tail -f /var/log/messages | grep Keepalived。正常情况下健康检查连续失败两次后主节点优先级降到 70备节点 90 抢占VIP 漂移。整个过程应该在 10 秒内完成。第三步验证业务。用 SIP 客户端向 VIP 注册看是否成功。拨一个测试号码确认信令和媒体都正常。这时候ip addr在备节点上应该能看到 VIP。第四步恢复主节点。重新启动 FreeSWITCH健康检查通过后优先级恢复但默认不会自动抢回 VIP因为 keepalived 的nopreempt没配的话会抢占。如果希望主节点恢复后自动接管保持默认如果希望稳定不频繁切换在备节点配置里加nopreempt。4.3 状态通知与日志排查notify脚本是排查问题的关键。每次状态变化都记一条日志包含时间、节点、新旧状态。#!/bin/bash # /etc/keepalived/notify.sh STATE$1 LOG/var/log/keepalived_state.log echo $(date %Y-%m-%d %H:%M:%S) - Node $(hostname) transitioned to $STATE $LOG # 切换到 MASTER 时可以触发 FreeSWITCH 重载 if [ $STATE master ]; then fs_cli -x reloadxml 2/dev/null fs_cli -x sofia profile external restart 2/dev/null fi这个脚本在 MASTER 状态时重载 FreeSWITCH 配置确保 SIP 地址绑定正确。日志文件要配合 logrotate 做轮转不然时间长了会撑满磁盘。排查切换问题时先看/var/log/messages里 keepalived 的 VRRP 状态变化再看keepalived_state.log确认 notify 脚本有没有执行最后看 FreeSWITCH 的fs_cli -x sofia status确认服务层状态。5. 避坑与常见问题那些让我熬夜的细节5.1 VIP 漂移了但 SIP 注册全部失败现象是 keepalived 显示切换成功VIP 已经在备节点上但话机注册全部超时。原因通常是 FreeSWITCH 的 sofia profile 还绑定在旧 IP 上或者ext-sip-ip没配成 VIP导致 SIP 响应里的 Contact 地址还是物理 IP客户端收到后往错误地址发后续请求。解决办法是检查 profile 配置确保ext-sip-ip和ext-rtp-ip都是 VIP切换后执行sofia profile external restart让绑定生效。我一般会在 notify 脚本里强制重启 profile避免手动遗漏。5.2 健康检查脚本误判导致频繁切换现象是 keepalived 日志里频繁出现 MASTER/BACKUP 切换业务时好时坏。原因是检查脚本太敏感比如fs_cli偶尔响应慢就返回失败或者fall设成 1一次失败就切换。解决办法是把fall调到 2 或 3脚本里加超时控制fs_cli调用用timeout 3包一层。另外检查脚本本身要轻量别在里面做复杂查询否则脚本执行时间超过interval会互相干扰。5.3 双主脑裂两台机器同时持有 VIP现象是两台机器都认为自己是 MASTERVIP 冲突网络时通时断。原因是 VRRP 通告被防火墙拦截或者virtual_router_id配错导致两个实例互相看不见。解决办法是确认防火墙放行 VRRP 协议IP 协议号 112和组播地址 224.0.0.18检查主备的virtual_router_id和auth_pass完全一致。如果网络环境不支持组播可以用unicast_peer配置单播通告。5.4 RTP 媒体单通或无声现象是呼叫能建立但一方或双方听不到声音。原因是 SDP 里通告的 RTP 地址不是 VIP切换后媒体流还往旧地址发。解决办法是确认ext-rtp-ip配置正确并且 FreeSWITCH 的acl和nat相关配置允许 VIP 网段。如果前面有 NAT还要配ext-rtp-ip为公网 VIP 并开启apply-nat-acl。这个坑最隐蔽因为信令看起来完全正常。5.5 切换后已建立的通话中断现象是切换瞬间所有在通话的呼叫全部断线。这是主备方案的固有特性因为会话状态没有同步。如果业务要求切换不断话需要做会话复制或媒体中继成本很高。通常的做法是接受这个代价在业务层做重拨引导或者把切换时间压缩到最短减少影响面。我一般会在方案文档里明确写清楚这个限制避免验收时被质疑。6. 验收与答辩怎么证明这套 HA 方案真的可靠验收这套方案核心就一句话用数据证明切换够快、业务够稳。我一般会准备一张验收表把测试项、预期结果、实测结果列清楚答辩时直接展示。测试项操作预期结果判定标准初始状态主备分别执行 ip addr主有 VIP备无符合进程故障切换主节点 stop freeswitchVIP 漂到备节点10 秒内完成端口故障切换主节点封禁 5060 端口VIP 漂到备节点15 秒内完成业务连续性切换后 SIP 注册注册成功3 次内成功呼叫验证切换后拨测信令媒体正常接通率 100%恢复回切主节点恢复VIP 按策略回切符合配置测试的时候有个技巧用tcpdump抓 VRRP 报文确认通告间隔和优先级字段符合预期。tcpdump -i eth0 vrrp -vv能看到 VRRP 版本、优先级、通告间隔。答辩时如果老师问「你怎么知道切换真的发生了」抓包记录比日志更有说服力。另一个重点是故障注入的多样性。别只测 stop 进程还要测 kill -9、断网、磁盘写满、CPU 打满这些场景。我一般会写一个测试脚本把常见故障模拟一遍记录每次的切换时间和业务影响。这些数据整理成表格就是方案文档里最有价值的部分。还有一点答辩时一定会被问到「为什么不做过多的节点」。这时候要能说清楚双节点主备的切换逻辑最简单脑裂风险最低维护成本最小。三节点以上要考虑投票机制、数据同步、会话一致性复杂度指数上升。对于课程设计或中小规模项目双节点是性价比最高的选择。把选型理由讲清楚比堆功能更能体现设计能力。从那以后我每次做 HA 方案都会先把故障场景列全再写健康检查脚本最后才配 keepalived。顺序反了后面全是补丁。希望帮到你。本文还有配套的精品资源点击获取