ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

Keepalived双机热备:从VRRP原理到实战配置全解析

Keepalived双机热备:从VRRP原理到实战配置全解析 干运维这些年被问得最多的需求之一就是“两台机器怎么搞热备”。业务量再小老板也怕单点故障数据库、Nginx、网关这些核心服务只要挂一台整个系统就瘫了客户投诉电话马上就来。我自己接过不少这样的烂摊子最后用得最顺手的方案还是 keepalived 双机热备。坚持用 keepalived不是因为它有多花哨而是它足够简单、足够稳。它就是一套基于 VRRP 协议实现的高可用方案核心就干一件事在两台服务器之间维护一个虚拟 IPVIP平时 VIP 落在主服务器上干活一旦主服务器宕机、服务异常或者网络出问题VIP 自动漂移到备服务器业务流量无缝切换用户几乎感知不到。整个过程不需要改应用代码不需要动数据库配置纯粹靠系统层面的资源漂移解决高可用问题。这篇文章我打算把 keepalived 双机热备从原理到配置再到踩坑完整梳理一遍。不管你是刚接触高可用的新手还是已经在用但被脑裂、切换失败折磨过的老手应该都能找到自己想要的答案。1. 双机热备到底解决什么问题先想清楚再动手1.1 单点故障是系统架构的原罪做高可用之前先要明白一个道理物理机不是永动机。电源会烧网卡会松磁盘会坏内核会 panic机房还会偶尔断电。哪怕是云主机也有底层宿主机迁移、维护导致实例重启的时候。如果你的核心服务只运行在一台机器上那么这台机器的任何一次意外都会让你的业务直接归零。我见过一个真实的案例某公司把自己的核心数据库放在一台老旧的物理机上没有做任何高可用方案。有一天那台机器的 RAID 卡直接挂了系统起不来数据库备份还在另一台存储上恢复花了整整一天。那一天公司所有线上业务全部停摆损失惨重。事后复盘开发团队说“以为数据库不会挂”这种想法在运维眼里就是定时炸弹。所以双机热备解决的核心问题就是“消除单点”。我用两台机器同时跑同一个服务正常情况下流量走主节点备节点待命主节点出故障了备节点立刻顶上。听起来很朴素的思路但实现起来牵扯到的问题并不少两台机器怎么知道对方挂了切换的时候 VIP 怎么过去切换需要多久切过去了应用还能不能正常对外提供服务这些问题keepalived 都给出了标准答案。1.2 keepalived 在双机热备生态里的位置市面上做高可用的软件不少常见的有 Keepalived、Heartbeat、PacemakerCorosync还有各种商业软件的 HA 模块。但我个人在 Linux 服务器上做双机热备用得最多的还是 Keepalived。原因有三点。第一Keepalived 配置极简核心就是一个/etc/keepalived/keepalived.conf配置文件几十行内容就能把主备关系、VIP、健康检查全部定义清楚没有复杂的集群资源管理概念。第二Keepalived 自带健康检查脚本机制可以定时检测 Nginx、MySQL、进程、端口甚至业务状态检测挂了才切换不是单纯依赖对方机器宕机才切换这个功能非常实用。第三Keepalived 和 LVSLinux Virtual Server集成得非常深如果你有负载均衡需求可以只用一套 Keepalived 配置同时搞定 LVS 负载均衡和服务高可用。相比之下Heartbeat 配置繁琐Pacemaker 功能强大但学习曲线陡峭对小团队或者单一业务场景来说性价比不高。Keepalived 能成为运维界默认的双机热备工具靠的是“够用、好用、稳定”。1.3 先分清主备模式、双主模式和主主模式在动手配置之前还得先明确你要哪种高可用模式。Keepalived 支持三种常见的部署模式这里我梳理一下它们的区别和适用场景主备模式Active-Standby一台服务器承载全部流量另一台备用只有主服务器故障时才接管 VIP。这种模式配置最简单适合数据库、缓存等不适合并行写多份的服务。我绝大多数生产环境用的都是这种模式因为逻辑清晰、不容易出乱子。双主模式Active-Active两台服务器都承载流量但对外提供的是同一个 VIP靠 LVS 把请求分到两台机器上。这种模式适合无状态服务比如 Web 层、API 网关。两台的资源利用率高但需要业务本身支持水平扩展不能有跨节点共享状态。主主模式Mutual-Master两台机器分别拥有不同的 VIP互为主备A 挂了 B 接 A 的 VIPB 挂了 A 接 B 的 VIP。这种模式适合两台机器分别承载不同业务、希望互相兜底的场景。在选择模式时不要一味追求 Active-Active。高可用的第一目标是“稳定切换”不是“资源利用率最大化”。如果业务状态管理复杂老老实实做主备把切换逻辑做得干净利落远比费劲心思做双活最后搞得两头不到岸要好。2. 核心原理拆解VRRP 协议以及 VIP 漂移的秘密2.1 VRRP 是怎么做到“一台挂了另一台上”的Keepalived 的地基是 VRRP 协议全称 Virtual Router Redundancy Protocol虚拟路由冗余协议。这个协议本身就是网络设备为了实现网关高可用设计的思路是把多台路由器组成一个“虚拟路由器”对外表现为一个 IP内部通过竞选机制决定谁当 Master 谁当 Backup。Keepalived 把 VRRP 的理念搬到了服务器层面。它通过报文宣告自己的状态Master 节点会周期性地默认 1 秒向组播地址 224.0.0.18 发送 VRRP 通告报文通知所有 Backup“我还活着”Backup 节点则在监听一旦连续默认 3 个通告周期也就是 3 秒左右没收到 Master 的报文就判定 Master 挂了立刻进入竞选状态把自己的状态提升为 Master接管 VIP。这个过程里有个关键概念叫“优先级”范围是 1-254数字越大越优先。主节点的优先级通常配置成 100备节点配置成 90 左右。只要主节点不出问题备节点靠优先级永远选不过主节点。当主节点故障时备节点因为收不到通告直接提升自己抢占 VIP。一旦原主节点恢复上线又会重新参与竞选因优先级更高会把 VIP 抢回来。这里面有两个最常见的坑我提前说一下。第一VRRP 报文走的是组播依赖网络设备正常转发组播数据如果两台服务器之间有防火墙且没有放行 224.0.0.18 这个组播地址那么备节点永远收不到主节点的通告会出现两台机器同时认为自己是主节点的“脑裂”现象VIP 在两个节点上同时存在流量来回跳后果极其严重。第二advert_int通告间隔时间不要随便调小主节点忙到 CPU 打满时可能影响报文发送过小的间隔反而更容易造成误判生产环境建议 1 秒测试环境可以调到 2 秒。2.2 抢占模式 vs 非抢占模式别让业务跟着你一起抖这个是很多新手容易忽略、但在生产环境里极其重要的一个设置。Keepalived 默认是“抢占模式”也就是主节点恢复后会立刻把 VIP 从备节点手上抢回来。听起来很合理但实际生产中我踩过不少次坑原本主节点只是因为瞬时网络抖动触发了切换业务已经平稳运行在备节点上了结果主节点恢复后强行抢回 VIP瞬间造成一次不必要的连接中断业务抖动反而更明显。为了解决这个问题Keepalived 提供了nopreempt非抢占模式。配置了这个选项之后即使主节点恢复了也不会主动抢回 VIP而是继续保持 Backup 身份直到下一次故障切换。要注意的是非抢占模式要求两台节点的优先级保持一致否则高优先级节点仍然会触发抢占配置就白做了。我在生产环境里的经验是如果是数据库、状态服务这类切换成本高的场景强烈建议使用非抢占模式把切换次数降到最低如果是无状态的 Web 服务抢占模式问题不大因为切换本身很轻量。关键还是想清楚你的业务更怕“多切换一次”还是更怕“主节点回来但没接管流量”。2.3 健康检查脚本Keepalived 的灵魂所在如果 Keepalived 只会检测对方机器宕没宕那它的价值会大打折扣。真正让 Keepalived 好用的是它的健康检查机制——定期执行你定义的检查脚本或检查命令检查失败了就降低本机优先级甚至直接把 Keepalived 停掉逼迫 VIP 漂移。我举个最典型的场景。你用 Nginx 做反向代理Nginx 进程卡死或者工作进程全挂了但操作系统本身还活着VRRP 报文照常发主节点看起来一切正常VIP 根本不会切走业务照样全挂。这就是典型的“机器活着服务死了”。没有健康检查的 Keepalived 是防不住这种故障的。Keepalived 提供了vrrp_script自定义检查脚本再加上track_script把脚本关联到实例上。脚本的退出状态码是核心返回 0 表示健康返回非 0 表示异常。常见的健康检查方式有pgrep -f nginx检查进程是否存在简单粗暴适合大多数场景。curl -I http://127.0.0.1/healthz检查 HTTP 接口是否能正常响应能更准确地反映业务可用性。mysqladmin ping -h127.0.0.1 -uroot -p***检查数据库主进程是否存活并接受连接。自定义复杂脚本比如检查最近一分钟的日志是否有某种致命错误。健康检查脚本里还有个细节值得注意脚本执行本身要快不要在里面 sleep 太长时间否则会拖慢整个检测周期脚本要加执行权限否则 Keepalived 会报权限错误脚本返回的退出码一定要写明确别让脚本因为某种意外路径走到最后一行返回 0那就等于白检测了。每一条都是我踩过的真实坑后面第 4 节我会展开细聊。2.4 脑裂双机热备最可怕的敌人脑裂Split-Brain这个词做高可用的人都应该刻在骨头上。它的意思很简单两台服务器都认为自己是 Master都持有 VIP都对外提供服务。为什么可怕举个例子。两台机器同时接管同一个数据库 VIP客户端请求被分发到两台机器上这台写了一个订单那台也写了一个订单两边数据不一致后面的数据就无法合并了整个业务逻辑直接崩掉。而且脑裂发生后通常意味着业务没有宕机而是以“半残废”的状态运行监控手段如果没检测 VIP 冲突你可能根本不会意识到出了大问题等发现时数据已经乱了。脑裂的原因无非这么几类两台服务器之间的组播不通VRRP 报文互相收不到彼此都认为对方死了于是各自抢占 VIP。防火墙策略拦住了 224.0.0.18 组播地址最常见的就是两台机器之间加装了防火墙规则。配置错误比如两台机器配置了相同的virtual_router_id但虚拟路由器编号冲突或者优先级配置颠倒了。交换机上的 IGMP Snooping 设置有问题组播报文被交换机丢弃。Keepalived 本身没有彻底解决脑裂的机制因为它只能感知通告无法感知对方的实际状态。所以在生产环境里我一般会搭配一条“双保险”思路除了依靠 VRRP 报文还要在业务层面做好幂等和冲突处理。比如数据库高可用要配合主从复制和读写分离应用层要做好唯一性约束。如果条件允许可以在两台机器上互相写一个检测脚本定时检查对端是否还在检测到异常就通过带外手段比如调用硬件管理口断电把对方隔离掉这就是业界常说的“STONITH 思想”。3. 实操配置全程一次完整的主备切换示例3.1 环境准备与安装先把环境说清楚我这次演示用的两台服务器配置如下节点操作系统IP 地址角色Node1CentOS 7.9192.168.1.101MasterNode2CentOS 7.9192.168.1.102BackupVIP-192.168.1.100虚拟 IP两台机器上都装了 Nginx业务场景就是通过 VIP 访问 Nginx正常情况下流量全部打向 Node1。Node1 挂了Node2 接替。安装 Keepalived 在 CentOS 上非常简单一条命令就搞定yum install -y keepalivedUbuntu 系统则用apt-get install -y keepalived装完之后先别急着配置先看版本keepalived -v我建议用 Keepalived 2.x 以上的版本1.x 和 2.x 在配置语法上有一些差异尤其是认证方式上老版本可能还需要配置 AH 认证2.x 默认用 PASS 认证。这里先不深究下文配置会直接用 2.x 的写法。3.2 主节点配置详解主节点的配置文件路径是/etc/keepalived/keepalived.conf。我故意把注释写全一点方便你们直接抄作业global_defs { router_id LVS_101 # 注意router_id 是当前节点的标识不是虚拟路由器的ID可以随意起 # 但建议和IP对应方便排查日志。 } vrrp_script chk_nginx { script /etc/keepalived/check_nginx.sh interval 2 weight -20 fall 2 rise 1 } vrrp_instance VI_1 { state MASTER interface ens33 virtual_router_id 51 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 123456 } virtual_ipaddress { 192.168.1.100/24 dev ens33 label ens33:0 } track_script { chk_nginx } }这段配置里的每个字段我都解释一下否则你就是配上了也不知道自己在干什么。state MASTER表示本节点初始状态为主节点。这个字段在 Keepalived 1.x 里是硬性指定角色2.x 里主要还是靠优先级但写上没坏处。interface ens33是 VIP 要绑定的物理网卡名必须和你机器上的实际网卡名一致。可以用ip a命令查。virtual_router_id 51这是关键同一组高可用的两台机器这个值必须一模一样否则它们认为自己在不同组不会互相监控。取值范围 1-255。priority 100主节点优先级备节点我会配 90差值不要太小建议 10 以上这样才能保证竞选时主节点稳赢。advert_int 1每秒发送一次 VRRP 通告。这个值不建议低于 1否则切换太快反而容易误判。authentication段是两台机器之间的密码认证两台必须一致。注意auth_pass最多支持 8 位超过 8 位会被截断我遇到过因为密码配了 10 位导致认证失败死活切不过去的坑。virtual_ipaddress里写的 192.168.1.100 就是需要漂移的虚拟 IP。track_script关联了健康检查脚本这是我能实现“Nginx 挂了自动切换”的关键。weight -20的含义是脚本检测失败时本机优先级减去 20从 100 变成 80低于备节点的 90于是备节点胜出VIP 漂移。这个设计比直接用weight 0更平滑因为脚本临时失败一次不会立刻把优先级打零而是先降权让它失去竞选优势。健康检查脚本/etc/keepalived/check_nginx.sh的内容我也一并给出#!/bin/bash # 检查 Nginx 进程是否存在存在返回0不存在返回1 if pgrep -f nginx: master /dev/null 21; then exit 0 else exit 1 fi写完脚本之后一定要记得加执行权限chmod x /etc/keepalived/check_nginx.sh如果你不想用进程判断也可以改成更精细的 HTTP 探测#!/bin/bash # 检查本机Nginx健康状态接口连续成功返回0失败返回1 curl -sf http://127.0.0.1/healthz /dev/null 21 exit $?用 HTTP 探测的好处是能检测到进程活着但业务响应异常的情况坏处是多一点系统开销而且依赖应用提供健康检查接口。3.3 备节点配置差异点备节点/etc/keepalived/keepalived.conf整体和主节点几乎一样只有少数几个字段不同。我把完整的备节点配置也贴出来方便对照global_defs { router_id LVS_102 } vrrp_script chk_nginx { script /etc/keepalived/check_nginx.sh interval 2 weight -20 fall 2 rise 1 } vrrp_instance VI_1 { state BACKUP interface ens33 virtual_router_id 51 priority 90 advert_int 1 authentication { auth_type PASS auth_pass 123456 } virtual_ipaddress { 192.168.1.100/24 dev ens33 label ens33:0 } track_script { chk_nginx } }对照主备两段配置你需要重点检查的对应关系如下配置项主节点备节点是否必须一致virtual_router_id5151必须一致auth_pass123456123456必须一致interfaceens33ens33各自机器对应即可priority10090必须不同主高备低stateMASTERBACKUP保持默认即可这里我再提醒一个很多人会忽略的点state BACKUP不代表它永远当备用只要主节点挂了它马上会提升为 MASTER。很多新手以为 BACKUP 就是“不干活”这是理解错了。BACKUP 在日常运行时确实不持有 VIP但它一直在监听组播、跑健康检查随时准备上位。3.4 启动服务与验证切换配置全部就位之后两台机器分别启动 Keepalivedsystemctl start keepalived systemctl enable keepalived启动完成后先在主节点上看 VIP 是否已经绑定ip addr show ens33正常情况下输出里会多出一行inet 192.168.1.100/24 scope global secondary ens33:0然后在备节点上看应该没有 VIP。接下来做切换测试这是双机热备配置完成后必须要做的验证步骤不要偷懒。测试一正常关闭主节点 Nginx。systemctl stop nginx等几秒健康检查周期 通告丢失周期再回到备节点查看ip addr show ens33如果看到 VIP 已经出现在备节点网上卡上说明健康检查触发的切换成功。接着测试原主节点恢复后的情况systemctl start nginx此时主节点上的 Keepalived 健康检查恢复通过优先级回升到 100如果没配置nopreemptVIP 会在几秒内被抢回。测试二直接重启主节点 Keepalived 服务。systemctl restart keepalived这个动作模拟 Keepalived 服务本身崩溃的情况VIP 应该同样切到备节点。如果这一步正常说明 Keepalived 守护进程的故障检测机制是通的。测试三彻底模拟宕机。poweroff这个测试在生产环境慎重做但测试环境一定要做一次。它模拟的是整台机器断电的极端场景备节点必须在 3-5 秒内把 VIP 抢过来恢复业务。如果这一步不做你永远不知道自己配的备节点是不是真的能扛住最坏情况。3.5 接入业务时的注意点应用千万别绑定死 IP配置层面的东西搞完了还有一个业务层面的坑必须要说如果你的应用配置了绑定固定 IP比如 Nginx 的listen 192.168.1.101:80或者 MySQL 的bind-address192.168.1.101那么即使 VIP 漂移到了备节点备节点的应用也不会监听 VIP 的端口因为应用根本没有监听那个 IP。所以双机热备不只是 Keepalived 配置的事还要求应用尽量监听0.0.0.0或者直接监听 VIP。如果应用非要绑定特定 IP最好的处理方式是让两台机器上的应用都绑定 VIP 这个地址因为 VIP 在哪台机器上哪台机器的应用就能正常接收流量。这个思路在做数据库自动切换时尤其重要绑定错误会导致 VIP 过去之后业务还是不通看起来像切换成功实际上服务直接瘫痪。我自己的习惯是Nginx、Tomcat、MySQL 这类服务的监听地址能写 0.0.0.0 就写 0.0.0.0然后把访问控制交给防火墙和网络安全组如果需要限制来源就通过防火墙规则来控制而不是把监听 IP 写死。4. 常见问题与排查技巧实录4.1 两台机器同时持有 VIP优先排查脑裂这是双机热备最严重后果也是最常见的问题。如果你发现ip addr看两台机器都绑定了同一个 VIP请按这个顺序排查第一检查两台机器之间的组播通信。在备节点上抓包tcpdump -i ens33 host 224.0.0.18正常的话应该能持续看到主节点发过来的 VRRP 报文。如果什么都看不到说明报文被中间链路丢掉了。再看防火墙iptables -L -n | grep 224.0.0.18CentOS 默认没有放行组播流量如果防火墙开着需要显式放行iptables -I INPUT -d 224.0.0.18 -p vrrp -j ACCEPT同时也要注意云厂商的安全组规则云主机的安全组如果不放行 VRRP 协议keepalived 在云上是跑不起来的。这也是为什么很多人说 keepalived 在传统物理机房好用、上云之后各种踩坑的原因。第二检查两台机器的virtual_router_id是否一致。不一致会导致它们各自认为自己独立成组互不通信于是各自抢占 VIP。第三检查优先级是否配置颠倒。如果备节点优先级比主节点高那从启动开始备节点就会抢走 VIP主节点反而成了摆设。4.2 VIP 不漂移或漂移很慢逐层排查通告丢失备节点一直拿不到 VIP最典型的症状就是主节点挂了业务却迟迟不切换到备节点。排查思路从近到远先在备节点上看 Keepalived 日志journalctl -u keepalived -f日志里通常会出现类似VRRP_Instance(VI_1) Entering MASTER STATE这样的关键字。如果根本没有进入 MASTER STATE说明备节点收不到主节点故障的信息问题大概率在网络层。再抓包看通告。前面说过tcpdump -i ens33 host 224.0.0.18如果抓不到主节点的报文但主节点明明还活着那就是组播链路问题。还有一种隐蔽的坑叫作“单播模式”。某些网络环境禁组播Keepalived 2.x 之后支持用unicast_peer配置单播对端地址把通告报文直接发给对端 IP 而不是组播。如果你的网络环境禁组播这个配置就是救命稻草vrrp_instance VI_1 { ... unicast_peer { 192.168.1.102 } }主节点配置里写备节点的 IP备节点配置里写主节点的 IP这样就能绕过组播限制。要注意的是单播模式下需要明确放行对端 IP 的 VRRP 协议流量。4.3 健康检查脚本失效别小看权限和退出码脚本不生效排查起来也有一套套路。先手动执行脚本bash /etc/keepalived/check_nginx.sh echo $?如果输出是 0说明脚本逻辑本身没问题。那就要检查 Keepalived 是否真的在调用它看日志journalctl -u keepalived | grep -i check日志里如果能看到类似VRRP_Script(chk_nginx) succeeded或failed的输出说明脚本被正常调用了。如果完全没有可能是脚本路径写错了或者vrrp_script的配置段没有合法地和vrrp_instance关联起来。还有最容易忽略的脚本文件没有可执行权限。Keepalived 调用脚本的方式是直接执行脚本文件不是用bash解释器去跑。所以chmod x这个操作千万别忘记。我在给客户排查时至少有两次都定位到这个问题配置看起来全对了但就是切换不了最后发现脚本没有执行权限。另一类问题是脚本里的命令依赖了特定环境变量比如用了pgrep但 PATH 环境不完整导致在 Keepalived 的调用环境下命令找不到。解决办法是脚本里尽量使用命令的绝对路径比如/usr/bin/pgrep、/usr/bin/curl别偷懒。4.4 切换后业务不通应用监听、ARP 缓存都要查VIP 漂移成功了但客户端访问还是不通。这个问题通常不在 Keepalived 本身而在两台机器和网络环境上。先查备节点上的服务是否在正常运行systemctl status nginx ss -lntp | grep 80如果服务没起来说明你只是把 VIP 切过去了应用自己还没准备好那当然不通。再查客户端所在机器的 ARP 缓存。VIP 从主节点漂移到备节点后交换机和客户端机器的 ARP 表里记录的还是旧 MAC 地址需要等 ARP 过期才能重新解析。Keepalived 在切换时会主动发送免费 ARPGratuitous ARP来强制刷新但有些交换机或者云网络环境对这个处理不友好导致切换后几十秒内业务还是不通。如果发现了这个问题可以考虑调相关网络参数比如在脚本里手动发一个免费 ARParping -I ens33 -c 3 -U 192.168.1.100把这个命令放进 Keepalived 的notify_master通知回调里当本机变成 Master 后自动执行。这个方法在物理机环境下解决了我的不少实际问题。4.5 常见问题速查表把上面说到的常见问题汇总成一张表方便你在现场直接对照故障现象可能原因排查命令/方法两台同时有 VIP组播不通、防火墙拦截、router_id 不一致tcpdump 抓 VRRP 报文iptables -L 查看主挂了备不切认证不匹配、virtual_router_id 不一致、优先级关系错误journalctl -u keepalived对比两台 confVIP 有但业务不通应用没监听 VIP、ARP 缓存未刷新ss -lntparping -U 强制刷新健康检查不触发脚本权限不够、脚本路径错、退出码不对手动执行脚本看退出码切换频繁抖动advert_int 太小、抢占模式误触发调大通告间隔考虑 nopreempt 模式密码认证失败auth_pass 超过 8 位被截断改成 8 位以内两边保持一致备节点日志无任何输出配置没生效、服务没启动systemctl status keepalived检查 conf 语法5. 再聊几句真实运维感受Keepalived 双机热备这个方案我前前后后用了七八年从物理机到虚拟机再到云主机踩的坑比配置示例里列出来的还要多一轮。但说实话它依然是我在 Linux 环境里做高可用的首选方案因为它的核心思想足够朴素——用虚拟 IP 掩盖单点故障用 VRRP 协议维护主备关系用健康检查脚本守护业务可用性。如果你现在正准备上手我的建议是把第 3 节的配置示例完整敲一遍把三种切换测试都跑通再接入真实业务。别嫌麻烦高可用这东西平时越懒故障时就越狼狈。尤其那个整机宕机的测试一定要做因为只有真正经历过一次切换过程你才会知道自己的方案到底靠不靠谱。最后分享一个小习惯我每配置完一套 Keepalived 环境都会把两个节点的配置文件备份一份带时间戳的副本同时把切换测试的结果记录在案。下次再出问题翻记录比翻记忆靠谱得多。运维的功夫大半都在这些不起眼的细节里。
返回列表