ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Keepalived双机热备实战:从VRRP原理到脑裂避坑指南

Keepalived双机热备实战:从VRRP原理到脑裂避坑指南 1. 方案选型搞懂需求再选工具别被双机热备四个字带偏Linux下的双机热备说白了就是两台机器对外呈现一台机器的假象一台挂了另一台立刻顶上业务方无感连接不中断。很多刚接触高可用的人第一反应是装个Keepalived不就行了但在生产环境里摸爬滚打几年后你会发现工具只是最后一步需求分析才是真正的分水岭。先聊聊双机热备最常见的三个应用场景以及它们对应的方案差异冷备Cold Standby备机平时不承担业务流量主备机之间只做状态同步。主挂了需要人工或脚本把VIP切过去业务中断时间以分钟计。这种模式适合非核心业务比如内部管理系统、报表平台停机几分钟无伤大雅。热备Hot Standby备机随时待命主备通过心跳机制互相监控主挂了备机在秒级甚至毫秒级内接管VIP和服务。这适合对外提供服务的场景比如Web服务、API网关、数据库中间件。注意热备并不等于双活备机不接流量只是随时准备接流量。双活Active-Active两台机器同时承担流量互为备份。这是更高阶的形态需要考虑会话同步、数据一致性、负载均衡通常需要业务层配合改造已经超出双机热备的范畴更接近分布式集群了。我见过太多人一上来就照着网上的教程配Keepalived结果业务是数据库数据文件在主备之间压根没同步主库一挂VIP是切过去了备库起来的却是一份残缺数据业务照样瘫。做双机热备之前先分清你保护的是服务进程还是业务数据。服务进程挂了好办Keepalived检测到nginx进程死了就切业务数据则要考虑磁盘同步、数据库主从复制、存储层双写这是完全不同的工程量。方案选型上目前Linux生态下主流就三条路方案核心机制优势劣势适合场景KeepalivedVRRP协议 自定义健康检查脚本轻量、稳定、配置简单几乎零学习成本只负责VIP漂移不管数据同步failover粒度依赖脚本Web、负载均衡、边缘网关Heartbeat心跳线 资源代理RA老牌方案资源管理能力比Keepalived强配置繁琐依赖corosync等组件社区活跃度下降传统业务老运维团队熟悉的场景Pacemaker Corosync分布式集群资源管理器支持多节点、复杂资源约束、跨数据中心学习曲线陡配置复杂杀鸡用牛刀数据库、虚拟化平台、需要强一致性约束的业务我给个个人建议90%的场景Keepalived就够了。如果你连Keepalived都没搞透别急着上Pacemaker轮询脚本WRR、VRRP优先级、单播配置这几个核心点足够覆盖绝大多数双机需求。真正需要Pacemaker的场景大概率还需要配套DRBD、多路径存储之类的技术栈那是另一个量级的话题。2. VRRP与VIP漂移双机热备的地基理解原理才能排查问题2.1 为什么VIP漂移能实现永不中断的错觉Keepalived的核心是VRRP协议Virtual Router Redundancy Protocol虚拟路由冗余协议。它的设计思路很巧妙把一组路由器在双机热备场景里就是两台Linux服务器组成一个虚拟路由器对外提供一个虚拟IPVIP客户端只认这个VIP不关心背后是哪台物理设备在处理。VRRP的工作原理可以简化成一句话多台设备抢一个老大身份老大活着就它说话老大不吭声了老二立刻顶上。两台服务器之间通过VRRP报文组播地址224.0.0.18协议号112互相通告状态报文中携带优先级Priority和状态信息。优先级高的成为Master负责持有VIP并提供服务优先级低的进入Backup状态默默监听Master的心跳报文。这里有个容易踩坑的点VRRP默认走组播但很多云环境、IDC网络会屏蔽组播。云服务器VPC内部通常不支持组播这种情况下必须改用单播模式。Keepalived的配置里设置unicast_peer参数明确指定对端IP地址。VIP漂移的实质是Master故障后Backup收到不到Master的VRRP报文等待一个advert_int默认1秒乘上master_hold_time通常1.5~3秒的延迟后主动升格为Master然后发送免费ARPGratuitous ARP广播告诉交换机这个VIP的MAC地址换人了。整个过程对客户端完全透明——客户端始终访问同一个IPTCP连接如果会话保持做得够好甚至不会断最多就是重发一两个包。这就是为什么很多人对双机热备的印象是主备切换就像网络抖动了一下。2.2 健康检查Keepalived怎么知道机器挂了默认配置下Keepalived只检测对端VRRP报文是否存活。也就是说只要内核的协议栈还活着VRRP报文就还在发即使nginx已经死透了、数据库连不上、磁盘满了Master依然以为自己活得好好的VIP也不切。这是默认配置最大的陷阱。所以生产环境必配健康检查脚本。Keepalived本身不做业务级检测它只负责执行脚本、看脚本返回值返回0表示健康继续保持Master返回非0则主动降级为BackupVIP漂移到对端。健康检查脚本的设计有几个原则第一检测必须覆盖真实业务路径。比如nginx机器不要只pgrep nginx要实际用 curl 拉一次本机服务端口。因为进程活着不代表服务可用可能是worker进程卡死、端口被占用、后端无响应。第二脚本本身不能太复杂。Keepalived调用脚本的间隔interval参数通常是2~3秒脚本执行时间长了或者内部写了复杂的循环会影响整个检测周期的稳定性。脚本里避免使用 grep -v grep 这类繁琐的命令简单直接最好。第三检测逻辑要能区分主机故障和服务故障。主机网卡断了、宕机了VRRP机制自己能感知但服务挂了、VIP还在Master上需要脚本转身把Keepalived干掉让备机接管。这两类故障的处置方式完全不同很多人只配了脚本却不理解它的定位出了问题全靠猜。举一个实用的nginx健康检查脚本示例#!/bin/bash # nginx健康检查同时检测进程存在和端口可访问 if ! pgrep -x nginx /dev/null; then # 尝试重启一次 systemctl restart nginx sleep 2 # 重启后还不行就宣告本机不健康 if ! pgrep -x nginx /dev/null; then exit 1 fi fi # 端口检测模拟一次HTTP请求超时5秒 if ! curl -s -o /dev/null -w %{http_code} --connect-timeout 3 --max-time 5 http://127.0.0.1/ | grep -q 200\|301\|302; then exit 1 fi exit 0注意这里给服务一次重启机会的思路很多脚本直接检测到进程没了就返回1把VIP切走但可能进程只是被OOM瞬间杀掉重启一下就能活。脚本里给它一次重启机会能有效降低无谓的切换频率。当然重启不能连试太多次否则就成了切也切不好、原地反复重启的捣糨糊状态。2.3 脑裂问题双机热备最大的坑两台服务器之间所有通信的基础是心跳链路。心跳断了两台机器同时认为对方挂了各自抢VIP结果网络中同时出现两台持有同一VIP的主机叫脑裂。脑裂的后果是灾难性的请求被两台机器随机处理数据状态可能各自独立数据库双写后数据文件直接不一致恢复的成本远远超过宕机本身。防止脑裂的方式业内通用的思路是增加第三路仲裁。最传统的做法是利用路由器、交换机或磁盘阵列上的一条独立心跳线即双心跳线冗余。更现代化的做法是引入仲裁节点比如在第三方机器上部署一个MySQL库或者Etcd两台机器同时写入我是Master的记录写入成功的那台才允许持有VIP。Keepalived本身不解决脑裂问题它只是个VRRP实现。如果你在真实生产环境建议做下面两件事双心跳链路交叉检测除了网线心跳再用串口或独立网段做第二路心跳在健康检查脚本里加对外ping网关的探测逻辑网关通了说明自己的网络链路没问题此时对端仍无应答才认为是自己网络异常主动放弃Master而不是抢占。脚本示例片段# 检测对端不可达时先检测本机网关是否可以ping通 if ! ping -c 3 -W 1 10.0.0.1 /dev/null; then # 本机到网关都不通说明可能是本机网络出了问题 exit 0 fi这个思路简单但极其有效本机网络都断了就别去抢Master了老老实实待着。3. Keepalived实战部署从零搭一套能用的双机热备3.1 环境准备与网络规划部署之前先把环境理清楚。我以两台CentOS 7/8/Stream机器为例Ubuntu也完全一样只是包管理器不同。假设规划如下Node A应用服务器MasterIP192.168.56.10Node B备用服务器BackupIP192.168.56.11VIP192.168.56.200对外提供服务两台机器之间用一条直连线或者独立网段做心跳传输可选VRRP组播本身就能做心跳但独立心跳更保险。我的建议是先用同一个网段验证通了再加独立心跳避免一开始就把问题复杂化。防火墙方面需要放行VRRP协议。iptables放行配置# 组播模式 iptables -I INPUT -p vrrp -j ACCEPT iptables -I INPUT -d 224.0.0.18 -j ACCEPT # 单播模式如果配置了unicast_peer需要放行指定IP的VRRP报文 iptables -I INPUT -s 192.168.56.11 -p vrrp -j ACCEPT iptables -I INPUT -s 192.168.56.10 -p vrrp -j ACCEPT顺带说一句云服务器默认安全组会拦截VRRP报文要在安全组规则里显式放行且很多云平台压根不让你用VRRP。这也是为什么云环境里高可用更倾向用负载均衡产品或者直接上K8s的NodePortIngress。3.2 安装与核心配置从能跑到跑好CentOS下的安装很简单yum install -y keepalived nginxUbuntu/Debianapt install -y keepalived nginx配置文件的默认位置是/etc/keepalived/keepalived.conf。我们先看Master节点的一份最小可用配置global_defs { router_id LVS_HA_MASTER enable_script_security } vrrp_instance VI_1 { state MASTER interface eth0 virtual_router_id 51 priority 150 advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 192.168.56.200/24 dev eth0 } track_script { chk_nginx } }Backup节点配置基本一样只有三个地方不同global_defs { router_id LVS_HA_BACKUP enable_script_security } vrrp_instance VI_1 { state BACKUP interface eth0 virtual_router_id 51 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 192.168.56.200/24 dev eth0 } track_script { chk_nginx } }几个关键参数的解读virtual_router_id两组Keepalived在一个网段内必须用不同的ID否则会互相干扰。可以理解成VRRP实例的身份证号同一个双机组的ID必须一致。priority优先级决定了谁当Master。数字越大优先级越高。注意日常维护时想手动切换主备可以临时调低Master的优先级让其自动让位比粗暴停Keepalived优雅得多。比如在Master上把priority临时改成90然后重启Keepalived让它主动降级成BackupVIP切到备机后再改回来。这个操作对业务的影响只是秒级闪断但远比直接杀进程可控。advert_intVRRP心跳间隔默认1秒。这个值关系到故障发现的速度。实测下来1秒是性能和网络开销的平衡点。调到0.5秒故障切换能更快但网络抖动概率也会增加调到3秒更省流量但中断时间会更长。生产环境建议1秒不要乱调。auth_passVRRP认证防止未授权设备加入虚拟路由器。注意它只是明文认证安全性极其有限不要当成真正意义上的安全防护。而且两台机器的认证密码必须一致否则VRRP报文会被丢弃。配置文件写好后分别启动服务systemctl enable keepalived systemctl restart keepalived启动后检查VIP是否生效ip addr show eth0正常情况下Master节点的eth0上会多出一个VIPBackup节点没有。可以用ip addr验证。为了便于看到切换过程拉长VIP状态检测的间隔然后手动停掉Master上的nginx试试实验演示这段实操值得自己跑一遍在Master上查看ip addr确认VIP存在手动停掉nginxsystemctl stop nginx等待脚本检测周期约2秒在Master上再查VIP你会发现VIP已经从Master的eth0上消失出现在Backup节点的eth0上重新在Master上启动nginx再过几秒VIP又切回来了。这个来回切换的过程就是Keepalived最核心的工作流。3.3 健康检查脚本与资源编排让切换真正可用默认的Keepalived只做VRRP层心跳不检测业务进程所以必须把检查脚本挂进来。我们在/etc/keepalived/check_nginx.sh写脚本内容就是前面贴过的进程端口双检测版本。在Keepalived配置的vrrp_instance里加track_script { chk_nginx }然后在配置文件顶部global_defs之后定义脚本vrrp_script chk_nginx { script /etc/keepalived/check_nginx.sh interval 2 timeout 3 rise 2 fall 2 }这几个参数值得好好琢磨rise连续成功N次才认为服务恢复了。默认1我建议设2避免服务刚重启起来还没完全就绪就被当作健康状态导致VIP切回来之后业务反而出错。fall连续失败N次才认为服务挂了。默认1我也建议设2。网络瞬间抖动导致一次失败就立刻切VIP很容易造成打乒乓反复切换。连续两次失败才切换能过滤掉大部分瞬时报错。timeout脚本执行超过这个时间会被Kill防止脚本卡死拖垮检测逻辑。这里有个重要的场景延展如果双机热备保护的不只是nginx还有PHP-FPM、Redis、MySQL等多个组件健康检查脚本里就要分别探测每个组件的端口。但注意判断粒度不要太死板比如MySQL在Master上挂了把VIP切过去备机的MySQL大概率也起不来因为数据不同步这时候反而要慎重不如让Master侧的脚本去尝试拉起MySQL实在拉不起来再切。这个先自救再切换的思路是我在数据库主从场景里踩过坑才总结出来的。3.4 故障切换实测验证方案是否真的可靠配置完成后一定要做故障演练。一套没有演练过的高可用方案等于没有高可用。演练的步骤我建议按以下顺序逐步加码第一步停服测试。停掉Master的nginx确认VIP切走、业务恢复。这是最基础的测试验证的是脚本生效。第二步主机存活测试。直接shutdown -h now把Master关机确认VIP切走、业务恢复。这一步验证的是VRRP心跳失效后能自动降级。第三步网络抖动测试。用tc命令在Master上模拟丢包和延迟# 模拟50%丢包 tc qdisc add dev eth0 root netem loss 50% # 清除模拟 tc qdisc del dev eth0 root观察Keepalived对网络抖动的反应会不会误切换。如果fall设成1大概率会出现误切。这也是我把fall调成2的实战验证。第四步切换时间测试。从Master故障到Backup接管VIP记录精确的时间。命令如下# 在Backup节点后台持续监测 while true; do ip addr show eth0 | grep 192.168.56.200 /dev/null echo $(date %H:%M:%S.%N) VIP on Backup break; sleep 0.1; done正常配置下advert_int1, fall2切换时间一般在3~5秒。如果超过10秒说明配置有优化空间优先检查心跳链路是否通畅、脚本执行是否耗时过长。4. 实际运维中高频踩坑点与排查路线4.1 VIP出现在两台机器上先看日志再想对策VIP同时出现在两台机器上的场景大概率是发生了脑裂。第一步不是急着抢修而是立刻检查两台机器的Keepalived日志tail -50 /var/log/messages | grep KeepalivedKeepalived的日志会记录状态切换的每一个细节Entering BACKUP STATE、Entering MASTER STATE、VRRP_Instance(VI_1) Dropping received VRRP packet...。如果看到 Dropping received VRRP packet说明收到了对端报文但认证或优先级配置有问题。脑裂的排查顺序两台机器的防火墙是否放行了VRRP用tcpdump -i eth0 vrrp抓包确认两端能不能互收VRRP报文确认virtual_router_id是否一致auth_pass是否一致确认心跳链路是否物理断开检查网线、交换机端口状态优先解决网络层问题后重启两台KeepalivedVIP会自动收敛回优先级高的那台。这里有个经验教训发现问题后不要同时在两台机器上重做VIP。先指定一台作为权威Master另一台停掉Keepalived然后手动ip addr add 192.168.56.200/24 dev eth0在权威Master上绑定VIP确保业务先恢复再逐步启动Backup。4.2 切过去了但业务还连不上排查链路的顺序VIP切换成功、业务还是连不上这类问题出现的概率不低。出现的原因是整个过程被很多人当作切了就完事忽略了业务侧依赖关系。排查顺着下面几步走第一步确认VIP绑定成功ip addr show看VIP的MAC地址是否已经挂到新机器的网卡上。第二步确认ARP缓存刷新在客户端机器上arp -n查看VIP对应的MAC地址。如果还是旧MAC手动清理ARP缓存ip neigh flush 192.168.56.200。这也是生产环境里最常见的一切配置都对但就是不通的原因——交换机或客户端缓存了旧MAC。第三步确认新机器上服务真的在监听ss -lntp | grep 80如果服务没起来查看服务的启动日志多半是服务依赖的后端连接串里写死了旧IP比如nginx的proxy_pass指向了192.168.56.10VIP切到11后11上的nginx还在代理到10而10已经挂了当然不通。很多配置文件在双机场景下要做本机访问优先即proxy_pass写http://127.0.0.1:8000而不是写对端IP。4.3 重启Master后VIP不切回来别慌这是正常现象双机热备默认配置下Master恢复后会自动抢占VIP因为priority更高。但在生产上这不一定是好事。比如Master起来后发现它的数据比Backup落后数据库主从延迟这时候把流量切回去业务反而出问题。所以高级一点的方案是关闭nopreempt让VIP在主备切换后不自动回切由运维人员决定什么时候手动回切。配置方法是在vrrp_instance里加上nopreempt加上 nopreempt 后即使Master恢复它也不会去抢VIP。运维在确认数据追平、服务健康后手动执行systemctl restart keepalived或临时调高优先级才能切回。这个设计思路适用于数据同步要求高的场景。自动回切听起来智能但实际运维中手动可控才是最大的安全感。静默回切导致的数据事故我见过不止一起。5. 延伸思考双机热备的边界以及下一步该走向哪里双机热备解决的问题始终是单点故障这一个点。它不解决性能瓶颈、不解决数据多活、不解决灰度发布。当你发现业务规模上来后双机热备的备机资源闲置和还在闪断秒级这两个问题会越来越刺眼。我的经验是双机热备是入门高可用的最好切入点但不是终点。如果你的业务真的需要底层基础设施具备标准意义上的故障自愈能力最终还是要往多节点集群和容器编排方向走。Kubernetes的Deployment天然支持多副本配好探针后节点挂了Pod自动迁移比Keepalived的体验好得多。但K8s也不是万能的它引入了etcd、CNI、存储编排等一整层复杂度运维门槛比双机热备高一个数量级。所以不要盲目追新。你的业务每天几十万PV一台2核4G的机器就能扛住那就做好双机热备就够了如果业务已经跑在十几台机器上还在纠结Keepalived怎么调优那方向就错了。最后分享一个我自己的习惯只要你做了双机热备不管用什么方案一定要每月至少做一次切换演练并且把演练做成文档化流程。很多人的Keepalived配好之后半年都没切过一次真到出故障那天手忙脚乱忘了密码、忘了VIP网段、忘了回切流程三小时才恢复业务。而演练过的团队三分钟就能完成接管。这个差距不是工具带来的是运维意识带来的。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进