ARTICLE DETAIL

资讯详情

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

Keepalived高可用实战:从VRRP原理到主备切换与踩坑指南

Keepalived高可用实战:从VRRP原理到主备切换与踩坑指南 Keepalived这套工具我第一次在Linux服务器上安装配置时是给Nginx做VIP入口的。当时想法特别简单两台机器一个IP谁挂了另一个顶上。结果配置完启动之后两台节点完全感知不到对方查了大半天才发现是防火墙没放行VRRP协议。接下来我就把Keepalived在Linux环境下的安装、配置、启动整条链路写清楚附带这些年跌过的坑和常用的验证方法。不管你是要给Nginx、MySQL还是RabbitMQ做高可用Keepalived都是Linux上最经典、最轻量、最容易上手的一层方案值得花时间彻底搞明白。1. 高可用不是玄学Keepalived与VIP的核心机制1.1 单点故障问题的本质任何一台服务器、任何一个进程都有概率发生故障。硬件老化、系统崩溃、进程被杀、网络分区随便一个原因都可能让服务不可用。在Keepalived出现之前解决单点故障最朴素的想法是“多加一台机器”但加完机器后问题就来了客户端访问的IP只有一个怎么让请求自动切换到备用机器这时候虚拟IPVIP的概念就出来了——对外只暴露一个VIP这个VIP由主备节点中的一台持有主节点故障后VIP自动漂移到备用节点客户端完全无感知。Keepalived干的就是这件事把VIP的持有权做成一种可以被“选举、移交、接管”的资源。1.2 VRRP协议的核心工作过程Keepalived的底层协议是VRRPVirtual Router Redundancy Protocol这个协议最早是为路由器高可用设计的思路和我们现在讲的服务器高可用完全一致。每个参与高可用的节点会周期性地向同一个网段发送VRRP通告报文报文中包含优先级、virtual_router_id等信息。收到通告后每个节点会比较自己和对方的优先级优先级高的成为MASTER持有VIP优先级低的进入BACKUP状态只是不停监听MASTER的通告。当BACKUP连续一段时间默认是3倍advert_int没有收到MASTER的通告就会认为MASTER已经失联立即重新选举——如果它的优先级最高就把VIP接管过来。这个过程中有两点值得注意。第一state字段里写的MASTER或BACKUP并不是最终决定谁是主的唯一依据priority的数值才是。你写MASTER但priority写得比对方低照样会退让。所以我在配置时习惯把主节点priority设为100备节点设为90既保证主备稳定又留出足够差距避免因网络瞬断导致的反复横跳。第二VRRP默认采用组播方式发送通告目标地址是224.0.0.18。这意味着同一网段内所有的Keepalived节点理论上都能收到彼此的报文而这也带来了防火墙放行和virtual_router_id隔离这两个后续要重点处理的问题。1.3 从“机器活着”到“服务可用”Keepalived只做VRRP的话只能感知“对端机器是否在线”感知不到“本机Nginx进程是不是挂了”。因此有了vrrp_script健康检查机制定期执行一段脚本脚本返回0表示正常返回非0判定为故障。当脚本检测到业务进程异常时本节点会主动降低优先级、退出MASTER状态把VIP让给备用节点。这种设计把“高可用”从机器层面下沉到了服务层面也是我在实际配置中一定会加上的一环。没有健康检查的Keepalived只能算半个高可用。1.4 状态机与切换触发条件小结Keepalived节点通常会在Initialize、Backup、Master、Fault几个状态之间流转。启动时进入Initialize随后如果判断自己是MASTER就直接进入Master状态并开始发送VRRP通告否则进入Backup状态等待。Fault状态代表本节点出现异常比如配置错误、脚本检测失败、网卡故障此时不会持有VIP。梳理清楚这几个状态再看后面的日志时就会顺畅很多。日志里出现的Entering MASTER STATE、Entering BACKUP STATE、Entering FAULT STATE分别对应一次完整的状态切换过程。2. 从空白系统到Keepalived就绪安装全流程2.1 安装方式选型yum/apt优先还是源码编译Keepalived的安装方式主要有三种系统包管理器安装、源码编译安装、容器部署。我个人对生产环境的建议是能直接用yum或apt就用别一开始就上源码。原因很简单包管理器安装会自动处理好依赖、配置文件路径和systemd服务文件一条命令之后就能用后续升级也方便。源码编译的优势在于版本新、可定制参数但需要自己处理依赖和服务文件对新手不够友好。容器化部署Keepalived不是不能做但在“给物理机或云主机上的业务提供VIP漂移”这个场景下直接用宿主机进程的方式更简单也少一层网络映射的复杂性。2.2 yum/apt安装的具体操作在CentOS、RHEL系上安装Keepalived只需要一行yum install -y keepalived安装完成后二进制文件默认在/usr/sbin/keepalived配置文件自动生成在/etc/keepalived/keepalived.confsystemd服务文件也注册好了。Ubuntu/Debian系上对应的是apt update apt install -y keepalived安装完成后同样可以用systemctl管理。这里特别提一下很多同学喜欢“装完立刻启动”但Keepalived此时只有一个默认的空配置模板直接启动不会报错但也什么都干不了。正确顺序是先检查配置目录、确认二进制版本再动手改配置。2.3 源码编译安装的完整过程如果系统源里没有Keepalived或者你需要特定版本源码编译也不难但前置依赖一定要装齐。在CentOS系上至少需要这些包yum install -y gcc gcc-c make openssl-devel popt-devel libnl3-devel这些都是Keepalived编译时要用到的头文件和工具链。缺失libnl3-devel时configure阶段会报libnl headers not found这种情况不是Keepalived本身的问题而是依赖没补齐。Ubuntu系上对应apt install -y build-essential libssl-dev libpopt-dev libnl-3-dev libnl-genl-3-dev依赖装好之后进入源码目录./configure --prefix/usr/local/keepalived --sysconfdir/etc/keepalived make make install--sysconfdir/etc/keepalived这一步非常关键它把配置文件的默认路径固定到/etc/keepalived和后面systemd服务文件里ExecStart的默认配置路径保持一致。如果漏了默认配置路径会变成/usr/local/etc/keepalived启动时服务找不到配置文件排查又浪费一轮时间。2.4 安装后的验证与环境自检安装完成后用下面几条命令确认环境keepalived --version which keepalived ls -l /etc/keepalived/keepalived.conf systemctl status keepalived接着确认网卡名这一步直接决定后面interface参数怎么写ip link我看到太多人直接把网上教程的eth0抄进配置结果自己机器网卡是ens33VRRP通告根本发不出去。确认完网卡再在两个节点之间互相ping一下确认基础网络是通的。这几件事做完才算真正具备配置Keepalived的前提条件。3. 配置文件的正确打开方式主备节点的每项关键参数3.1 配置文件整体结构Keepalived的配置文件通常包含几个段global_defs是全局定义vrrp_script是健康检查脚本定义vrrp_instance是虚拟IP实例virtual_server是与LVS集成时的配置段。日常使用中最核心的是vrrp_script和vrrp_instance。一个配置可以同时包含多个vrrp_instance一台机器上跑多个实例就能实现“我是A组的主、B组的备”这种互备架构。这也是Keepalived比较灵活的地方高可用不一定是两台机器一主一闲资源可以互为备份。3.2 global_defs里的关键参数global_defs里最常用的就是router_id它是一个字符串标识建议两台节点设置成不同值比如主节点叫LVS_MASTER备节点叫LVS_BACKUP。虽然它不参与选举但会在日志里出现设置成有意义的名称后期排查多实例时能一眼看出是哪台机器。另一个值得了解的是enable_script_security如果健康检查脚本里会执行较复杂的命令加上这个参数并配合script_user指定用户可以限制脚本的执行权限。不过我的实际经验是健康检查脚本越简单越好尽量别在脚本里做复杂的逻辑否则脚本本身就会变成新的故障源。3.3 vrrp_instance逐参数拆解下面是一份最典型的主节点配置global_defs { router_id LVS_MASTER } vrrp_instance VI_1 { state MASTER interface eth0 virtual_router_id 51 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 1234 } virtual_ipaddress { 192.168.10.100/24 dev eth0 } }备份节点大部分参数相同只有state、router_id、priority不同。下面这张表可以直接对照着写参数主节点备份节点stateMASTERBACKUPpriority10090virtual_router_id5151interface实际网卡名实际网卡名authentication与主节点一致与主节点一致三个容易出问题的点第一interface必须写本机实际网卡名别照抄示例里的eth0。第二如果同一网段里部署了多套Keepalived集群virtual_router_id绝对不能重复否则会互相抢VIP。第三auth_pass官方限制最多8位建议就写8位以内的纯数字或字母别学网上某些教程写一长串否则可能因认证报文不符合预期导致节点之间无法正常协商。advert_int默认1秒表示每隔1秒发送一次VRRP通告建议保持默认。virtual_ipaddress里的VIP必须和业务网卡在同一网段否则外部访问不通。3.4 健康检查脚本与track_script联动健康检查是Keepalived真正体现业务感知的模块。假设要给Nginx做健康检查先写一个脚本#!/bin/bash if pgrep -x nginx /dev/null 21; then exit 0 else exit 1 fi给脚本加执行权限后在配置文件中定义vrrp_script check_nginx { script /etc/keepalived/check_nginx.sh interval 2 timeout 2 rise 2 fall 2 }然后在vrrp_instance里引用track_script { check_nginx }这里几个参数的实际含义需要说清楚interval是健康检查执行间隔秒数timeout是单次脚本执行超时时间超过就按失败处理rise表示连续成功多少次才把状态从故障恢复为正常fall表示连续失败多少次才判定故障。默认情况下rise和fall都是1但在网络或服务恢复场景下很容易出现“刚恢复就切换”的抖动现象所以我通常会把fall设成2甚至3避免一次偶发失败就造成VIP来回漂。脚本返回值0表示健康非0表示不健康这个约定是Keepalived判定状态的唯一依据。3.5 notify脚本让切换动作可感知、可追踪VIP漂移只是一层表象实际运维中我更关心切换发生之后系统做了什么。在vrrp_instance里配置三个notify参数notify_master /etc/keepalived/notify_master.sh notify_backup /etc/keepalived/notify_backup.sh notify_fault /etc/keepalived/notify_fault.sh三个脚本分别在节点变成MASTER、BACKUP、FAULT状态时被调用。最常见的用法是notify_master里reload业务进程、刷新ARP缓冲notify_backup里把机器上不属于自己的VIP清理干净notify_fault里调用告警接口做通知。脚本务必使用绝对路径加执行权限脚本内部如果有输出最好重定向到日志文件。我在notify_master脚本里通常会这样写#!/bin/bash echo $(date %F %T) [notify_master] /var/log/keepalived_notify.log systemctl reload nginx 2/dev/null || true这样既能确认切换逻辑触发又不会让script脚本的输出干扰Keepalived主进程的日志。4. 启动、验证与主备切换演练4.1 启动前先做配置语法检查改完配置后不要急着start先让Keepalived自检一下keepalived -t -f /etc/keepalived/keepalived.conf输出里出现语法正常之类的提示后再用systemctl启动。语法检查这一步看似多余实际上能帮你拦截一大半的“服务起不来”问题。配置文件的括号、分号、参数名只要有一处错误服务都可能直接失败而这类错误恰好是最让人头大的。4.2 启动的正确姿势与进程判断systemd下启动很简单systemctl start keepalived systemctl enable keepalived启动后我通常第一时间看两样东西进程是否完整、状态是否正常。ps -ef | grep keepalived systemctl status keepalived正常情况下ps能看到主进程加VRRP子进程如果配置了健康检查还会看到check子进程也就是三条记录。如果只有一条或者两条异常多半是子进程启动失败了这时马上看日志journalctl -u keepalived -f日志是Keepalived排错的第一手资料比到处猜强得多。看到Entering MASTER STATE就说明这台已经成为主节点VIP应该很快会出现在网卡上。4.3 VIP验证这几条命令最直接判断VIP是否生效不需要看管理界面命令行就够了ip addr show ip addr show dev eth0如果VIP已经配置成功能看到类似192.168.10.100/24 scope global eth0这样的地址。如果看不到按这个顺序排查interface参数写没写对防火墙有没有放行VRRP两台节点之间的网络通不通。协议层面可以用tcpdump验证tcpdump -ni eth0 vrrpMASTER节点应该每隔1秒就发一个VRRP通告包。如果你在BACKUP节点上也频繁抓到通告说明两台节点至少能从协议层发现对方问题大概率出在配置细节上。4.4 主备切换演练不能只在理论上说Keepalived配完必须做真实切换演练不然你永远不知道哪一步配置其实有问题。我的标准流程是在主节点执行systemctl stop keepalived模拟进程异常退出。到备用节点执行ip addr showVIP应该几秒内出现在备用节点网卡上。查看备用节点notify_master脚本日志确认切换通知触发。重新启动主节点Keepalived观察VIP是否按预期抢占回来。再一次执行ip addr show和日志检查确认主备状态恢复。演练时如果发现VIP没有切换先不要急着改配置而是按“网络是否通-防火墙是否放行-配置是否一致-日志是否报错”的顺序逐步排查。我见过最隐蔽的问题是两个节点的时间差太大导致日志和故障时序对不上排查时硬是绕了很久所以也建议大家配置NTP同步虽然VRRP本身不强依赖时间但日志对不上真的太痛苦了。5. 踩坑复盘从防火墙到云主机的常见翻车现场5.1 防火墙与SELinux占翻车案例的一半Keepalived部署后最容易翻车的地方就是防火墙。VRRP使用的协议号是112既不是TCP也不是UDP所以常规的放行80端口、443端口的规则对它不起作用。firewalld下可以这样放行firewall-cmd --permanent --add-rich-rulerule protocol valuevrrp accept firewall-cmd --reloadiptables下则是iptables -I INPUT -p vrrp -j ACCEPTSELinux也经常会成为隐性拦路虎。如果你发现配置完全正确但VRRP报文就是发不出去可以用setenforce 0临时验证一下确认是SELinux之后再考虑是否永久关闭或者调整对应的布尔值。这里补一句修改防火墙或SELinux之后建议把Keepalived服务重启一次让进程重新建立网络绑定否则可能出现规则已经放行了但连接还是不通的怪现象。5.2 网卡名不一致最常见的低级错误现代Linux发行版和云主机的网卡命名已经不一定是eth0了ens33、ens5、eth1都很常见。interface参数填错后Keepalived进程可能正常启动但完全监听不到正确的网卡导致VRRP通告发不出、收不到主备互不感知。我建议在配置前先在每个节点上执行ip link把真实的网卡名记下来两台节点各自填各自的interface不需要强求一致。比如主节点是ens33备节点是eth0只要各自填对VRRP照样能工作。5.3 virtual_router_id冲突跨集群的干扰virtual_router_id是0到255之间的整数它的作用是在同一网段内区分不同的VRRP虚拟路由器。同一个高可用集群的两台节点必须写同一个ID但不同集群之间绝对不能重复。如果同一网段里有两组Keepalived都用了ID 51这两组会互相干扰轻则日志怪异重则VIP被误抢。这个问题的隐蔽性在于日志里往往不会有明显的报错只有用tcpdump抓包后才能看到不同集群之间发送了相同virtual_router_id的VRRP报文。我的习惯是给每个集群规划独立的ID同时在配置文件里用注释写明这个ID属于哪套业务避免后续维护时撞车。5.4 脑裂高可用最怕的两个字脑裂是所有高可用方案的噩梦Keepalived也不例外。脑裂发生后两台节点同时认为自己是MASTER同时持有同一个VIP流量被打散到两台机器上如果后面连的是数据库后果不堪设想。判断脑裂的标准动作有两个第一在两台节点上分别执行ip addr show看VIP是否同时存在第二在两台节点上分别抓VRRP包看到底是谁在正常发通告。定位到脑裂后按顺序检查两台节点priority是否设置正确、防火墙是否放行了VRRP、interface是否填写正确、三层网络是否互通。脑裂的根源几乎都是“一个节点能正常发通告但另一个节点收不到”所以重点永远是排查通信链路而不是怀疑Keepalived本身。5.5 非抢占模式nopreempt写在哪很有讲究默认的Keepalived是抢占行为主节点恢复后会立刻把VIP抢回来。但有些业务场景不允许VIP频繁切换比如长连接服务一旦切换就要断连重连。这时需要配置非抢占模式。网上很多配置都写错了。注意nopreempt只能写在BACKUP节点的vrrp_instance里并且两个节点的state都要写BACKUP只靠priority区分主次。原因在于Keepalived只在BACKUP状态下才会处理nopreempt逻辑。如果你在MASTER节点上写nopreempt根本不会生效。还有一种更平滑的方案是preempt_delay主节点恢复后等待一段时间再抢占比如300秒给业务和网络一个稳定窗口期。5.6 健康检查脚本的隐性坑健康检查脚本看起来简单实际上坑不少。第一个坑是权限脚本没有执行权限Keepalived会直接判定脚本执行失败。第二个坑是环境变量比如脚本里用到某个软件的绝对路径但Keepalived的systemd环境里PATH和交互式shell不一致导致命令找不到。第三个坑是超时如果脚本执行时间超过了timeout配置会被直接判为失败。我的建议是脚本先用root手动执行一遍确认返回码正确脚本里所有命令用绝对路径脚本执行时间务必小于配置的timeout如果脚本在业务高峰期可能变慢就把timeout适当调大同时把fall阈值调大避免CPU抖动导致误判。5.7 云主机上的单播改造云环境是当前部署Keepalived的重要场景。传统物理机环境下VRRP用组播方式互发通告组播地址是224.0.0.18交换机默认会转发同网段组播。但许多公有云的VPC网络并不支持VRRP组播两台节点互相收不到报文结果都认为自己该当MASTER。解决办法是把Keepalived改成单播模式在vrrp_instance里写unicast_src_ip 192.168.10.10 unicast_peer { 192.168.10.11 }这样本节点只向指定的对端IP发送VRRP通告不再依赖组播。同时云平台安全组也要放行对应协议和端口。我在任何云主机上部署Keepalived时不管平台是否支持组播都会直接使用单播配置宁可多写两行也不给自己留隐患。6. 场景延伸Keepalived在Nginx、MySQL、RabbitMQ高可用中的接入方式6.1 Keepalived不具备业务感知感知逻辑都在脚本里搞清楚这一点你就能理解为什么Keepalived能接那么多不同场景。它自身只负责VRRP协议和VIP漂移而对业务进程是否正常的判断全部交给vrrp_script里的脚本。所以要想让Keepalived监控某种服务只需要写对应的检测脚本检测Nginx就检查nginx进程和80端口检测MySQL就检查mysqld进程和3306端口检测RabbitMQ就检查rabbitmq-server和5672端口。框架完全一样只需要改脚本内容。这也是Keepalived在Linux运维体系里长盛不衰的原因它足够底层、足够通用。6.2 Nginx高可用最标准的一套组合NginxKeepalived是目前最常见的组合做法也最简单。两台Nginx服务器各自启动Nginx监听自己的本机IPKeepalived提供VIP。客户端访问VIPVIP落在哪台机器上请求就打到哪台机器的Nginx。当MASTER的Nginx进程异常退出check脚本返回非0Keepalived主动让出VIPBACKUP接管VIP后通过notify_master里的脚本确保本机Nginx也在运行。这样整体对外提供的服务地址始终不变。需要提醒的是不要在notify_master里只做“切换VIP”这件事一定要确认业务进程本身可用否则就是VIP切过去了业务反而不可用这种“假高可用”我在生产上见过不止一次。6.3 MySQL和RabbitMQ等中间件的高可用思路很多接触Keepalived的人都是为了解决MySQL、RabbitMQ这类中间件的高可用问题。以MySQL主从场景为例正常情况下VIP挂在主库上应用连接串里写的是VIP主库故障后VIP漂移到从库应用不需要改配置。健康检查脚本要同时探测本机IP的3306端口和数据库进程状态避免只检测进程存活而端口已经不可用的情况。RabbitMQ类似脚本里检查5672端口或进程状态配合notify脚本做集群节点止损。但要直说Keepalived只解决了“入口漂移”解决不了中间件内部的数据同步、脑裂等问题。MySQL的数据一致性得靠半同步复制或额外的高可用编排工具RabbitMQ的镜像队列、仲裁队列也有自己的高可用机制。Keepalived适合作为最上层的接入入口别指望它包办一切。6.4 给生产环境的几条配置建议最后把这些年看到的问题汇总成几条生产建议第一双节点的Keepalived配置一定要放在版本控制里配置文件改动需要可回溯不然线上有一次手误改错了优先级就是一次隐蔽故障。第二VIP的地址要提前规划好不要用DHCP可能分配的地址否则IP冲突时候的故障极其难查。第三advert_int不要为了追求切换速度无限调小网络抖动会引起VIP反复漂移我一般保持默认1秒即可。第四每个节点的日志和notify日志要有独立文件并配置轮转Keepalived本身日志量不大但vrrp通告在故障期间会连续输出不轮转的话可能撑爆磁盘。第五高可用演练要定期做不要只在刚部署时做一次。Keepalived这套东西配置本身不复杂真正考验人的是故障发生时的判断力而这种判断力只能靠一次次真实演练积累出来。
返回列表