两台服务器都运行着相同的业务服务,并不等于入口已经高可用。

假设客户端把请求固定发给 node-1。即使 node-2 完全正常,只要 node-1 宕机,客户端仍然找不到 node-2。问题不在于“有没有备用服务器”,而在于入口地址仍然属于某一台具体机器

Keepalived 解决的就是这个入口问题:它让多个节点共同维护一个虚拟 IP,并根据节点状态决定当前由谁持有这个 IP。客户端只记住虚拟地址,不需要参与主备判断。

本文不讨论软件安装和系统命令,而是围绕以下问题建立完整的理解:

  • Keepalived、VRRP 和 VIP 分别负责什么?
  • MASTER 是写在配置里的,还是选举出来的?
  • Nginx 故障为什么能够影响 VIP 的归属?
  • priorityweight 如何共同决定有效优先级?
  • 服务故障、Keepalived 故障和主机故障有什么区别?
  • 节点恢复后,VIP 为什么有时会切回来,有时不会?
  • 什么是脑裂,Keepalived 又有哪些能力边界?

🧭 Keepalived 解决的核心问题

先看一个典型的双节点入口:

Keepalived 双机高可用拓扑客户端始终访问虚拟地址 192.168.10.100。node-1 是优先级 120 的 MASTER 并持有 VIP,node-2 是优先级 100 的 BACKUP;两个节点通过 VRRP 单播交换状态。VRRP UNICAST · FLOATING IP客户端只访问虚拟 IPVIP · 192.168.10.100当前绑定到 MASTERnode-1 · 192.168.10.11MASTERpriority 120持有 VIP · Nginx 运行node-2 · 192.168.10.12BACKUPpriority 100等待接管 · Nginx 运行VRRP 单播通告
客户端只访问 VIP;Keepalived 通过 VRRP 选举决定 VIP 当前属于哪台服务器。

图中有三个不同层次的地址:

地址含义
node-1 的真实 IP唯一标识 node-1,本身不会漂移
node-2 的真实 IP唯一标识 node-2,本身不会漂移
VIP面向客户端的服务入口,可以在两个节点之间移动

正常情况下,node-1 是 MASTER,VIP 绑定在 node-1 上。node-2 是 BACKUP,它不会绑定 VIP,但会持续观察 MASTER 是否正常。

当 node-1 不再适合提供服务时,node-2 接管 VIP。客户端仍然访问原来的地址,变化只发生在入口地址背后。

这里要特别注意:Keepalived 不是 Nginx 的替代品,也不是请求代理。Nginx 负责处理 HTTP 请求,Keepalived 只负责回答一个问题:现在应该由哪台机器拥有 VIP?

🧩 Keepalived、VRRP 与 VIP

这三个概念经常一起出现,但它们并不是同一层面的东西。

Keepalived

Keepalived 是运行在 Linux 节点上的高可用软件。它负责运行 VRRP 实例、检查本机状态、计算优先级,并在角色变化时添加或移除 VIP。

可以把它理解成每台节点上的“本地决策者”。它既观察本机,也接收其他节点发来的状态信息。

VRRP

VRRP(Virtual Router Redundancy Protocol)是节点之间协调主备关系的协议。多个节点通过相同的 virtual_router_id 组成一个虚拟路由器,其中一个节点成为 MASTER,其余节点处于 BACKUP。

MASTER 周期性发送通告,表达“我仍然在线,而且我的优先级是这么多”。BACKUP 收到通告后保持等待;如果更高优先级节点出现,或者 MASTER 的通告消失,角色就可能改变。

VRRP 使用的是 IP 协议号 112,不是某个 TCP 或 UDP 端口。组播和单播只是报文发送方式不同,传输的仍然是 VRRP 通告。

VIP

VIP(Virtual IP)是虚拟路由器对外提供的地址。它不永久属于某台服务器,而属于“当前 MASTER”这个角色。

