做运维这些年,业务从一台服务器慢慢扩展到几十台,最怕的不是半夜被电话吵醒,而是电话响了之后发现主节点宕机、业务躺平、备节点还在睡大觉。Heartbeat 高可用集群就是当年解决这个问题的经典方案之一,它通过节点间持续收发心跳报文来判断彼此存活状态,一旦主节点失联,备节点自动接管IP和服务,把故障切换时间从“人工几小时”压缩到“脚本几十秒”。这篇文章不是抄文档,而是把我从裸配 Heartbeat、到踩坑脑裂、再到迁移 Corosync/Pacemaker、最后在 Proxmox VE 里落地高可用集群的完整过程整理出来,适合正在选型高可用方案的运维,以及想了解集群切换底层逻辑的开发者。
1. 高可用集群的核心逻辑与 Heartbeat 的定位
1.1 心跳机制到底在检测什么
很多人第一次接触 Heartbeat,以为它就是在两台机器之间定时发个包,收到包就证明对方活着。这个理解方向没错,但实际工程远没那么简单。心跳检测的本质,是在“当前节点无法确认对端状态”的时候,依然能做出正确的故障决策。
Heartbeat 的心跳链路默认走 UDP 协议,默认端口 694。节点之间通过三种方式交换心跳报文:广播(bcast)、组播(mcast)和单播(ucast)。早期集群大多用 bcast,一条心跳线连着两台机器,配置简单,但广播报文会占用局域网资源,而且在多节点场景下不够精准。后来更推荐 ucast,直接指定对端 IP,报文更干净、排障更直观。mcast 则适合需要跨多个网段组集群的场合,但需要网络设备支持组播协议,部分云环境默认禁组播,所以要提前确认。
心跳检测的时效性由三个时间参数控制:
- keepalive:心跳报文发送间隔,默认 1 秒。
- deadtime:超过该时长没收到对端心跳,节点判定对方已死,默认 30 秒。
- warntime:超过该时长没收到心跳,只是记录告警,默认 15 秒。
实际调参的时候,不同业务对切换时间的要求不一样,不能无脑把 deadtime 调到 3 秒。因为心跳报文在网络抖动时可能丢包,如果 deadtime 太短,一次 GC 暂停或网卡驱动异常就会触发误切,反而造成业务抖动。我一般习惯 keepalive=2、warntime=6、deadtime=15,兼顾误判率和切换速度。如果业务对中断容忍度极高,可以往小了压,但必须保证心跳网络稳定、节点负载可控,否则误切换比真故障更可怕。
1.2 为什么至今还有人在提 Heartbeat
严格来说,Heartbeat 项目已经停止活跃开发,最后稳定版停留在 3.0.6,社区主力早已迁移到 Corosync + Pacemaker 组合。但直到今天,各类搜索平台依然有人持续搜索“heartbeat配置”,说明存量环境里还有大量 Heartbeat 集群在生产线上跑,很多老运维也习惯了这套配置思路。
Heartbeat 当年的意义在于,它是第一个把“高可用”这个概念转换成可配置文件、可操作命令、可观察日志的开源方案,降低了集群的落地门槛。它的资源接管模型(IP 漂移、服务启停、文件系统挂载)在今天看来虽然粗糙,但逻辑清晰,非常适合用来理解高可用集群的底层运作。
更重要的是,现代集群方案 Corosync/Pacemaker 的心跳机制、仲裁模型、资源代理概念,很大程度上都能在 Heartbeat 里找到影子。把 Heartbeat 吃透,再去看新方案就是降维理解。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 部署前的节点规划与安装配置
2.1 两台节点怎么规划才合理
Heartbeat 高可用集群最常见的形态是双节点主备模式,一主一备,备节点平时完全空闲或只跑一些低优先级任务。节点规划时最容易忽略的几点:
第一,两块网卡是底线。一块用于业务流量,一块专用于心跳互联。心跳网卡之间用直连线或独立 VLAN 隔离,避免业务大流量打满网卡导致心跳报文延迟,引发误判。我见过不少线上事故,就是因为业务网卡和心跳网卡混用,半夜一次全量备份直接把心跳链路打爆。
第二,两个节点的时间要同步。Heartbeat 本身不强制要求时间一致,但资源接管、日志审计、证书校验(如果使用加密心跳)都依赖时间,所以务必在两边都装好 NTP 或 chrony,并且让它们跟随同一时间源。
第三,数据存储要提前分离。高可用集群可以保证服务漂移,但保证不了数据不丢。如果业务数据只存在主节点本地磁盘,主节点宕机后备节点接管服务,看到的还是旧数据。生产环境建议把数据放到共享存储(如 SAN、DRBD)或分布式文件系统,再用 Heartbeat 负责把数据卷挂载到当前活动节点。
节点规划做好之后,操作系统层面的基础配置也要统一。两台节点的主机名必须不同,但 /etc/hosts 里都要能互相解析到对方心跳网卡的 IP。Heartbeat 的 node 配置依赖主机名来识别节点,如果解析不对,后面服务根本起不来。
2.2 主配置 ha.cf 逐项拆解
Heartbeat 安装包在 CentOS/RHEL 等发行版里可能已经移除,需要从归档仓库或第三方镜像下载。Debian/Ubuntu 的软件源里通常还保留着 heartbeat 包,直接 apt install 即可。安装完成后,核心配置集中在 /etc/ha.d/ha.cf。
一个典型的双节点 ha.cf 长这样:
bash复制# 心跳通信相关
keepalive 2
deadtime 15
warntime 6
initdead 60
# 心跳链路
ucast eth1 192.168.100.2
ucast eth1 192.168.100.1
# 节点定义
node node1
node node2
# 使用 CRM 管理资源(可选)
crm no
# 日志
logfacility local0
这里重点解释两个坑。
第一个是 initdead。很多新手第一次配置时,明明确认配置没问题,但 heartbeat 服务就是起不来,日志里一堆 “Timed out” 报错。原因在于 initdead 设置得过小。initdead 是节点启动后等待集群收敛的宽限时间,系统刚启动时网络栈、服务管理器都还没完全就绪,如果这个值小于 deadtime,节点会在启动初期就误判对端失联,导致集群状态混乱。经验值是 initdead 至少设为 deadtime 的 2 到 4 倍,我一般写 60 秒,稳。
第二个是 ucast 的写法。两台节点都要配置对方地址,但互指就行,不用写自己的 IP。比如 node1 上写 ucast eth1 192.168.100.2,node2 上写 ucast eth1 192.168.100.1。
注意:ha.cf 里的日志通道默认是 syslog 的 daemon facility,实际排障时最好单独指定,比如 logfacility local0,然后在 rsyslog 里把 local0 单独导到一个文件,这样 heartbeat 日志不会跟系统其他日志混在一起,出问题时候查起来干净很多。
2.3 authkeys 安全认证配置
心跳报文如果不做认证,任何能访问心跳网段的机器都可以伪造心跳包,欺骗节点做出错误的故障切换。authkeys 文件就是用来做消息认证的。
bash复制auth 1
1 sha1 0x5f1c2e3d4a5b6c7d8e9f0a1b2c3d4e5f
这里 auth 1 表示使用第 1 种认证算法,后面几行依次定义算法编号和密钥。Heartbeat 支持 crc、md5、sha1 三种方式,其中 crc 只做校验不做加密,防误码不防伪造;md5 和 sha1 才是真正的认证。生产环境至少用 sha1,而且密钥要足够长。
authkeys 的一个重要属性是权限,必须设为 600,否则 heartbeat 服务启动时会报权限错误拒绝加载。这一点在官方文档里写得很清楚,但总有人忽略,包括我自己早期也踩过。
配置完成后,两个节点的 authkeys 内容必须完全一致,否则节点之间认证不通过,心跳无法建立,集群起不来。这听起来像废话,但常见的改动场景是只改了主节点忘记同步备节点,导致整个集群异常,排查半天才发现是密钥不匹配。
3. 资源接管与故障切换实战
3.1 haresources 资源定义的精髓
Heartbeat 的资源管理有两种模式:经典模式使用 haresources 文件定义资源列表,另一种是启用 CRM(Cluster Resource Manager)配合 Pacemaker 管理。经典模式简单直接,适合双节点场景;一旦节点数变多、资源依赖变复杂,很快会力不从心。先看经典配置。
/etc/ha.d/haresources 内容示例:
bash复制node1 IPaddr::192.168.1.100/24/eth0 Filesystem::/dev/sdb1::/data::ext4 httpd
这一行含义是:在 node1 上定义一组资源,正常情况下 node1 持有这个资源组,具体包括:
- 一个虚拟 IP 192.168.1.100,子网掩码 24,绑定到 eth0 网卡。
- 挂载 /dev/sdb1 到 /data,文件系统 ext4。
- 启动 httpd 服务。
当 node1 故障时,整个资源组按顺序迁移到 node2,由 node2 执行同样的资源接管动作。注意“顺序”很关键,Heartbeat 默认按照 haresources 里定义的顺序启动资源,先启动 IP,再挂载文件系统,最后启动服务。这个顺序不能随意调整,因为服务通常依赖 IP 和文件系统就绪后才能正常工作。
写 haresources 时几个坑:
IPaddr 资源别忘了写子网掩码和网卡名,只写 IP 的话 Heartbeat 会走默认值,默认网卡可能不是你想绑的那块。Filesystem 资源在两台机器上的挂载点必须一致,否则切换后服务的配置文件路径全乱了。资源定义到同一行,表示同一资源组,资源和资源之间是绑定的,不能切一半。把不需要跟随漂移的本地服务写进 haresources,会导致故障切换时本地服务被误杀或误启,这类资源要排除在资源组之外。
3.2 脑裂与 STONITH:集群的“保底手段”
心跳高可用集群最怕的不是节点宕机,而是脑裂。脑裂是指主备节点之间心跳中断,但两台机器本身都正常运行,于是备节点认为主节点死了,开始接管资源,资源在两边同时跑起来,业务 IP 两边都有,数据同时被两个节点写入,最终造成数据损坏。
为什么心跳断了,备节点不能直接接管?因为备节点无法确认主节点到底是宕机了,还是只是网络中断。如果主节点只是网络抖动,备节点贸然接管,两个节点就会同时操作同一份资源。这就是脑裂。
解决脑裂的标准手段是 STONITH(Shoot The Other Node In The Head),核心思想是“宁可错杀,不可放过”。当集群无法确认某个节点状态时,先强制切断该节点的电源或从网络隔离,再接管资源。Heartbeat 本身对 STONITH 的支持比较弱,需要配合外部设备(如 IPMI、iLO 或智能 PDU)来实现。具体做法是在 ha.cf 里配置 stonith 插件,指向节点带外管理接口,一旦触发 fencing,带外设备直接给故障节点发送硬重启指令。
在经典的 Heartbeat 配置中,STONITH 设备配置在 ha.cf 里:
bash复制stonith host node1 fence_ipmilan -A 192.168.200.1 -U admin -P passwd -l lanplus
实际生产环境里,很多团队觉得配置带外管理太麻烦,干脆不配 STONITH。这在双节点场景下风险极高,一旦心跳链路故障,等着你的就是业务中断加数据损坏。我的建议是:既然上了高可用,就把“最后一道保险”一起上了,别省这点工作量。
3.3 切换演练实操
配置完成后,不能光看不练。我习惯在业务低峰期做一次完整的故障演练,确认集群在真实故障场景下能自动恢复。
演练第一步,先在两台节点上确认服务状态:
bash复制# node1 上确认资源
ip addr show eth0 | grep 192.168.1.100
systemctl status httpd
# 查看 heartbeat 状态
heartbeat status
第二步,手动模拟主节点故障。为了不影响业务演练,可以先从核心服务下手:
bash复制# 在 node1 上杀掉 heartbeat 主进程
pkill heartbeat
正常情况下的切换预期是:几十秒后,192.168.1.100 出现在 node2 的 eth0 上,httpd 也在 node2 上运行,业务 IP 访问无中断或仅有极短中断。
第三步,验证结束后让 node1 回归。这里有个细节:node1 恢复后,资源不会自动切回 node1。因为 Heartbeat 默认策略是避免资源来回漂移,资源只会留在当前活动节点上。如果你希望 node1 恢复正常后资源回到最佳运行节点,需要手动把资源迁移回去,或者调整相关策略参数。
整个演练过程,务必盯住 /var/log/ha-log 的日志输出,练一次,就把集群的切换链路完整摸一遍,后面线上真出问题的时候心里有底得多。
4. 高频故障排查与心法
4.1 常见问题速查
这几天整理了一下典型的故障现象、可能原因和处理思路,直接做成表格方便对照:
| 故障现象 | 可能原因 | 排查思路 |
|---|---|---|
| heartbeat 服务启动失败 | initdead 太短、authkeys 权限不对、ha.cf 配置有误 | 先看 /var/log/ha-log,重点搜 “Timed out” 和 “Bad” 关键字;用 heartbeat -d 前台调试模式启动,观察输出的报错 |
| 两个节点都认为自己是主节点 | 心跳网卡故障、防火墙拦截 UDP 694、deadtime 过短 | 确认两台机器的心跳网卡互通,用 tcpdump 抓 694 端口的报文,看对端是否发了心跳、自己是否收到了 |
| 虚拟 IP 绑定到错误网卡 | haresources 里 IPaddr 没有指定网卡名 | 添加接口名参数,如 IPaddr::192.168.1.100/24/eth0,重启 heartbeat 生效 |
| 资源切换后服务起不来 | 资源依赖顺序不对、应用启动脚本依赖本地配置 | 确认应用配置与文件系统挂载点是否在正常路径上,手动在目标节点执行资源对应的启动命令,逐步排查 |
| 主节点恢复后资源不回来 | Heartbeat 默认的迁移策略 | 手动执行资源迁移,或确认是否配置了自动回切策略 |
| 心跳报文丢失但网络正常 | 防火墙、网卡 offload 特性、交换机端口安全 | 临时关闭 iptables 测试,检查网卡 ethtool 参数,与网络同事确认交换机上是否有端口策略 |
排障的时候最忌乱猜,一定要顺着日志走。Heartbeat 对日志的依赖比新方案更重,它的自我诊断输出不丰富,很多深层原因藏在细微的日志差异里。
4.2 从 Heartbeat 迁移到 Corosync/Pacemaker
如果你的集群节点数已经超过两个,或者资源之间出现了依赖关系、互斥关系、优先级调度,Heartbeat 的 haresources 模式很快会把配置变成一团乱麻。这时候需要迁移到 Corosync + Pacemaker 组合。
Corosync 取代 Heartbeat 作为底层通信层,负责集群成员管理、心跳检测、消息广播。Pacemaker 接管资源调度,支持更复杂的状态机、约束和资源规则。二者配合,相当于把“心跳检测”和“资源编排”彻底解耦,各自独立演进,这也是现代集群架构的主流做法。
迁移的时候不用从头写资源,Pacemaker 提供了一组命令行工具,例如:
bash复制# 定义一个虚拟 IP 资源
pcs resource create vip IPaddr2 ip=192.168.1.100 cidr_netmask=24 op monitor interval=5s
# 定义服务资源
pcs resource create web-server systemd:httpd op monitor interval=10s
# 设置资源必须在同一节点运行
pcs constraint colocation add vip with web-server
# 设置启动顺序约束
pcs constraint order start vip then start web-server
迁移的收益不只是功能更强,运维体验也会好很多。Pacemaker 有 pcs status 这种清晰的状态输出,有 resource agent 的标准错误码,日志里能直接看到探活失败原因,排障效率比 Heartbeat 高很多。
4.3 Proxmox VE 场景中的高可用集群实践
Proxmox VE 是目前很流行的开源虚拟化平台,它的高可用集群从底层选型上就延续了 Linux-HA 的思路,使用 Corosync 做集群通信,Pacemaker 做资源管理,同时引入 pmxcfs 这个基于文件系统层级的分布式配置库来保存虚拟机配置,让所有节点看到一致的集群状态。
在 Proxmox VE 里做高可用集群,配置路径和传统的 Heartbeat 有很大不同。PVE 从 4.x 开始支持 HA Manager,通过 Web 界面可以直观地给虚拟机或容器开启哈保护。底层的实施逻辑是:将虚拟机配置存到 pmxcfs,把虚拟机的运行状态交给 HA 调度器,调度器依赖 Corosync 检测节点存活,节点故障后自动在健康节点上重新拉起虚拟机。
实操时,在 PVE Web 界面的 Datacenter -> HA 页面,勾选需要保护的虚拟机,设置恢复策略,例如 max_restart=3 表示尝试在同一个节点上重启 3 次,超过后才会迁移到其他节点。这里要注意:PVE 高可用强制要求有外接 fence 设备,比如 IPMI 或独立看门狗,否则节点失联后可能因为无法确认状态而产生脑裂风险,PVE 后台日志也会给出明显告警。
把传统 Heartbeat 换成 PVE 内置 HA,对虚拟化场景来说运维负担小很多。日常维护只需关注虚拟机的启动顺序、存储是否配置为多节点可访问(建议 Ceph、DRBD 或共享存储),节点故障后虚拟机会自动在健康节点上启动,服务恢复时间通常可以控制在 1 分钟以内。
说实话,Heartbeat 这个老项目已经完成了它的历史使命,但它教会我们的那套高可用逻辑——心跳、仲裁、资源接管、脑裂防护——每一环都在今天的 Corosync、Pacemaker、Proxmox VE 高可用体系里延续着。所以我依然建议新入行的运维专门搭一套 Heartbeat 环境玩一次,亲手触发一次故障切换、观察一次脑裂的发生,比看图学概念深刻十倍。等到你对这些底层机制有了体感,再上手 PVE 或者 K8s 的多副本架构,思路会清晰得多。
