ARTICLE DETAIL

资讯详情

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

Keepalived双机热备实战:从VRRP原理到脑裂排查

Keepalived双机热备实战:从VRRP原理到脑裂排查 做运维这些年如果只让我挑一个必须掌握的HA方案我的答案大概率是Keepalived。它不算炫技但胜在朴实可靠两台机器、一条虚拟IPVIP、一套VRRP协议就能把单点故障这个最常见的心病治掉一大半。现在的企业环境里不管前面是Nginx、LVS、HAProxy还是数据库代理层Keepalived双机热备依然是很多人方案里的默认选项。这篇文章不打算讲成官方文档翻译稿就按我实际部署过的套路来把原理、配置、验证、踩坑一次说清楚。这个内容适合谁看刚接触高可用概念、被老板要求搞一下主备的运维新兵以及已经会配但被脑裂漂移不干净脚本导致疯狂切换折磨过的同行。看完你不需要再东拼西凑查资料照着下面的步骤能完整落地一套可用的双机热备并且知道出问题时往哪个方向查。1. Keepalived双机热备到底在解决什么问题1.1 先搞对概念VRRP解决的是路由冗余不是负载均衡很多人一听到Keepalived就在脑子里和负载均衡划等号这个误解得先纠正。Keepalived的项目背景确实和LVS关系密切最初它就是为了给LVS提供高可用能力而生的。但Keepalived的核心机制是VRRP全称Virtual Router Redundancy Protocol虚拟路由冗余协议。这个协议要解决的是当一台路由器挂了怎么让网络里的其他设备无感知地把流量交给备用路由器。你可以把VRRP想成小区门口的门禁岗。平时只有主岗保安登记访客备用保安在旁边看着主岗一旦下班或者出状况备用保安立刻站到同一个闸机前继续干活进门的住户根本不知道换过人。在VRRP里这个闸机就是虚拟IP而岗哨状态由优先级决定主备之间靠组播心跳报文维持默契。这跟负载均衡完全是两码事。负载均衡是把请求按策略分发到后端多台服务器每台都在干活双机热备是同一时间只有一台在处理VIP的流量另一台在冷备或者半热备状态容器里装着现成的服务配置等你一声令下就接管。所以Keepalived部署完以后你要是看到两台机器同时都绑定了VIP别高兴太早那不是负载均衡那是脑裂事故现场。1.2 VIP是怎么漂移的免费的ARP通告才是关键动作虚拟IP本质上并不是一个被分配的IP它更像一把挂在两台机器之间的钥匙。正常状态下钥匙插在主节点上对外表现就是主节点的网卡多了一个IP地址比如eth0:0上顶着192.168.10.100/24。备份节点上你是看不到这个IP的。当主节点出故障备份节点经过短暂的等待确认收到不到Master的心跳后就执行接管动作。所谓接管底层就两步把VIP地址加到自己网卡上然后全网发送免费ARPGratuitous ARP通告。这个免费ARP通告才是关键它相当于广播了一份门牌号变更声明以后发往192.168.10.100的帧去新MAC地址找。交换机收到这个通告会更新自己的MAC表同网段的客户端也会更新ARP缓存。这一套做完流量自然就切过来了。提示免费ARP不是可选项它是整个切换能对外生效的灵魂。很多切换后VIP明明过去了但业务不通的诡异问题最后查下来就是ARP没刷干净。后面我在坑位实战里会说怎么处理。1.3 Keepalived在这个体系里的位置一台VRRP状态机健康检查定时器的合体Keepalived不是只有一个VRRP协议实现它内部最核心的两个模块概念你要知道VRRP实例负责状态机运转健康检查框架负责决定要不要给你降权。再加上本地脚本通知机制就构成了一个完整的HA闭环。我们平时改的keepalived.conf工作逻辑其实是一个三层结构。最外层是全局配置中间层是VRRP实例每个实例里坐着优先级、认证、虚拟IP这些人设。每台节点把自己的人设广播出去谁优先级高谁当Master。但Keepalived不会傻到只看人设它会根据健康检查脚本的返回值动态调整优先级这叫track_script加权。比如脚本说Nginx进程挂了权重就减20分一旦分数跌破对手你就得乖乖让位。想通这个模型后面很多配置参数你就能自己推导了。2. 动手前先把架构定清楚主备、互备与脑裂2.1 单VIP主备最常见的双机热备形态最简单的拓扑两台机器一台叫lb01一台叫lb02共用一个VIP比如192.168.10.100。物理IP各自独立lb01是192.168.10.21lb02是192.168.10.22。同一套VIP在lb01上配置优先级150在lb02上配置优先级140。正常情况下打开ip addr看只有lb01网卡上飘着192.168.10.100。业务流量进来到VIP被接入层交换机转发到lb01的MAC地址。lb01上跑着的Nginx把请求转发给后端应用服务。等lb01宕机或者Nginx挂掉让脚本报了故障lb02在Master_Down_Timer计时结束后自动升级VIP漂到lb02上整个对外IP不变。这种形态的优点是架构简单、部署快、排障方便。缺点是备份机长期闲着硬件利用率不高而且如果主节点只是业务进程挂了而系统还在备份机接管之后不会自动把主节点的业务拉起来得等主节点修复后手动确认状态。2.2 双VIP互备让两台机器都别闲着如果机房资源紧张不想养一台纯备机可以做双VIP互备。这个思路是每个节点各带一个主VIP各自对外承接不同的服务或流量入口。比如lb01上跑服务A的VIP是192.168.10.100lb02上跑服务B的VIP是192.168.10.101。两台机器互为对方的BackupA的VIP主在lb01、备在lb02B的VIP主在lb02、备在lb01。这样做的效益很明显两个VIP各自的主备关系彼此独立一台挂了另一台短期要扛两套VIP的流量但只要容量规划时有冗余完全能顶住。配置上就是两个vrrp_instance各自指定不同的virtual_router_id和优先级。实际使用中这种架构在接入层代理和数据库代理上很常见。2.3 脑裂问题所有HA方案都绕不开的噩梦双机热备最怕的不是宕机是脑裂。脑裂的意思是主备之间的心跳通信断了但两台机器业务都正常于是各自都认为对方死了都把自己升为MasterVIP同时在两台机器上出现。此时交换机MAC表来回抖客户端请求一会儿发到旧机一会儿发到新机数据库双写、缓存不一致整个系统直接变成薛定谔的可用。VRRP之所以能尽量避免脑裂靠的是Master和Backup之间持续的心跳通告。Backup只要还能收到Master的组播报文就知道大哥还活着不会去抢。一旦心跳断了几秒Backup才启动接管。所以在设计双机热备时第一原则是让心跳路径尽可能可靠尽量用独立的物理网卡或管理网络不要让业务网卡和心跳网卡挤在一起避免业务流量打满就把心跳饿死了。但仅靠一条心跳链路仍然不能保证百分百不死锁。很多严格的生产环境会给Keepalived再加一层仲裁脚本比如检查脚本里额外ping网关或对端物理IP只有本机网络正常且对端也不可达时才允许升Master。说到底双机热备减少的是风险不是消灭风险。这个认知得先建立起来。2.4 选型建议你的场景到底需要哪种方案我给自己的项目定方案时一般按下面这个思路过滤如果后端是无状态服务比如Nginx代理层、LVS转发层优先用单VIP主备简单、好维护。会话保持问题交给后面的负载均衡层或引入一致性哈希。如果是有状态服务比如MySQL、Redis主从做Keepalived双机热备一定要想清楚数据同步延迟和脑裂后的数据一致性。别指望VIP漂移能解决数据丢失问题它只解决IP层面的可用性。如果机器资源够多、流量不大直接用双VIP互备把备机利用起来同时也降低了单机故障影响面。3. 完整落地从安装到验证一次跑通3.1 环境规划与基础准备我这里以两台CentOS 7.9虚拟机为例同一台虚拟机交换机、同一个网段内做演示。生产环境建议用独立网卡做心跳这里为了减少演示干扰就用同一块eth0承载VRRP和业务流量。角色主机名物理IPVIP系统Masterlb01192.168.10.21/24192.168.10.100/24CentOS 7.9Backuplb02192.168.10.22/24192.168.10.100/24CentOS 7.9两台机器都要先把主机名设置好然后把/etc/hosts里加入对端主机名解析避免后面日志里主机名乱跳。业务层用Nginx先起一个简单测试页面内容分别写成this is lb01 nginx和this is lb02 nginx这样切换后你能在浏览器直接看到效果。关闭NetworkManager对网卡管理的干扰或者至少保证它不会乱改你手动添加的VIP。这一步最容易忽略很多人配置都正确结果每重启一次VIP就被NetworkManager悄悄删了。3.2 安装Keepalived与主配置文件拆解CentOS上安装很简单yum install -y keepalived keepalived -v主配置文件在/etc/keepalived/keepalived.conf。安装好后默认是个空模板我们直接重写。先看Master节点的完整配置global_defs { router_id LVS_DEVEL enable_script_security } vrrp_script check_nginx { script /etc/keepalived/check_nginx.sh interval 2 weight -20 rise 2 fall 3 } vrrp_instance VI_1 { state MASTER interface eth0 virtual_router_id 51 priority 150 advert_int 1 authentication { auth_type PASS auth_pass 1234 } unicast_src_ip 192.168.10.21 unicast_peer { 192.168.10.22 } virtual_ipaddress { 192.168.10.100/24 dev eth0 label eth0:0 } track_script { check_nginx } notify_master /etc/keepalived/notify_master.sh notify_backup /etc/keepalived/notify_backup.sh notify_fault /etc/keepalived/notify_fault.sh }这里我特意用了单播模式unicast_src_ipunicast_peer。很多人默认习惯用组播但云环境和某些交换机默认就会过滤组播包导致VRRP心跳互相收不到、两台都成Master排查起来非常痛苦。单播把心跳改成了明确的点对点通信依赖面更小我实际项目中几乎全部用单播。Backup节点配置整体相同只需要改动这几个地方state改成BACKUPpriority改成140unicast_src_ip改成192.168.10.22unicast_peer里改成192.168.10.21路径和认证字符串完全一致。除此以外的virtual_router_id、auth_pass、virtual_ipaddress必须一模一样否则两台之间协议报文校验不通过根本搭不上伙伴关系。注意virtual_router_id是VRRP实例在同一个二层网络里的唯一标识范围0到255。如果机房里有多个Keepalived集群一定要规划好id分配比如A集群51、B集群52。碰撞的后果是两个集群互相抢VIP现象极其诡异。3.3 配置健康检查脚本这是双机热备的灵魂vrrp_script块是让Keepalived从纯网络层备用变成业务可用性备用的关键。它的意思很直白每2秒执行一次脚本脚本返回0表示健康返回非0表示故障。连续失败3次fall 3就给当前实例的优先级减去20分连续成功2次rise 2则恢复加分。脚本本身写在哪都行我这里统一放/etc/keepalived/check_nginx.sh#!/bin/bash # 检查Nginx master进程是否存在 if ! pgrep -f nginx: master process /dev/null; then systemctl start nginx sleep 2 if ! pgrep -f nginx: master process /dev/null; then exit 1 fi fi exit 0这个脚本的思路是先自救再自弃。Nginx没起来时先尝试拉起如果拉不起来才通知Keepalived降权。千万不要一检查到进程不在就直接exit 1那会把一次瞬时抖动放大成一次切换。脚本完成后记得加执行权限chmod x /etc/keepalived/check_nginx.sh为什么优先检查nginx: master process而不是笼统地pgrep nginx因为Nginx进程模型里有master和worker两类进程worker挂了master会自己拉起你检查到worker掉几个并不代表不可用。只看master进程最稳。同理如果你做MySQL或者Redis检查也是优先探活真正的服务监听端口不只看某个辅助进程。3.4 启动、验证与故障切换演练配置核对完以后启动Keepalivedsystemctl enable keepalived systemctl start keepalived等个几秒钟看VIP位置ip addr show eth0正常情况下你应该在lb01上看到inet 192.168.10.100/24 scope global eth0:0而lb02上没有。再看状态日志journalctl -u keepalived -flb01上日志应该是Transition to MASTER STATE然后Entering MASTER STATElb02上是Entering BACKUP STATE。验证阶段我一般按故障注入的等级从低到高来一遍停掉lb01上的Nginxsystemctl stop nginx观察lb02是不是在几秒内接管VIP。重新拉起lb01的Nginx观察是否切回取决于你配没配nopreempt默认抢占模式会切回。直接停掉Keepalivedsystemctl stop keepalived模拟整机异常。最后直接reboot模拟最彻底的主机宕机。每次切换后都要在客户端机器上反复ping VIP和curl VIP确认服务连续可用。抓包看切换过程可以这样tcpdump -i eth0 vrrp -nn你会看到Master周期发出的VRRP报文以及切换瞬间备份机发出的免费ARP广播。看到这个广播心里就踏实了。4. 切换过程中的关键细节与参数调优4.1 抢占还是非抢占nopreempt的取舍preempt是Keepalived的默认行为Master恢复后如果发现自己的优先级更高会立刻把VIP抢回来。这会带来一个实际问题——主备切换两次客户端连接要断两次。第一次是故障时切到Backup第二次是恢复时切回Master。很多业务对闪断很敏感更希望谁接了就继续扛着别来回折腾。这时在VRRP实例里加一行nopreempt加了以后即使原Master恢复只要它此刻不是Master就不会主动抢回VIP直到当前Master再次故障。需要注意一个配置怪癖如果启用nopreempt两台的state都建议写成BACKUP让优先级纯粹由priority决定。只在一台写MASTER、另一台写BACKUP时状态机初始化的判断逻辑在某些版本里会有偏差容易出恢复后谁也不当Master的尴尬局面。我的经验是对外的接入层服务默认就上nopreempt减少无谓抖动对追求主节点必须是固定那台的有特殊审计要求的场景保留抢占模式。4.2 通告间隔与故障检测时延的计算advert_int 1代表Master每1秒发一条VRRP通告。Backup多久才认定Master失联不是立刻而是等一个Master_Down_Timer计算公式是Master_Down_Timer 3 * advert_int (256 - priority) / 256拿priority 150代入大概就是3秒加0.41秒约3.4秒。也就是说即使Keepalived进程本身在网络层面发现不了Master了也要3秒多才酝酿切换。再加上健康检查脚本的周期和失败次数从进程故障到对外切换整体通常需要5秒上下。所以你们验收时如果看到切换耗时3到5秒别觉得是bug这是VRRP的正常设计。真要追求更快可以把advert_int降到0.2把interval调成1但代价是心跳报文变多广域网和弱网环境下反而可能误判一般不建议为了零点几秒去赌稳定性。4.3 多实例与双VIP互备的配置演化如果要用双VIP互备Master节点上就要定义两个vrrp_instance比如VI_A和VI_B。VI_A的virtual_router_id为51优先级150VIP是192.168.10.100这是本机当主VI_B的virtual_router_id为52优先级写140VIP是192.168.10.101这是本机当备。Backup节点完全反过来。这种配置看起来绕理清楚了其实不复杂每个实例都是一套独立的主备选举实例之间只共享物理网卡不共享状态。实际操作时我习惯把两份配置并排对比检查尤其是auth_pass、virtual_router_id、unicast_peer这几个字段手一抖就复制串了。5. 真实环境中的坑与排查实录5.1 ARP缓存导致切换后流量仍旧走到旧节点有次线上切换演练日志显示Backup已经Entering MASTER STATEVIP也在新节点上了但业务就是有一半请求超时。后来抓包发现问题不在Keepalived而在于接入交换机开启了动态ARP探测的某些私设参数FreeARP通告发了好几次它都不刷新MAC表把发往VIP的帧继续丢给已经宕机的旧主机的MAC地址。Keepalived本身有应对手段可以在实例里增加免费ARP发送策略garp_master_delay 5 garp_master_repeat 3意思是成为Master后延迟5秒发起免费ARP期间连续发送3条。延迟的意图是给网卡状态稳定留出时间避免接口刚UP就狂发通告反而被交换机忽略。真遇到交换机死性不改处理方式就是找网络组去改交换机的MAC学习策略。这个教训告诉我们双机热备不是纯服务器侧的事网络侧的配合验收也要纳入变更流程。5.2 防火墙拦截VRRP导致脑裂VRRP报文使用的不是TCP或UDP端口而是IP层协议号112。很多人配置防火墙时只放行了TCP端口比如放行80、443忘记放行协议号112结果两台Keepalived互相收不到心跳双双升MasterVIP出现在两台机器上。那场面极其惊悚。CentOS 7的Firewalld放行这样写firewall-cmd --permanent --add-protocolvrrp firewall-cmd --reloadiptables写法是这样iptables -I INPUT -p vrrp -j ACCEPTUbuntu的ufw写法是ufw allow proto vrrp排查的时候如果怀疑心跳不通最直接的手段还是抓包在Backup节点上跑tcpdump -i eth0 vrrp -nn如果什么包都看不到先怀疑组播被切或防火墙拦截再检查单播配置。5.3 健康检查脚本写不好比不写还坑脚本不是越复杂越好。我曾经接手过一个项目检查脚本里放了判断后端Tomcat存活、检查磁盘空间、检查VIP连通性的一堆逻辑结果某个凌晨磁盘IO抖动脚本执行超过5秒keepalived的检查线程被卡住硬生生触发了一次毫无必要的切换。这里有几条原则脚本执行时间要严格小于interval值最好在几百毫秒内退出。不要在脚本里做重量级网络探测非要检查端口就用超时控制的nc -z -w 2。脚本的退出码必须是确定的0或非0避免莫名其妙的二进制作怪。脚本里使用systemctl restart这种动作时要谨慎别每2秒检查一次就重启一次服务最后把服务重启死。5.4 virtual_router_id冲突多集群的隐形炸弹某天早上一上班监控就报警说两套不同的业务系统VIP频繁抖动。查了一圈两台机器在不同的网段本来八竿子打不着但它们的VRRP组播报文居然互相干扰。后来一查配置两个集群的virtual_router_id都用51。VRRP报文里靠这个ID区分实例两台在同一个广播域里就能互相收到对方的通告优先级高的反而把人家集群的VIP抢跑了。所以多集群环境里virtual_router_id必须做统一规划。我现在每个机房都建一张表谁家用哪个ID记清楚新项目部署前先查表领号。5.5 日志与状态机怎么快速确认当前谁是Master排障时很多人记不住几个常见日志。Keepalived的日志主要走journalctl -u keepalived或者/var/log/messages。出现最多的几个关键词Transition to MASTER STATE即将成为Master。Entering MASTER STATE正式成为Master。Entering BACKUP STATE降级为Backup。VRRP_Instance(VI_1) Received higher prio advert收到了优先级更高的通告说明有更强的节点在场。有个经验当你不确定当前谁是Master时别只在一台机器上看ip addr必须两台同时执行ip addr show eth0 | grep 100。只看一台容易得出VIP丢了的误判两台一对比就能看出到底是正常主备还是一方异常降级。6. 常见问题速查表症状可能原因排查手段解决方案两台机器同时有VIP业务时而通时而不通脑裂检查防火墙是否放行协议112两台都看ip addr放行vrrp协议检查unicast配置增加仲裁脚本VIP始终在一台故障后不切换健康检查未生效脚本没执行权限weight值不够手动执行检查脚本看返回查看track_script日志给脚本加执行权限检查weight计算差值切换后业务仍访问旧节点ARP缓存/交换机MAC未刷新抓包确认是否发出免费ARPping VIP解析MAC调整garp参数联系网络组清MAC或调整学习策略Keepalived启动后报配置语法错误配置少括号auth_pass长度超限制keepalived -t检查语法修正配置文件密码控制在8位以内两台机器收不到对端VRRP通告组播被交换机丢弃防火墙拦截单播地址写错tcpdump -i eth0 vrrp -nn改用单播模式放行防火墙vrrp协议主节点恢复后VIP不归位启用了nopreempt查看Keepalived配置如确需抢占去掉nopreempt说实话Keepalived双机热备这套东西配置本身一个小时就能写完真正决定方案成败的从来都是细节你愿不愿意把心跳路径单独规划好愿不愿意把健康检查脚本写得克制且收敛愿不愿意在切换后去盯着ARP和防火墙做一次全链路验证。我见过太多配置十分钟、救火一整天的例子都是栽在以为配好了就行的心态上。你在自己的环境里按上面的流程走一遍把这些细节都验过以后线上出问题才能心里有底。
返回列表