因此,VIP 漂移的本质不是修改客户端配置,而是改变这个地址当前绑定在哪台机器的网卡上。新 MASTER 接管后,通常还会通过 Gratuitous ARP 等机制通知周围网络设备更新地址映射。

👑 MASTER 与 BACKUP 如何协作

可以把双节点关系理解成一个持续运行的状态机:

  1. 两个节点启动并加入同一个 VRRP 实例。
  2. 节点比较优先级,选出 MASTER。
  3. MASTER 绑定 VIP,并周期性发送 VRRP 通告。
  4. BACKUP 不绑定 VIP,只监听 MASTER 的通告。
  5. 当选举条件变化时,BACKUP 可能升级为 MASTER。
  6. 原 MASTER 失去资格后移除 VIP,新的 MASTER 绑定 VIP。

配置中的 state MASTERstate BACKUP 主要表达初始状态倾向,并不是永久身份。最终角色由 VRRP 通告、优先级、跟踪项以及抢占策略共同决定。

换句话说,MASTER 是运行时角色,不是服务器的固定名称。今天的 node-1 可以是 MASTER,故障后 node-2 也可以成为 MASTER。

为什么 BACKUP 不立即接管

网络偶尔丢失一条报文并不意味着 MASTER 已经故障。如果 BACKUP 因为一次通告没收到就接管 VIP,系统会非常容易抖动。

因此,BACKUP 会等待一个 MASTER Down 时间窗口。只有在这个窗口内持续收不到有效通告,才认为原 MASTER 已经不可用。advert_int 越短,故障发现通常越快,但报文频率也越高;实际业务恢复时间还会受到健康检查、系统调度、地址通告和客户端重试影响。

⚖️ VRRP 如何选出 MASTER

选举的核心规则很直观:有效优先级更高的节点更有资格成为 MASTER。

常见配置可以压缩成下面这个最小模型:

vrrp_instance VI_1 {
    state BACKUP
    interface eth0
    virtual_router_id 51
    priority 120
    advert_int 1

    virtual_ipaddress {
        192.168.10.100/24
    }
}

这里最值得理解的不是语法,而是参数之间的关系:

参数逻辑含义
virtual_router_id哪些节点属于同一场选举
priority本节点的基础竞争力
advert_intMASTER 多久声明一次自己仍然可用
virtual_ipaddress获胜节点需要持有的入口地址
interfaceVIP 和 VRRP 实例关联的网络接口

同一个 VRRP 实例中的节点必须使用相同的 VRID,但应该使用不同的优先级。假设 node-1 的基础优先级为 120,node-2 为 100,两者状态都正常时,node-1 成为 MASTER。

如果优先级相同,协议还需要使用其他规则打破平局。学习和设计时不应依赖平局结果,而应主动为节点设置清晰、不同的优先级。

🧮 基础优先级与有效优先级

只看 priority 还不够,因为 Keepalived 可以根据本机状态动态调整节点的竞争力。

  • 基础优先级:配置中的 priority
  • 有效优先级:基础优先级叠加健康检查、接口状态或其他跟踪项的权重之后,用于实际比较的值。

以本文的双节点为例:

node-1 基础优先级:120
node-2 基础优先级:100
node-1 的 Nginx 检查失败权重:-30

正常时,120 > 100,node-1 持有 VIP。node-1 的 Nginx 故障后:

node-1 有效优先级:120 - 30 = 90
node-2 有效优先级:100

此时 90 < 100,node-2 更有资格成为 MASTER。

EFFECTIVE PRIORITY健康检查如何改变选举结果
健康状态优先级对比node-1 优先级为 120,高于 node-2 的 100,因此 VIP 位于 node-1。健康状态两台 Nginx 均可用node-1 · 120node-2 · 100120 > 100VIP 在 node-1Nginx 故障后的优先级对比node-1 的健康检查失败,优先级从 120 减少 30 变为 90,低于 node-2 的 100,因此 VIP 切换到 node-2。Nginx 故障track_script 应用 weight -30node-1 · 120 - 30 = 90node-2 · 10090 < 100VIP 切换到 node-2
负权重必须足以改变优先级顺序:node-1 从 120 降到 90 后,node-2 的 100 才能接管 VIP。

