ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Keepalived双机热备实战:从VRRP原理到配置与故障排查

Keepalived双机热备实战:从VRRP原理到配置与故障排查 三更半夜被电话吵醒值班同事说VIP虚拟IP ping 不通了业务全部打不开了。这种场景干运维的多少都遇到过。如果提前上了 Keepalived 双机热备也就是用两台机器顶着同一个虚拟IP配合健康检查自动切换那这种情况下你大概率还能继续睡顶多早上起来看一眼切换日志。这篇文章就来聊聊 Keepalived 双机热备这套方案从选型思路、核心原理、配置细节到常见故障排查把能讲的实操经验都摊开说。这套方案适合谁主要是维护自建机房的运维工程师、刚接触 Linux 高可用的小白以及那些不想引入成套商用集群软件、想用轻量方案解决单点问题的团队。它能解决的问题很直接一台服务器挂了另一台能自动顶上业务不中断。下面进入正文。1. 双机热备的核心问题与 Keepalived 的选型思路1.1 为什么需要双机热备单机部署最怕什么不是配置不对不是代码有 bug而是硬件说坏就坏、系统说宕就宕。电源烧了、内存报错、机房掉电、内核 panic哪一样都不是你半夜能立刻赶到现场修好的。尤其是网关、负载均衡入口、数据库 VIP 这类关键节点一旦挂了整个业务链全断。双机热备的出发点很简单你一台机器扛不住我就上两台。一台主一台备平时主节点干活备节点待命主节点出问题备节点立刻顶上整个过程对外表现为一个漂移的虚拟IP客户端根本感知不到后端换了一台机器。这个思路在金融、电商、政企内网里被验证过无数次是最经典也最实用的高可用手段之一成本相对可控效果立竿见影。1.2 VRRP 协议是怎么一回事Keepalived 的真正底层基础是 VRRPVirtual Router Redundancy Protocol虚拟路由冗余协议。这个协议最初是网络设备上用的让一组路由器共享一个虚拟IP当主路由器挂了备用路由器能自动接管 IP保证网络不中断。Keepalived 把这个思路搬到了服务器上——多台 Linux 服务器组成一个虚拟路由器组对外统一提供一个 VIP谁优先级高谁就是 MASTER。协议的核心机制是报文竞选和心跳通告。每台运行 Keepalived 的机器都会周期性地向组内其他机器发送 VRRP 报文报文中携带优先级、虚拟IP等信息。MASTER 节点会持续发送通告报文告诉其他人“我还活着”BACKUP 节点收到报文后如果发现 MASTER 失联超过设定时间通常按 3 倍通告间隔计算就认为 MASTER 挂了立即切换自己为 MASTER完成 VIP 接管这个过程就是故障转移。打个生活化的比方一个工作群里有正组长和副组长正组长每个5分钟在群里发一条“我在干活”的消息。如果副组长连着15分钟没看到正组长说话他就自动升级成正组长负责对外对接。这个机制不依赖某个中心节点纯靠心跳来完成状态判断简单而可靠。1.3 为什么选 Keepalived 而不是其他方案市面上做高可用的方案不少heartbeat、corosyncPacemaker、LVS、Nginx Plus、商业集群软件等。Keepalived 能长期占据一席之地有几个原因。第一轻。Keepalived 是一个单一进程配置文件是简单的文本格式整个部署过程就是 yum 安装、写配置、启动三件事不像 Pacemaker 那样需要理解资源代理、约束、stonith 一堆概念。第二稳。VRRP 协议非常成熟报文简单网络开销极小一台机器上一秒还在跑业务下一秒协议栈自动完成切换不需要复杂的分布式一致性协议来协调出问题的概率低。第三配置直观。VIP、优先级、通告间隔、健康检查脚本全都靠几行配置就能定义清楚。比如你期望的业务切换阈值、主备切换的优先级都可以通过参数精准控制可调空间足够日常使用。当然它也有局限性。Keepalived 是“故障转移”方案不是“负载均衡”方案同一时刻只有一台机器在服务VIP备机平时基本是闲置的。如果追求两台机器同时分摊流量那需要组合 LVS 或 Nginx 等负载层产品。但单纯从“防止单点故障”这个诉求看Keepalived 双机热备的性价比确实是最高的。2. 核心配置概念与参数设计2.1 全局配置段运行身份与通知机制Keepalived 的配置文件默认路径是/etc/keepalived/keepalived.conf全文件分为几大段global_defs、vrrp_instance、vrrp_script、virtual_serverLVS 场景使用本文不展开。这里先从global_defs说起。global_defs { router_id LVS_DEVEL_01 enable_script_check script_user root }router_id只是本机在 VRRP 组内的标识通常写成主机名或业务名用于日志识别和抓包分析。enable_script_check和script_user是配合自定义健康检查脚本用的确保脚本以 root 身份运行并正确获取退出状态码。很多新手容易漏掉这两项结果健康检查脚本不生效VIP 一直没切换还以为是 Keepalived 的问题。如果条件允许推荐在global_defs里开启邮件通知或者 SNMP 告警这样切换发生时能第一时间收到消息。不过到了生产环境更常见的做法是让 Keepalived 切换时触发脚本由脚本统一调用企业微信、钉钉或者监控平台 API这样告警能和 CMDB 事件关联起来信息更完整。2.2 vrrp_instance定义一台虚拟路由器vrrp_instance是整份配置的核心任何一台参与双机热备的服务器都要定义这个容器并且相同业务的所有机器必须保证virtual_router_id一致。这个ID就是 VRID取值范围 0-255用来在网络上标识同一个虚拟路由器组属于同一个组的机器才能互相通信协商。这里给一份基础配置模板先用最简单的形态演示vrrp_instance VI_1 { state BACKUP interface eth0 virtual_router_id 51 priority 100 advert_int 1 nopreempt authentication { auth_type PASS auth_pass 123456 } virtual_ipaddress { 192.168.1.100/24 dev eth0 label eth0:1 } }解释几个关键设计考量。state参数虽然可以写 MASTER 或 BACKUP但在实际生产里我建议两台机器都写BACKUP让竞选完全由priority决定。为什么因为如果主节点配置为 MASTER一旦它因某种原因短暂网络隔离后又恢复大概率会立刻抢占 VIP取决于是否设置nopreempt这会造成可用性抖动。而两边都是 BACKUP 的情况下谁优先级高谁自然启动后先成为 MASTER后期即使它挂掉再恢复由于另一台已经胜出也不会轻易抢回来切换更平滑。advert_int是 VRRP 通告间隔单位秒。1 表示每 1 秒广播一次这是最常用的设置值。如果网段内广播包受控或链路状态不稳定可以适当调大一点比如 2 秒但注意失联判定时间会相应拉长切换耗时也变长了。反过来如果想做到秒级切换可以把advert_int调到 0.5 甚至更小但这时对网络稳定性要求高广播风暴和误判风险也随之上升。authentication段用于组内认证PASS是简单密码模式密码最长为 8 位。注意所有节点的密码必须一致否则 VRRP 报文会被丢弃两边都以为自己是 MASTER出现脑裂。2.3 优先级和解说抢占切换行为的关键控制点priority的范围是 104-254按 VRRP 规范255 保留实际上 Keepalived 允许继续向下设置但约定俗成按规范走。两台机器的优先级差建议控制在 10-50 之间比如备机 100、主机 110或者备机 90、主机 100。差值太小比如只差 1任何一台如果由于瞬时抖动导致优先级计算异常都可能引发不必要的来回切换差值太大比如主机 254、备机 100则备用机器永远没有机会在主机降级后通过手动抬高优先级来上位管理灵活性低。nopreempt这个参数值得单独拿出来说。它表示非抢占模式即使本机优先级比当前活动的 MASTER 高也不主动抢占 VIP。这在大规模集群里很有用因为强制抢占往往会造成连接中断、缓存失效尤其是在切回主机的场景下为了主备状态好看而牺牲业务稳定是不划算的。设置为nopreempt后切换只发生在当前 MASTER 故障时BACKUP 被动接管恢复后也不还回去直到下一次故障或人为干预。不过项目里如果追求“主备必须严格按预设角色运行”就不能开nopreempt需要允许抢占模式此时主机重启后会自动夺回 VIP。两种模式各有优劣生产上我主要看业务容忍度。3. 实操从零搭建一套双机热备3.1 环境准备与初始化演示环境假设有两台 CentOS 7.9 服务器配置如下项目主节点node1备节点node2主机名lb01lb02物理IP192.168.1.10192.168.1.11VIP192.168.1.100192.168.1.100子网掩码255.255.255.0255.255.255.0网关192.168.1.1192.168.1.1操作系统CentOS 7.9CentOS 7.9第一步是设置主机名和 hosts 解析保证两台节点之间能通过主机名互相访问避免将来扩展脚本时踩坑hostnamectl set-hostname lb01 hostnamectl set-hostname lb02cat /etc/hosts EOF 192.168.1.10 lb01 192.168.1.11 lb02 EOF第二步是关闭 SELinux 或设置为 permissive生产环境按公司安全基线来决定不要盲目禁用同时确保防火墙放行 VRRP 协议。如果使用 firewalld需要执行firewall-cmd --add-protocolvrrp --permanent firewall-cmd --reload很多双机热备起不来的原因是防火墙把 VRRP 多播包拦了双方收不到对方通告各自认为自己是 MASTERVIP 一启动就冲突。配置完之后用ping验证两台机器基础互通再做一次抓包确认 VRRP 报文能正常经过网络。3.2 安装 Keepalived 与最小配置两节点都执行yum install -y keepalived systemctl enable keepalived接下来配置主节点。假设业务入口服务是 Nginx监听 80 端口我们希望通过检测 Nginx 状态来决定是否切换 VIP。那么配置如下global_defs { router_id lb01 } vrrp_script check_nginx { script /usr/local/bin/check_nginx.sh interval 2 weight -20 fall 2 rise 1 } vrrp_instance VI_1 { state BACKUP interface eth0 virtual_router_id 51 priority 110 advert_int 1 nopreempt authentication { auth_type PASS auth_pass 123456 } track_script { check_nginx } virtual_ipaddress { 192.168.1.100/24 dev eth0 label eth0:1 } }对应的check_nginx.sh内容#!/bin/bash if pgrep -f nginx: master process /dev/null; then exit 0 else exit 1 fi这段脚本的逻辑很简单检查本机 Nginx 进程是否存在存在返回 0不存在返回 1。Keepalived 通过脚本退出状态码判断服务健康脚本返回非0时weight -20就会把当前节点的priority从 110 降到 90低于备节点的 100从而让 VIP 漂移到备节点。备节点配置类似只需修改router_id、priority为 100并注释或修改nopreempt策略如果整体要求主机恢复后抢回则备节点不要配置nopreempt如果追求平滑保持两边一致也行。脚本内容保持相同。3.3 启动验证与 VIP 漂移测试两台节点都启动服务systemctl restart keepalived ip addr show eth0正常情况下主节点eth0:1上应该出现 192.168.1.100备节点上没有。用ip addr和arp检查对照同时查看日志tail -f /var/log/messages日志里会看到Entering MASTER STATE、Entering BACKUP STATE的记录这些状态切换记录是排查问题最重要的线索。接着做故障模拟。在主节点上停掉 Nginxsystemctl stop nginx等待 2-3 秒脚本检查周期加通告时间执行ip addr应该看到主节点的 VIP 消失备节点的 VIP 出现。再启动主节点的 Nginx因为配置了nopreemptVIP 不会自动漂移回来除非备节点也故障。如果想立即回切可以考虑手动重启备节点的 Keepalived或者临时把备节点优先级调低后重启服务待 VIP 回主再恢复。4. 业务层健康检查与更复杂的实际场景4.1 从“进程存活”进化到“可用性检测”上面用pgrep检测 Nginx 进程这只是最基础的存活检测。如果 Nginx 进程还在但已经拒绝连接、worker 进程僵死或者后端上游全部不可用那么这种检测就失效了。更贴近业务的检测方案是本地主动发起请求用响应码判断服务是否可用。示例脚本升级#!/bin/bash curl -s -o /dev/null -w %{http_code} http://127.0.0.1/healthcheck if [ $? -eq 0 ] [ $(curl -s -o /dev/null -w %{http_code} http://127.0.0.1/healthcheck) 200 ]; then exit 0 else exit 1 fi这段脚本每 2 秒请求一次本地健康检查接口只有返回 200 才认为服务健康。它的意义在于不是“Nginx 还活着”就算健康而是“这个服务可用”才算健康。很多团队把这一步省了结果 Nginx 进程在但业务接口 500VIP 不切换用户全部报错比宕机还难受。如果业务是 TCP 协议比如 MySQL、Redis脚本写法类似用 nc 或者 timeout 3 bash -c 检查端口通断即可。4.2 多实例与多VIP的扩展玩法一个 Keepalived 进程可以管理多个vrrp_instance每个实例拥有独立的virtual_router_id和 VIP。这种机制非常实用比如你有两个业务入口分别需要一组主备但不想为每套业务单独部署两台 Keepalived 机器那就可以在一台机器上定义两个 instancevrrp_instance VI_BIZ1 { state BACKUP interface eth0 virtual_router_id 61 priority 100 advert_int 1 virtual_ipaddress { 192.168.2.100/24 dev eth0 label eth0:1 } } vrrp_instance VI_BIZ2 { state BACKUP interface eth0 virtual_router_id 62 priority 90 advert_int 1 virtual_ipaddress { 192.168.3.100/24 dev eth0 label eth0:2 } }同组的两台机器上的配置必须保持一致VRID、VIP、认证信息一致只有priority可以有差异。这样一套 Keepalived 就能承担多套业务的 VIP 托管。但注意CRITICAL 场景下不要在一个实例里塞太多VIP切换粒度太粗一个脚本失败可能导致所有VIP一起漂移影响面被放大。4.3 双主模式与单主模式的选型补充双机热备并不是只有“一主一备”这一种形态。如果你的业务入口是两个独立服务比如两个 Nginx 各自服务不同业务线那么可以做成双主模式。机器 A 为业务甲提供 VIP1 主节点同时为业务乙提供 VIP2 的备节点机器 B 则相反。这样两台机器都有活跃VIP都承载业务流量利用率翻倍同时任意一台挂了它承载的 VIP 会漂到另一台上。这是比较高级的用法配置上只需在每台机器上定义两个vrrp_instance指定不同的 VRID并让优先级一高一低交叉即可。这种布局特别适合网关双入口、消息队列双节点、缓存双副本这类场景既保证了高可用又避免备机长期空转的浪费。5. 常见问题与故障排查实录5.1 脑裂问题到底怎么防脑裂是所有双机热备方案都绕不开的坎。所谓脑裂就是两台机器都认为自己是 MASTER同时持有 VIP造成同一IP在同一网络中出现冲突报文发向哪边完全不可控业务表现时好时坏甚至整个网段 IP 冲突广播风暴。脑裂常见原因有三类VRRP 心跳被阻断、认证密码不一致、网卡或广域网链路单通。防范手段首先是网络层面保证两台节点二层互通VRRP 报文走多播必须确保交换机能正常转发组播包。其次是检查认证密码两台机器密码必须完全一致如果一台改了密码另一台没同步立刻脑裂。同时建议配套一个“仲裁脚本”。比如在检测脚本里增加一个对端连通性检查如果本机检测到对节点长时间不可达同时本机也没有接管 VIP就主动降级避免同时争抢。这个思路类似于数据库多主集群里的 quorum 机制核心原则是“不能确定自己是唯一活着的节点时宁可停止服务也不抢资源”。5.2 常见故障速查表故障现象可能原因排查步骤两台机器同时持有 VIPVRRP 报文被防火墙拦截检查 firewalld 是否放行 vrrp检查交换机广播域隔离策略VIP 不出现keepalived 未启动或配置语法错误systemctl status keepalivedkeepalived -t -f /etc/keepalived/keepalived.conf检查语法健康检查脚本不生效脚本权限不足或返回码不匹配手动执行脚本确认退出码检查是否缺少执行权限故障切换太慢advert_int 过大或脚本检查周期太长调小advert_int缩短脚本interval切换后业务不通另台机器没有配置 VIP 对应的 ARP 表更新确认 VIP 的label正确必要时调整 arp_ignore 和 arp_announce 内核参数日志出现Receive invalid ip number认证密码不一致对比两台机器的auth_pass确保完全一致5.3 抓包定位问题的办法排查 VRRP 问题最有效的工具是 tcpdump。在两台机器上分别执行tcpdump -i eth0 vrrp -n -vv正常状态下MASTER 每 1 秒发一条 VRRP 通告BACKUP 只在收到通告后回复或自己状态变化时发消息。如果一台机器上只看到发出通告而不见对方回复说明它认为自己就是 MASTER如果两台机器都在发通告说明已经脑裂了。抓包结果和ip addr输出一对照什么问题基本一目了然。另外建议开启 Keepalived 的详细日志级别在配置文件里加global_defs { ... log_level 6 }日志会细化到每一次通告收发极大方便排查启动阶段或切换阶段的异常行为。5.4 项目落地时容易忽略的几个坑第一台机器上配置了nopreempt另一台没有结果恢复正常后 VIP 漂不回去或者切回去后业务中断。两台机器的抢占策略必须一致这是配置同步的底线。第二VRRP 通告间隔和健康检查脚本的时间要错开。比如脚本每 2 秒检查一次通告间隔是 1 秒那么切换判定最差情况可能是 3 秒多切换耗时远超预期。推荐做法是脚本检查周期大于等于通告间隔且脚本执行本身不能阻塞不能有长时间 sleep 的环节。第三VIP 的网卡绑定。建议显式使用label eth0:1这样的形式绑定到物理网卡避免系统路由表混乱。如果不指定dev参数Keepalived 会默认找到第一块接口如果网卡名不是 eth0比如 ens160配置就会出问题。第四内核参数调整。在 VIP 所在节点上可能需要设置net.ipv4.ip_nonlocal_bind 1这个参数允许进程绑定到本机尚未持有的本地IP有些业务服务跟 VIP 绑定时需要提前加载否则服务会起不来。改完后执行sysctl -p验证生效。最后再交代几句我在生产环境里磕磕碰碰调试双机热备的时间不短最大的体会是Keepalived 本身只是一个协议实现真正的工程在于“你怎么定义健康”。把健康定义成“进程活着”还是“端口能连”还是“请求返回 200”决定了这个高可用方案在真实故障下能不能扛住事。很多团队把配置照抄一遍测试也做了但等到真正出事才发现检测脚本检测的不是用户能感知的那个健康状态导致备机接管后用户依旧访问不了等于白上。另外还要注意演练。双机热备不是部署完就一劳永逸的最好每个月做一次切换演练主动停主、主动断网、主动杀进程看备机是不是真的能顶上来。如果不敢演练等于没做高可用因为你根本不知道哪一天它会失灵。运维这行设备可以偶尔出问题但方案必须在关键时刻站得住。Keepalived 双机热备不是什么新鲜东西但把它用对用透已经能让绝大多数业务的单点风险大大降低。
返回列表