
凌晨两点值班群里弹出一条告警数据库主节点宕机。我摸到笔记本前先看了一眼监控大屏——业务指标没跌用户侧毫无感知。这套MySQL跑在Corosync Pacemaker托管的VIP之上节点挂了资源在几秒内被另一台机器接管。这种“挂了跟没挂一样”的效果正是无数运维人折腾集群管理的终极目标。这篇文章不聊理念和概念堆叠直接从真实配置出发讲清楚Corosync Pacemaker这套组合的安装、配置、故障切换和排错细节。适合刚接手高可用环境的运维工程师也适合准备从Keepalived/脚本方案切换出来的团队作为选型参考。1. Corosync与Pacemaker一对分不开的老搭档1.1 先搞清楚它们各自干什么很多刚接触集群管理的人会被这两个名字搞晕总觉得它们是一套东西实际分工完全不同。Corosync是底层通信层负责集群成员管理、心跳检测、消息传递和法定票数计算。每个节点通过它相互感知对方是否存在某个节点失联了由它先发现并向其他节点广播新的事实。它本身不关心“跑在上面的Nginx是哪个IP的虚拟地址”只关心“集群里现在有哪些节点状态如何说话算不算数”。Pacemaker是资源管理器坐在Corosync之上负责决定“哪个节点上的哪个服务该处于什么状态”。它维护着完整的资源状态机协调启动、停止、监控、迁移动作。它从Corosync拿到集群成员变化的通知再根据约束规则和当前资源分布决定是否要把资源从故障节点挪走挪到哪里去。可以这样类比Corosync是楼宇的门禁和广播系统时刻告知“谁在楼里、谁已经离开”Pacemaker是物业调度中心收到消息后决定“楼里断电了把备用发电机切到哪个配电柜”。门禁不负责开电闸调度中心也不负责发通行卡但两者配合才能保证整栋楼不停摆。1.2 为什么不是Keepalived不是K8s不少人在选型时问过Keepalived做VIP漂移已经很成熟为什么要上Corosync Pacemaker这套更重的方案Keepalived的核心能力是VRRP协议下的VIP漂移适合“一主一备、大家抢一个VIP”的场景。它配置轻、上手快但资源管理能力弱你想让Nginx挂掉后VIP自动切走需要写track_script想让两块业务一起漂移、且保持特定启停顺序你得自己在脚本里拼凑想扩展成三节点甚至五节点再处理脑裂就超出了Keepalived的舒适区。Corosync Pacemaker则把“节点成员关系”和“资源编排”完全解耦。它支持多节点架构下的法定票数机制从根上降低脑裂概率资源类型覆盖IP、Systemd服务、LVM文件系统、数据库实例等还有约束机制控制顺序和位置配合栅栏设备Fencing节点失联时可以直接强制隔离避免“两台机器同时写一块数据”这种致命情况。代价是配置复杂度上了一个台阶对运维者的要求也更高。至于Kubernetes那是容器编排层面的调度器解决的是“一堆微服务怎么在节点池里跑”的问题。如果只是几台物理机/虚机上挂一个数据库VIP和一个Web服务引入K8s属于大炮打蚊子。Corosync Pacemaker可以直接装在传统Linux环境中也能托管K8s自身的关键组件两者并不互斥。1.3 常见架构与版本选型最常见的生产架构是三节点集群。三节点下法定票数阈值为2任何一个节点宕掉剩下两个节点依然有票数继续工作两节点架构则存在天然缺陷——节点A认为B挂了B也认为A挂了两边票数相等如果没有额外机制就会各自漂移资源产生双主冲突。如果资源条件限制只能做两节点必须在配置中显式启用two_node: 1并配合一个投票仲裁节点或栅栏设备来控制脑裂风险。另外两节点场景下如果隔离设备配置不当故障节点被踢出集群后可能因为无法被“击杀”而继续写共享存储风险极高。版本选型上RHEL/CentOS 7系列默认Pacemaker 1.1 pcsRHEL/CentOS 8以上默认Pacemaker 2.x pcs。2.x版本引入了一系列资源代理和调度器优化规则语法也有增强。如果你的系统还停留在老版本强烈建议迁移前先查看官方升级说明因为从1.1升到2.0后部分约束配置需要调整。2. 环境准备那些装完系统后马上要办的事2.1 主机规划与网络要求我推荐至少三台节点生产环境连存储一起纳入规划。节点命名建议沿用域名规划例如node1.prod.internal、node2.prod.internal、node3.prod.internal。Corosync对时间同步极其敏感节点之间时钟偏差过大会导致心跳超时误判所以从装好系统那一刻起就要把chrony或NTP统一配置好。以下是一套比较典型的三节点规划表可以直接当作模板用节点名IP地址管理网IP地址集群专用网角色node110.10.10.11192.168.100.11主节点候选node210.10.10.12192.168.100.12主节点候选node310.10.10.13192.168.100.13仲裁/资源节点集群专用网建议走单独的网卡用交叉线或者独立交换机连通避免业务流量把心跳通道打满。每台机器的/etc/hosts必须保持一致写入所有节点的短主机名和IP映射千万不要依赖DNS解析DNS一旦抖动集群会以为节点消失了。2.2 安装软件包rhel系和debian系在RHEL/CentOS系执行下面命令yum install -y pacemaker pcs corosync fence-agents-all systemctl enable --now pcsd echo hacluster:your-strong-password | chpasswdDebian/Ubuntu系类似apt-get install -y pacemaker pcs corosync systemctl enable --now pcsd echo hacluster:your-strong-password | chpasswd这里要把pcsd服务先跑起来它是pcs的远程控制端节点之间认证、同步配置都依赖它。hacluster是集群管理专用账号安装时不会设置默认密码必须手动设置后面pcs cluster auth认证时要用。所有节点都装完后在其中一个节点上执行认证把其他节点的授权加进来pcs host auth node1 node2 node3 -u hacluster -p your-strong-password如果这里报「unable to authenticate」多半是pcsd服务没启动或者防火墙拦了端口2224。2.3 时间同步与主机名的坑时间同步的问题最容易在故障排查时暴露。我踩过的真实案例是集群运行了半年某天节点B硬件时钟漂移了2秒Corosync开始间歇性报Missed heartbeat但业务没中断只有日志在刷告警。当时通过chronyc tracking对比各节点偏移量发现B节点源失效修好NTP后再也没出现过。主机名那边也有两个坑要避hostnamectl set-hostname设置的短主机名必须放在/etc/hosts的第一列和uname -n输出一致。pcs创建集群时会默认用节点的短主机名写入nodelist如果后期改主机名corosync.conf里的name字段也要同步更新否则节点启动后显示Unexpected。还有一点安装完先确认SELinux状态。RHEL系默认 enforcing 环境下pcsd可能因为端口绑定问题起不来。最小化配置阶段可以直接setenforce 0 vi /etc/selinux/config # 改为SELINUXpermissive systemctl restart pcsd生产环境建议保留SELinux但需要放行对应端口并配置布尔值这里不展开跑通后慢慢加固。3. Corosync配置实战从默认模板到可用配置3.1 pcs cluster setup 到底做了什么我见过不少人直接手写corosync.conf然后启动一堆奇奇怪怪的报错。这个文件不是不能手写而是你用pcs生成会省太多事。在两节点的情形下先在三节点中选一个入口节点执行pcs cluster setup mycluster node1 node2 node3它会在当前节点生成/etc/corosync/corosync.conf并通过pcsd同步到其他节点。生成的配置里已经包含了nodelist、quorum、totem等区块结构清晰。corosync.conf的核心在于三个区块的理解totem心跳协议参数如 token令牌超时时间、consensus选举超时、join节点加入超时。nodelist节点名单写入每台机器的ring0_addr通信地址和name。quorum法定票数规则expected_votes和two_node是关键。修改配置前手动检查节奏总没错corosync-cfgtool -s这个命令会输出当前集群的通信状态如果看到RING ID和STATUS正常说明底层通信没问题。3.2 手动理解corosync.conf关键字段直接用pcs生成的配置比较简洁但生产环境需要理解每个参数的意义下面是简化后的常见形态totem { version: 2 cluster_name: mycluster token: 3000 consensus: 5000 join: 60 transport: knet crypto_cipher: aes256 crypto_hash: sha256 } nodelist { node { ring0_addr: 192.168.100.11 name: node1 nodeid: 1 } node { ring0_addr: 192.168.100.12 name: node2 nodeid: 2 } node { ring0_addr: 192.168.100.13 name: node3 nodeid: 3 } } quorum { provider: corosync_votequorum expected_votes: 3 }各字段说明token单位是毫秒表示节点间心跳丢失多久后判定对端不可达。token: 3000意味着如果3秒收不到对方心跳就触发成员变更。调大它可以让集群对网络抖动更容忍但也会拖慢故障切换速度需要权衡。consensus一般要求大于token值用于处理多节点同时异常时的一致性达成不宜设得太紧。transport: knet是当前主流传输层支持多链路和加密老式的udp/udpu在生产环境不建议再用。crypto_cipher与crypto_hash配合启用端到端加密通信防止有心人直接抓包分析心跳数据和资源状态。expected_votes: 3告诉集群“正常情况下有几票”投票机制依赖它计算法定票数阈值。节点数变化时需要同步更新这个值否则可能造成节点即使数量足够也无法达成法定票数。如果只有两个节点pcs setup 时加--force它会自动写入two_node: 1。此时法定票数规则被特殊处理但仍强烈建议配合fence使用。3.3 加密层配置默认pcs生成的配置不会强制加密但对于生产环境这一步我建议必须开启。在pcs 0.10以上版本可以通过pcs cluster setup mycluster node1 node2 node3 --encryption自动生成密钥并写入配置。也可以手动在totem中添加crypto_model: aead crypto_cipher: aes256 crypto_hash: sha256aead模型提供认证加密一条消息同时保证机密性和完整性。开启之后可以用corosync-cfgtool -s查看通信状态输出中会有加密标志说明。加密开关最怕的就是“改了配置忘记重启”。每次修改corosync.conf后必须执行pcs cluster stop --all pcs cluster start --all让所有节点用新配置重新建立连接。只重启单个节点的corosync可能因token不匹配导致节点长时间无法加入。4. 启动集群前的最后一步让Pacemaker接管资源4.1 pcs cluster start 之后再做什么集群启动后corosync和pacemaker两个服务都会在节点上拉起。验证集群状态用pcs status正常情况下会看到类似Cluster name: mycluster Cluster Summary: * Stack: corosync * Current DC: node1 (version 2.0.5) * Last updated: ... * Last change: ... * 3 nodes configured * 0 resource instances configuredCurrent DCDesignated Controller表示当前集群的控制节点它负责汇总各节点状态、执行资源调度决策。如果某个节点没有出现在节点列表中先查corosync-quorumtoolcorosync-quorumtool -l它能列出当前哪些节点在线、哪些失联以及当前是否达到法定票数。和pcs status配合可以快速定位问题是属于通信层还是资源调度层。4.2 集群属性与全局策略刚启动的集群并不会自动保护资源必须先设置几个全局属性否则后续创建资源时会碰壁。pcs property set stonith-enabledfalse pcs property set no-quorum-policyignore上述两条仅适用于没有配置fence的测试环境。stonith-enabledfalse表示不启用隔离设备no-quorum-policyignore表示失去法定票数后不停止资源测试方便但生产环境这么做等于把“双主风险”敞开了。在有fence设备的生产环境应该设置pcs property set stonith-enabledtrue pcs property set no-quorum-policystopno-quorum-policystop的意思是节点判断自己已经成为少数派、达不到法定票数时主动停止本地资源让出运行权防止数据被多点写入。这是最常见的生产配置也是Pacemaker能做“脑裂保护”的关键。4.3 从corosync层面检查集群健康资源调度问题往往从pcs status能看出来但通信层的问题还是得回到Corosync的工具链。常用检查三板斧corosync-cfgtool -s # 查看环连接状态 corosync-quorumtool -s # 查看法定票数情况 journalctl -u corosync --since 5 minutes ago | tail -200-s输出会显示每个ring的连接状态如果有TRANSPORT或CRYPTO层的报错通常意味着链路不稳定或加密配置不一致。法定票数输出里有一项Quorate值为yes才算正常。如果为no即使pcs status显示节点在线Pacemaker也不会执行任何资源调度。常见的状态含义可以直接对照下表状态含义处理方向Quorate: yes达到法定票数集群可正常决策无需处理Quorate: no票数不足资源停止调度检查失联节点、恢复网络、核对expected_votesRing status: faulty环连接异常检查网卡、交换机、knet链路Missed heartbeat心跳丢失计数增加排查时间同步、网络延迟、token设置5. 创建一个真正的业务资源从VIP到Nginx5.1 Resource Agent的选择逻辑资源代理Resource Agent是Pacemaker对接具体服务的桥接层。常见三类ocf:heartbeat:*OCF标准脚本Pacemaker最常用的资源类型如IPaddr2、Filesystem、nginx等。lsb:*兼容SysV init脚本老环境常见新项目不建议。systemd:*直接托管systemd服务单元和systemctl的管理行为一致。选型时有几个经验原则。纯网络类资源优先选ocf:heartbeat:IPaddr2它带了arp通告和if_down处理切换体验更平滑业务进程优先用systemd:或官方提供的OCF脚本因为systemd单元能更好回收子进程数据库这类有状态服务不要只依赖默认monitor检查最好用ocf:heartbeat:pgsql或mysql自带的健康检查脚本避免“进程还在但无法写入”的假活状态。5.2 定义IPaddr2、nginx资源以一套Nginx VIP的最小高可用服务为例。首先创建VIP资源pcs resource create vip ocf:heartbeat:IPaddr2 \ ip10.10.10.100 cidr_netmask24 \ op monitor interval5s timeout20sop monitor interval5s表示每5秒执行一次健康检查。IPaddr2的monitor动作会检查网卡上是否绑定了目标IP如果绑定失败或漂移异常立即触发资源重启或迁移。然后创建Nginx资源pcs resource create nginx-server systemd:nginx \ op monitor interval10s timeout20s这里依赖systemd管理Nginx。创建完成后资源是并行启动的两者各自分散在不同节点上所以必须添加约束。5.3 资源组与约束谁先启动谁能跟谁待在一起约束是Pacemaker最核心也最容易理解错的地方。两道最基本的约束pcs constraint order vip then nginx-server pcs constraint colocation add nginx-server with vip INFINITY顺序约束order保证VIP先绑定然后Nginx再启动。不配置的话可能出现Nginx先起来、但监听IP还没漂移过来的窗口期。排列约束colocation是“谁能跟谁待在一起”的规则。INFINITY表示无限强制意味着nginx-server必须运行在vip所在的节点。如果二者跑了pcs status看location一定会发现被绑在一起。生产环境经常用资源组把多个强绑定的资源包在一起pcs resource group add web-group vip nginx-server组内自带顺序和排列约束节点故障时整组一起迁移。但资源组不适合跨节点有复杂依赖的场景比如数据库依赖共享存储、同一存储不能挂多个节点就得拆开写分离约束pcs constraint colocation add db-data with db-vip INFINITY pcs constraint colocation add db-backup-server with db-data -INFINITY-INFINITY表示强制分离避免备份服务与主数据库抢资源或少数据写入口。约束不是越多越好每多一条都意味着故障时调度器要多算一层可维护性也会下降。6. 模拟故障后发生了什么一次完整的切换复盘6.1 拔网线/停服后的调度逻辑在测试环境里我习惯直接停掉某一节点的corosync服务来模拟节点失联systemctl stop corosync此时集群剩下的两个节点会启动故障判定流程。流程大致是Corosync在token时间内没有收到故障节点的心跳就会触发成员变更变更消息广播到所有存活节点Pacemaker的DC收到变更后重新评估资源位置决定是否把涉及该节点的资源重新放置如果存活的节点没有约束冲突新节点开始启动资源成员。pcs status的变化过程非常直观故障节点变成OFFLINEVIP和Nginx资源从Started变成Migrating然后其他节点上变成Started。整个过程通常发生在5到10秒内具体时延和token值成正比。6.2 切换过程观测对运维而言故障瞬间最能体现集群管理质量。我一般开三个终端同时观察watch -n 0.5 pcs status watch -n 1 corosync-quorumtool -l journalctl -f -u pacemaker -u corosync第一屏看资源落在哪个节点第二屏看成员关系第三屏看调度日志。实际现象是故障节点从Members列表消失pcs status里出现OFFLINE随后资源在存活节点上启动日志里能看到Resource action: nginx-server start on node2这样的记录。如果配置了fence设备流程中间还会插入一步存活节点先对故障节点执行隔离操作比如通过IPMI断电确认故障节点被强制下线后才开始资源迁移。没有这一步故障节点上的脚本可能还在运行赶上共享存储场景就是灾难。6.3 Ping不通了从集群层面排查故障切换后有时会发现VIP虽然漂移了但外部依然无法访问。此时不能只盯pcs status要分三路排查第一路看约束是否生效。pcs constraint colocation list确认VIP和Nginx绑在一起如果分散检查约束是否因为start动作失败而被临时重置。第二路看ARP表是否刷新。IPaddr2脚本切换后会自动发送免费ARP但有些交换机或者云环境需要额外配置端口安全策略。如果对端仍然把包发往旧节点的MAC地址业务自然不通。第三路看应用服务状态。Nginx进程起来了但业务端口没起来或者监听地址绑定错了网卡也会造成“集群正常、业务不通”的假象。此时用ss -lntp和curl直接在存活节点上验证。下面是一个故障排查速查表现象排查命令常见根因资源未迁移pcs constraint 查看约束约束阻止、storage等资源无法启动资源已迁移但ping不通arp -a交换机arp表未刷新、VIP绑错网卡切换时间过长corosync-cfgtool -stoken设置过大、心跳网卡降级节点被反复踢除journalctl -u corosync时间不同步、网络抖动、加密配置不一致7. 我在生产环境踩过的坑完整排查链路7.1 坑一两台节点同时起资源——法定票数配置不当导致双主某次两节点测试集群我为了图省事只执行了pcs cluster setup没加--force然后手动在corosync.conf里塞了two_node: 1还设了no-quorum-policyignore。结果某次网络中断后两边节点都认为自己是唯一合法节点同时把Nginx拉起来了——两台都有VIP外部流量被随机分发到两台机器业务侧毫无感知但数据层已经开始双写。定位过程当时异常痛苦查了网卡、查了路由最后打开日志才发现corosync报 “Quorum lost”两边都在执行资源启动。根因就是两节点配置下必须让集群在失去成员时判断自己没有法定资格才能让no-quorum-policystop生效从而停止资源。正确配置顺序是pcs cluster setup mycluster --force node1 node2 pcs property set stonith-enabledfalse pcs property set no-quorum-policystop7.2 坑二token设置过大导致故障转移时间拖到30秒这个坑让我被业务方骂了一周。接手一个老集群corosync.conf里token: 3000030秒当时是为了忍受跨机房网络抖动才调大的。结果某次上游网络割接主节点宕了业务中断了整整35秒——因为Pacemaker要等Corosync把token耗尽确认节点真死了才开始调度资源。调校参数前需要先算一笔账token决定了故障感知上限consensus必须大于tokenjoin不能过小。跨机房场景建议检测真实网络抖动再调不要无脑调大。当时把token改回5000并配合knet多链路冗余往返丢包率低于1%时切换时间稳定在7秒左右。对于普通业务token设3000到5000是多数场景下的安全区间。7.3 坑三升级内核后corosync进程连接异常某次安全整改给所有节点执行了yum update重启后node3的corosync进程反复崩溃加入不了集群。pcs status里node3永远是OFFLINE或UNCLEAN。检查journalctl看到大量与knet相关的DGRAM创建失败最终定位到新版内核的rp_filter反向路径过滤策略对多网卡场景不友好导致corosync绑定的对端地址被认为不合法而丢弃。解决办法是在node3的sysctl.conf中临时关闭对该业务网卡的rp_filternet.ipv4.conf.all.rp_filter 0 net.ipv4.conf.default.rp_filter 0 net.ipv4.conf.eth1.rp_filter 0 sysctl -p systemctl restart corosync这也提醒了所有做集群管理的人每次升级内核前先检查集群兼容性尤其是遇到多网卡、多链路、高安全加固的系统环境。7.4 其他常见问题速查表除了上面三个案例我再整理一张速查表都是日常维护中高频遇到的问题问题现象可能原因解决方向pcs host auth失败pcsd未启动或防火墙拦截2224端口启动pcsd放行端口资源一直显示Stopped约束冲突、资源代理脚本权限/语法问题查看pacemaker日志、pcs resource debug-start resourceName两台节点同时出现相同VIP未配置fence、两节点quorum配置错误规范配置no-quorum-policy配置fence设备corosync启动失败报bind error网卡名/地址与nodelist不一致核对nodelist的ring0_addrpcs status显示Failed Actions资源监控超时、脚本执行异常pcs resource failcount reset resourceName查超时日志迁移后VIP在旧节点残留未启用stontith、网络隔离不彻底配置fence并启用stonith8. 最后提醒一点别让集群本身成为单点维护Corosync Pacemaker这套组合几年下来我最大的体会是集群管理工具本身也会出问题人类对它的过度信任才最致命。有值班时凌晨3点接到告警说某个节点存储读IO卡住但集群不切换——因为资源代理检查到进程还活着、端口还能连却没有深入验证底层存储是否可用。后来给Filesystem资源加了额外的深度监控参数才避免同样问题再次发生。类似经验还有好几个Nginx进程傻活但上游API全挂MySQL端口通但无法执行查询。资源代理默认监控的都是浅层检查生产环境必须根据业务特点自己补健康检查逻辑。还有一点建议至少每季度做一次真实的故障演练。不要只在文档里写“切换测试通过”要真的把某个节点的systemctl stop corosync按下去观察VIP和服务漂移的完整过程把监控告警、工单流程一起串起来跑一遍。只有演练过才能发现ARP表不刷新、fence权限变更、防火墙策略更新这类只有在真实故障中才会暴露的隐性坑。如果团队刚接触这套技术我建议先从小范围的非核心服务开始比如内部管理系统跑通整个切换流程后再逐步上生产核心业务。手边时刻保留一套可复现的脚本集和配置存档并在每次修改配置后利用pcs config backup做快照备份。这套组合能给你带来很高的稳定性但稳定永远不是“装完就完事”而是靠持续维护和演练换来的。