这也解释了一个常见误区:健康检查失败,不一定会导致 VIP 漂移。如果 node-1 的权重只是 -10,它的有效优先级仍然是 110,依然高于 node-2 的 100

所以设计权重时,真正的问题不是“要扣多少分”,而是:

故障发生后,剩余的有效优先级是否足以改变选举结果?

🩺 Keepalived 如何感知业务故障

VRRP 通告只能证明 Keepalived 和网络仍在工作,不能证明 Nginx、数据库或业务接口一定健康。

例如,node-1 的操作系统和 Keepalived 都正常,但 Nginx 已经停止。此时 node-1 仍然能够发送 VRRP 通告。如果没有业务健康检查,它会继续持有 VIP,客户端却只能访问到一个失效入口。

Keepalived 通过 vrrp_script 定义检查,再通过 track_script 把检查结果关联到 VRRP 实例:

vrrp_script chk_nginx {
    script "/etc/keepalived/check-nginx.sh"
    interval 2
    timeout 1
    weight -30
    fall 2
    rise 2
}

vrrp_instance VI_1 {
    priority 120

    track_script {
        chk_nginx
    }
}

这段配置表达的是一条决策链:

运行检查脚本

根据退出码判断健康状态

连续失败达到 fall 次

应用 weight,修改有效优先级

重新比较节点资格

必要时触发 MASTER 切换

intervaltimeoutfallrise

参数含义主要影响
interval 2每 2 秒检查一次检查频率
timeout 1单次检查最多等待 1 秒防止脚本卡住
fall 2连续失败 2 次才确认故障抗瞬时抖动能力
rise 2连续成功 2 次才确认恢复防止刚恢复就立即回切

阈值越敏感,发现故障越快,但误判风险越高;阈值越保守,系统越稳定,但接管会更慢。它们本质上是在“恢复速度”和“抗抖动能力”之间做取舍。

负权重与 FAULT

负权重表示检查失败后降低有效优先级,让节点继续参与比较。这适合把多个因素综合起来决定角色。

某些跟踪方式也可以在失败时让实例直接进入 FAULT。这表示当前节点不再具备持有 VIP 的基本条件,而不是简单地少一些分数。

可以这样区分:

  • 负权重:这个节点变差了,但仍可以参与选举。
  • FAULT:这个节点当前没有资格成为 MASTER。

🔄 一次完整的故障切换

下面把 Nginx 故障后的变化连成一条完整时间线:

Keepalived 健康检查触发 VIP 故障切换node-1 的 Nginx 连续失败后,有效优先级从 120 降至 90。node-2 以优先级 100 成为 MASTER,VIP 和客户端请求路径切换到 node-2。客户端请求VIP · .100node-1 · 192.168.10.11MASTERBACKUPpriority 120120 - 30 = 90Nginx 健康连续 2 次检测失败node-2 · 192.168.10.12BACKUPMASTERpriority 100Nginx 健康 · 接管服务track_script · weight -30node-2 接管完成
Nginx 故障使 node-1 的有效优先级降到 90;node-2 以 100 成为 MASTER,VIP 和请求路径随之切换。
  1. 正常阶段:node-1 的有效优先级为 120,作为 MASTER 持有 VIP;node-2 以 100 处于 BACKUP。
  2. 检测阶段:node-1 的 Nginx 开始失败,但 Keepalived 不会因为单次失败立即切换。
  3. 确认阶段:失败次数达到 fall,检查结果正式变为不健康。
  4. 降权阶段:node-1 应用 weight -30,有效优先级降到 90
  5. 重新选主:node-2 的 100 高于 node-1 的 90,node-2 成为新的 MASTER。
  6. VIP 转移:node-1 移除 VIP,node-2 绑定 VIP,并向网络声明新的地址归属。
  7. 客户端恢复:客户端仍然访问同一个 VIP,但请求已经由 node-2 处理。

“故障切换时间”不是一个单独参数。它至少由以下几部分组成:

故障确认时间
+ VRRP 状态收敛时间
+ VIP 添加与网络邻居更新
+ 客户端超时和重试
= 用户感知到的恢复时间

因此,即使 VIP 很快完成漂移,原有 TCP 连接也可能中断。Keepalived 解决的是入口重新可达,并不会把已经建立的连接状态一起迁移到新节点。

🧯 三类故障有什么不同

理解故障类型,比记住停止服务的命令更重要。

业务服务故障

例如 Nginx 停止响应,但操作系统、网络和 Keepalived 仍然正常。

这类故障必须依赖业务健康检查发现。切换的直接原因通常是有效优先级下降,或者 VRRP 实例进入 FAULT

Nginx 故障 → 检查失败 → 有效优先级变化 → VIP 切换

Keepalived 进程故障

业务服务可能仍然正常,但 Keepalived 已经停止,无法继续维护 VIP 或发送 VRRP 通告。

BACKUP 会因为失去 MASTER 通告而接管。这里不需要依赖 Nginx 检查,核心信号是 VRRP 心跳消失。

Keepalived 故障 → VRRP 通告消失 → BACKUP 超时 → VIP 切换

主机或网络故障

服务器断电、内核崩溃、网卡离线或链路中断时,原 MASTER 无法执行优雅清理,也无法主动告诉其他节点自己已经故障。

BACKUP 仍然只能通过“持续收不到通告”推断故障。这类切换更能反映真实高可用能力,因为它不依赖原节点配合。

主机或链路故障 → 通告不可达 → BACKUP 超时 → VIP 切换

三类故障最终都可能表现为 VIP 漂移,但触发信号不同:

故障类型Keepalived 是否还在运行主要判断依据
业务服务故障本地健康检查
Keepalived 进程故障VRRP 通告消失
主机或网络故障否或不可达VRRP 通告持续不可达

🔁 抢占、延迟抢占与非抢占

故障节点恢复后,还需要回答一个问题:VIP 要不要切回原来的高优先级节点?

默认抢占

高优先级节点恢复后重新成为 MASTER。优点是拓扑会回到预设状态;缺点是恢复过程又产生一次切换,可能再次影响连接。

延迟抢占

通过 preempt_delay 给恢复节点预留观察时间:

state BACKUP
preempt_delay 60

它不会延迟故障时的接管,而是延迟高优先级节点恢复后的回切。这样可以避免服务刚恢复就立刻承担入口流量。

非抢占

通过 nopreempt 让当前 MASTER 继续工作,即使原来的高优先级节点已经恢复:

state BACKUP
nopreempt

非抢占模式通常要求实例以 BACKUP 作为初始状态。它减少了不必要的来回切换,但意味着当前 MASTER 可能长期不是最初规划的主节点。

三种策略没有绝对优劣:

策略恢复后的行为适合关注点
默认抢占VIP 切回高优先级节点固定主备关系
延迟抢占等待一段时间后再切回恢复稳定性
非抢占保持当前 MASTER减少回切次数

⚠️ 脑裂、抖动与错误切换

脑裂

脑裂指多个节点都认为自己应该成为 MASTER,并同时持有同一个 VIP。

最常见的原因不是两台机器同时坏了,而是它们之间的 VRRP 通信被切断:

node-1 收不到 node-2
node-2 也收不到 node-1
两边都认为对方已经失效
两边都尝试成为 MASTER

这说明 Keepalived 的判断建立在“我能看到什么”之上,而不是一个拥有全局视角的中心协调器。网络隔离时,每个节点都可能基于局部信息做出合理但互相冲突的决定。

健康检查抖动

如果业务接口时好时坏,而 fallrise 又设置得过小,节点的有效优先级会频繁变化,VIP 也可能在两边来回漂移。

解决思路不是无限增加切换速度,而是区分:

  • 短暂超时是否应该被忽略?
  • 连续多少次失败才代表真实故障?
  • 恢复后需要稳定多久才重新接管?
  • 是否真的需要自动回切?

权重无法改变结果

健康检查已经失败,VIP 却没有移动,往往不是脚本“没生效”,而是降权后的节点仍然拥有更高有效优先级。

排查这类问题时,应先写出每个节点的计算式,而不是先盯着配置语法:

基础优先级 + 所有跟踪项权重 = 有效优先级

🧱 Keepalived 能做什么,不能做什么

Keepalived 的能力边界非常清晰。

它能做什么

  • 在多个节点之间选出一个 MASTER。
  • 根据 VRRP 通告判断对端是否仍然可达。
  • 根据脚本、接口和其他跟踪项调整节点资格。
  • 在角色变化时添加或移除 VIP。
  • 为客户端提供相对稳定的网络入口。

它不能做什么

  • 不会同步 Nginx 配置、证书或静态文件。
  • 不会复制数据库数据或解决数据一致性问题。
  • 不会迁移已经建立的 TCP 连接和内存会话。
  • 不会自动保证两个节点的业务能力完全相同。
  • 无法单独消除所有网络分区和脑裂风险。
  • 不能保证切换对客户端绝对无感。

所以,一套完整的高可用系统至少还需要考虑:

入口高可用:Keepalived / VIP
业务高可用:两个节点都能独立处理请求
数据高可用:复制、共识或共享存储
客户端韧性:超时、重试和连接重建
可观测性:状态、日志、告警和故障演练

Keepalived 只覆盖其中一部分,但这一部分非常关键:它把客户端与某台具体服务器解耦了。

🧠 建立自己的判断模型

以后看到一份 Keepalived 配置,可以按下面的顺序理解,而不是逐行背参数:

  1. 谁在参加同一场选举?virtual_router_id、网络接口和对端关系。
  2. 正常时谁应该获胜? 比较各节点的基础优先级。
  3. 什么故障会改变资格? 找到 track_script、接口和其他跟踪项。
  4. 故障后分数是多少? 计算每个节点的有效优先级。
  5. MASTER 消失后多久接管? 看 VRRP 通告与故障确认逻辑。
  6. 故障节点恢复后是否回切? 看抢占、延迟抢占和非抢占策略。
  7. 如果节点互相看不见会怎样? 评估网络隔离和脑裂风险。
  8. VIP 切换后业务真的可用吗? 检查数据、会话和客户端重试能力。

只要这八个问题能回答清楚,配置中的大多数参数就不再是孤立的关键字,而是一套完整决策逻辑的组成部分。

✍️ 思考题

可以尝试不看前文回答下面的问题:

  1. node-1 的优先级是 120,node-2 是 100。如果 node-1 的失败权重为 -10,VIP 会切换吗?为什么?
  2. 两台节点的 Nginx 都正常,但 MASTER 的 Keepalived 进程退出,BACKUP 依靠什么发现故障?
  3. 为什么 fall 1 能更快切换,却不一定是更好的配置?
  4. VIP 已经切换到 node-2,为什么客户端的原有连接仍可能断开?
  5. node-1 恢复后不希望 VIP 自动切回来,应该考虑哪种策略?
  6. 两个节点之间的 VRRP 报文被防火墙同时拦截,最危险的结果是什么?
  7. Keepalived 已经实现 VIP 高可用,为什么数据库仍然可能是单点?

✅ 总结

Keepalived 的核心逻辑可以浓缩为四句话:

  1. 多个节点通过 VRRP 组成一个虚拟路由器。
  2. 有效优先级决定当前由谁成为 MASTER 并持有 VIP。
  3. 健康检查把本机业务状态转换成优先级或资格变化。
  4. 抢占策略决定故障恢复后是否再次切换。

理解 Keepalived,不应该从复制两份配置开始,而应该先理解“节点看到什么、如何计算、何时改变角色”。当你能根据基础优先级、健康检查结果和抢占策略推导出 VIP 的归属时,就真正掌握了它的工作逻辑。

📚 参考资料