LVS+Keepalived高可用集群搭建与排障实战 这套组合我已经搭过不下十回了——Web服务集群里LVSKeepalived像是那种你平时想不起、一出事就靠得住的老伙计。很多新项目一上来就买云负载均衡省事是省事但如果你自己维护过几套业务就知道自建四层高可用集群有多重要转发性能高、故障秒级切换、后端节点动态摘除这三个能力正好命中Web服务集群最核心的需求。这篇文章我把从选型、概念、配置到排障的完整过程写下来适合正在做运维、或者准备入门负载均衡高可用的同学直接参考。先给一个总览LVSLinux Virtual Server负责把流量按调度算法分发给后面的真实服务器Keepalived负责两件事——用VRRP协议让VIP虚拟IP在主备之间漂移以及定期探测后端节点健康状态。两者配合就得到了一套既抗单点、又能自动剔除故障节点的Web服务集群。下面我按实际落地的顺序从头讲。1. 为什么还在用LVSKeepalived——选型背后的现实考量1.1 四层转发和七层代理的本质区别很多人最开始接触负载均衡是用Nginx我自己也是。Nginx做七层代理时要完整解析HTTP头部、维护客户端连接、还要考虑upstream连接复用逻辑很重。一台Nginx在纯转发场景下能扛的并发确实不低但一旦请求体很大、长连接多、或者SSL卸载集中到一台机器上CPU很容易被打到红线。LVS不一样它工作在Linux内核态本质上是修改数据包的目的MAC或IP然后按调度算法把包发到后端。它不关心HTTP协议内容也不维护客户端和服务端之间的业务连接状态除非你开持久性所以单机转发能力高出Nginx一个量级。拿我负责过的一个接口网关项目来说高峰期每秒请求量在两万左右之前Nginx集群三台还经常CPU告警换LVS后两台LVS节点CPU长期在15%上下后端RS的压力反而成了瓶颈。还有一点容易被忽略LVS不只是为HTTP服务理论上你只要定义了端口和协议TCP/UDP服务都可以做四层分发Redis、MySQL读写入口、RPC框架都能挂在这套集群后面。这是七层代理很难替代的通用性。1.2 单点变高可用Keepalived补上的关键一环LVS本身只是内核里的转发规则它不负责“高可用”。如果你只在一台机器上配ipvsadm调度器宕机整个集群立刻瘫痪这跟没有负载均衡没什么区别。Keepalived在这里补的正是两件事通过VRRP协议在多个LVS节点间漂移VIP主节点挂了备节点自动接管通过健康检查探测后端真实服务器发现某个RS异常自动从转发规则里摘掉服务恢复后再加回来。用生活化的类比LVS是前台总机负责把来电转给不同工位Keepalived是前台主管总机坏了马上有人顶替哪个工位没人接电话立刻停止往那边转。可能你会问既然云厂商都有负载均衡产品为什么还要自建几个现实原因一是成本长期运行的固定业务自建两台通用服务器比按流量付费划算很多二是可控性你可以完全掌握调度算法、会话保持时间、健康检查细节三是学习价值理解这套原理后再去看云负载均衡的文档很多参数一眼就能看懂。当然如果你只有一两个轻量服务、不想维护服务器直接用云产品没毛病工具选择永远看场景。2. 核心概念LVS工作模式与集群规划2.1 三种工作模式NAT / DR / TUN配置LVS之前必须先搞清楚三种工作模式否则后面出了问题根本想不明白为什么。NAT模式客户端访问VIPLVS把目标地址改成后端RS的IP响应包再经过LVS改回源地址返回客户端。优点是后端随便私网IP就行缺点是进出流量都要过调度器流量一大调度器就是瓶颈。DR模式Direct Routing客户端访问VIPLVS只修改数据帧的目标MAC地址把请求转发给后端的某台RS后端RS收到包后发现目标IP是VIP而这个VIP同时配置在RS的lo接口上于是RS认为自己就是目标服务器直接回应客户端。响应包不经过LVS这就是DR模式性能高的根本原因。代价是LVS和RS必须在同一个二层网络内并且要在RS上做ARP抑制避免多台机器同时响应VIP的ARP请求。TUN模式通过IP隧道把请求封装后发给后端可以跨网段部署但封装/解封装开销大实际运维中配置复杂除了个别跨机房场景我很少见人用。生产环境我基本都是DR模式。原因很直接性能最好、配置相对简单、只要注意ARP参数和回环接口就能跑得很稳。2.2 一套可落地的IP规划与VIP设计假设我们部署一个典型的Web服务集群后端是Nginx提供静态和API服务。IP规划如下模拟生产环境内网地址角色IP地址说明VIP192.168.1.100对外提供服务的虚拟IPLVS主节点192.168.1.20Keepalived状态为MASTERLVS备节点192.168.1.21Keepalived状态为BACKUPRS1192.168.1.11Nginx节点权重2RS2192.168.1.12Nginx节点权重1RS3192.168.1.13Nginx节点权重1规划时有几个点要特别留意。VIP不能和任何物理机IP重复也不建议和DHCP分配池混在一起最好在网管系统里预留出来。客户端访问的入口如果是内网VIP用内网地址如果业务对公网开放前面一般还有防火墙做DNAT把公网IP映射到192.168.1.100。另一件重要的事RS节点上的VIP必须用32位掩码配置在lo接口比如192.168.1.100/32 dev lo而不是和物理网卡放在同一个网段否则RS往VIP的访问会产生奇怪路由。还要注意RS的默认网关必须指向物理网段的真实网关绝对不能指向VIP或LVS节点否则回包路由会失败。2.3 DR模式下两个关键ARP参数这是DR模式的核心难点我单独拿出来讲。默认情况下如果VIP配置在RS的lo接口上当网络上有人问“谁是192.168.1.100”时LVS主节点和所有RS都会回答“我是”这样客户端ARP缓存里存的可能是任意一台机器的MAC流量就乱了。解决办法是让RS“不响应VIP的ARP请求、也不主动宣告VIP”。需要设置两个内核参数arp_ignore 1只回答目标IP是本接口IP的ARP请求。RS的物理网卡IP不是VIP所以不会响应VIP的ARP请求arp_announce 2发送ARP通告时尽量使用目标IP相同接口的地址作为源地址避免从lo接口发出VIP的ARP。很多老教程只设置了net.ipv4.conf.all没有设置net.ipv4.conf.lo结果RS还是会泄露VIP的ARP。我在生产上一般把all和lo都设置一遍保证万无一失。下面这组配置是标准做法直接放进/etc/sysctl.confnet.ipv4.conf.all.arp_ignore 1 net.ipv4.conf.all.arp_announce 2 net.ipv4.conf.lo.arp_ignore 1 net.ipv4.conf.lo.arp_announce 2 net.ipv4.conf.eth0.arp_ignore 1 net.ipv4.conf.eth0.arp_announce 2设置后执行sysctl -p生效注意部分内核参数写进all之后具体网卡接口也需要确认生效值可以用sysctl -a | grep arp_检查。3. 手把手搭建LVSKeepalived高可用集群3.1 环境准备与系统初始化我用的是Rocky Linux 9本质上和CentOS 7/8没有区别Ubuntu也能用这套方法只是安装命令换成apt。先把必要的软件装上两台LVS节点都需要yum install -y keepalived ipvsadm systemctl enable keepalived接下来是系统层面几个容易踩坑的点。如果你装了firewalld需要放行VRRP组播流量或者干脆在测试环境先停掉systemctl stop firewalld systemctl disable firewalldVRRP默认使用的组播地址是224.0.0.18协议号是112如果公司网络有防火墙策略要在交换机或主机防火墙里放行。SELinux如果处于enforcing状态keepalived绑定VIP会受限测试环境我建议先setenforce 0生产环境则要写对应放行策略不要直接关。后端RS只需要有Web服务不需要装keepalived和ipvsadm。RS上要确保Nginx监听80端口并且有健康检查用的路径比如/healthz这是个很重要的细节。3.2 主节点Keepalived配置详解主节点/etc/keepalived/keepalived.conf默认没有需要自己创建。我直接贴一份完整可用的配置再做逐段说明global_defs { router_id LVS_MASTER vrrp_skip_check_adv_addr vrrp_garp_interval 1 vrrp_gna_interval 1 } vrrp_instance VI_1 { state MASTER interface eth0 virtual_router_id 51 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 192.168.1.100/24 dev eth0 } } virtual_server 192.168.1.100 80 { delay_loop 6 lb_algo wrr lb_kind DR persistence_timeout 60 protocol TCP real_server 192.168.1.11 80 { weight 2 TCP_CHECK { connect_timeout 3 connect_port 80 } } real_server 192.168.1.12 80 { weight 1 TCP_CHECK { connect_timeout 3 connect_port 80 } } real_server 192.168.1.13 80 { weight 1 TCP_CHECK { connect_timeout 3 connect_port 80 } } }先看global_defsrouter_id只是一个标识主备可以不同影响不大但virtual_router_id在主备之间必须完全一致它是VRRP报文里区分实例的关键值。很多脑裂问题就是两台机器这个ID不一致导致的。priority决定了谁是主主节点写100备节点写90。advert_int 1表示每隔1秒发一次VRRP通告这是我们评估切换时间的重要依据。Keepalived默认在连续3个通告周期没收到master通告后备用节点才会升级所以切换时间大概是3秒左右。如果你希望更快可以把advert_int改成0.5秒但这样组播包更频繁对网络稳定性要求也更高我实际用下来1秒比较稳。virtual_server段是LVS转发规则的定义注意它不属于vrrp_instance而是keepalived的另一个模块。Keepalived启动后会自动调用ipvsadm把这些规则加载到内核里。lb_kind DR就是选DR模式lb_algo wrr表示加权轮询。persistence_timeout 60的意思是来自同一个客户端IP的连接在60秒内尽量转发到同一台RS这个可以视业务决定开不开。如果是短请求且后端无状态可以设为0如果有登录态且后端没有共享Session建议按照业务会话长度来设置比如900。还需要解释为什么备节点也要配置完整的virtual_server段因为备节点平时只是“待命”但一旦主节点故障备节点成为MASTER后必须立刻有转发规则可用。如果配置里没有这些real_serverVIP飘过去也只是一个空壳IP无法分发流量。这是很多人会漏掉的地方。3.3 后端真实服务器RS配置在每台RS上执行ip addr add 192.168.1.100/32 dev lo同时把VIP写进开机自启。最简单的方式是放到/etc/rc.local记得给执行权限更规范的做法是写一个systemd service。生产上我更推荐systemd因为能依赖网络就绪后再执行[Unit] DescriptionVIP on lo Afternetwork-online.target [Service] Typeoneshot ExecStart/usr/sbin/ip addr add 192.168.1.100/32 dev lo ExecStop/usr/sbin/ip addr del 192.168.1.100/32 dev lo RemainAfterExityes [Install] WantedBymulti-user.target然后设置前文说的ARP抑制参数sysctl -p生效。再确认Nginx监听的是80端口。这里有个很容易搞混的地方RS的Nginx配置里server_name和listen不需要改成VIP保持原来的配置即可因为请求到达RS时目标IP已经是VIPNginx拿到的Host头是客户端请求里的域名不做特殊处理也能正常回包。RS上如果还有iptables规则留意不要阻断来自LVS节点的请求。我见过一个案例RS上默认DROP策略只放行了某个网段结果漏了LVS节点所在网段VIP访问时好时坏。3.4 启动验证与流量观察两台LVS节点都启动keepalivedsystemctl start keepalived然后先确认VIP在哪台节点上ip addr show dev eth0正常情况下VIP只出现在主节点。接着看LVS规则ipvsadm -Ln输出里应该有VIP和三个real_server状态为Available权重正确。如果ipvsadm -Ln里没有规则说明keepalived配置文件有问题看日志排查。如果real_server后面显示的不是Available而是类似“no route”或“down”就要从健康检查入手查。然后从客户端用VIP访问curl -s http://192.168.1.100/healthz多试几次配合下面的命令观察连接分布watch -n1 ipvsadm -Ln --stats--stats会显示每个RS累计转发的包数和字节数从数字增长能看出流量是否均匀。为了验证高可用我在主节点上执行systemctl stop keepalived同时客户端用一个循环脚本持续发请求while true; do curl -s -o /dev/null -w %{http_code} %{remote_addr}\n http://192.168.1.100/; sleep 1; done大约3秒后VIP会漂移到备节点请求不中断或只中断一两个这就是预期结果。回切也值得测一次重新启动主节点的keepalivedVIP应该在几十秒内自动回到优先级更高的MASTER节点上。4. 健康检查、故障切换与脑裂问题4.1 健康检查机制从TCP_CHECK到HTTP_GET前面配置里用的是TCP_CHECK它只探测TCP端口通不通。优点是轻量、不消耗太多资源缺点是不够真实——Nginx进程还活着但业务线程卡死TCP端口照样能连上这时候Keepalived认为节点正常流量还会打过去客户端就踩到502或超时。更可靠的做法是用HTTP_GET检查一个真实的健康接口比如/healthz。配置改成这样real_server 192.168.1.11 80 { weight 2 HTTP_GET { url { path /healthz status_code 200 } connect_timeout 3 nb_get_retry 3 delay_before_retry 2 } }Keepalived每delay_loop秒我设的6秒会向后端发起一次HTTP请求只有返回200才认为节点健康。如果后端应用接口返回500Keepalived会在连续重试3次后把节点摘掉再每隔2秒继续探测直到恢复后自动加回。还有一种更灵活的MISC_CHECK可以执行自定义脚本来判断节点健康。比如脚本里可以检查磁盘、内存、应用层队列长度适合复杂场景。自定义脚本要注意执行权限、超时时间、返回码——返回0表示健康非0表示异常。我建议生产环境优先把健康检查做到应用本身再配合HTTP_GET这样最直观也最好排查。4.2 VRRP主备切换与双主模型Keepalived的VRRP状态只有三种MASTER、BACKUP、FAULT。MASTER定期发组播通告BACKUP收到后刷新计时器一旦超过阈值时间没收到通告BACKUP就通过选举升级为MASTER。所以我们看到的3秒切换本质就是“3个advert_int没等到主节点的声音”。主备两台机器的virtual_router_id必须相同否则VRRP报文不匹配各认各的脑裂就来了。auth_pass也要一致它只做简单认证不是加密所以不要在跨公网的环境里裸跑VRRP。硬件资源如果不想浪费一台备机可以做成双主模型两个VIP分别落在两台机器上互相做对方的BACKUP。比如VIP1的MASTER是node1VIP2的MASTER是node2node1挂掉后node2同时持有VIP1和VIP2。配置时建两个vrrp_instancepriority互相错开vrrp_instance VI_1 { state MASTER virtual_router_id 51 priority 100 } vrrp_instance VI_2 { state BACKUP virtual_router_id 52 priority 90 }注意两个实例要用不同的virtual_router_idnode2上则刚好相反。双主模型适合两台机器规格一致、业务规模较大时使用能让备机也承担一部分生产流量。我实际维护过一套这样的集群出现过单机宕机期间另一台流量翻倍但只要容量预估够了问题不大。4.3 脑裂的成因、检测与防范脑裂是所有高可用方案最怕的问题表现就是两台LVS节点同时持有VIP客户端请求有时到主节点、有时到备节点后端被不同调度器随机分发整个集群行为完全不可控。常见的脑裂原因有这么几个两台机器的virtual_router_id不一致VRRP报文无法匹配双向都不认对方防火墙或交换机阻断了组播224.0.0.18备用节点收不到主节点通告以为主节点挂了就升级advert_int设置过小网络发生瞬时拥塞时通告丢失触发了不必要的切换两台机器priority相同双方在某些实现下可能出现竞争。防范措施首先是保证配置规范router_id保持一致、auth一致、priority不同。其次是网络层面不要在LVS节点的防火墙里拦截VRRP交换机上如果开了组播过滤要给VRRP放行。还有一招是把VRRP绑定到独立的管理网卡比如双网卡机器一张走业务流量一张专门走VRRP组播这样即使业务网卡拥堵也不影响心跳。检测脑裂最直接的办法是巡检脚本。我们在两台LVS节点上都放一个脚本检查本机是否持有VIP然后把结果上报给监控系统。如果监控同时收到两台机器上报“持有VIP”立即告警。脚本很简单#!/usr/bin/env bash VIP192.168.1.100 if ip addr show | grep -qw $VIP; then echo LVS_HAS_VIP else echo LVS_NO_VIP fi配合zabbix或Prometheus的文本采集每30秒跑一次就能实时发现双主。不要等线上出现诡异故障了才去翻IP脑裂问题越早发现越容易处理。5. 典型故障排查与调优实录5.1 常见问题速查我把这几年遇到的高频问题整理成一张表方便对照排查现象可能原因排查命令 / 处理方案访问VIP完全超时VIP不在任何LVS节点上ip addr show dev eth0检查主备VIP访问VIP超时但VIP存在LVS转发规则没生效ipvsadm -Ln确认real_server存在部分后端请求失败某RS服务异常但健康检查没摘除检查HTTP_GET的检查路径和状态码流量全部打向同一台RS会话保持时间太长、或权重差异过大调整persistence_timeout检查weightkeepalived频繁切换VRRP通告丢失看messages日志检查组播防火墙策略RS收不到请求LVS与RS二层不通从LVS节点ping RS_IP检查同网段RS回包客户端但业务异常lo接口VIP未配置或ARP参数失效ip addr show losysctl -a排查顺序我一般固定为先确认VIP在哪Keepalived状态再确认内核规则ipvsadm再确认后端节点本身健康curl RS最后才是抓包。这个顺序能把90%的问题缩小到三个层面里。5.2 抓包与日志定位一次真实故障讲一个印象很深的故障案例。某天接口服务快慢不一一部分请求稳定返回另一部分大概有20%会在5秒后超时。第一反应是后端某台机器出问题了但登录每台RS看CPU、内存都正常Nginx错误日志也没有明显异常。通过ipvsadm -Ln --stats看到三台RS都有了流量其中RS1的转发量明显偏高。再手动curl每一台RS的/healthzRS1偶尔要等4秒才返回其他节点几十毫秒。问题定位到RS1。但为什么Keepalived没把它摘掉因为当时用的是TCP_CHECK端口一直通应用层的慢根本没有暴露。后来把健康检查改成HTTP_GET /healthz同时在后端把/healthz接口的响应时间打印出来Keepalived在连续重试后把RS1摘掉了集群恢复稳定。那次之后我养成了两个习惯所有Web服务必须提供轻量健康接口且不能依赖数据库所有 Keepalived 健康检查优先用HTTP_GETTCP_CHECK只用于非HTTP服务。排查过程中用到的关键命令也放出来# 实时查看Keepalived状态 systemctl status keepalived journalctl -u keepalived -f # 查看LVS的连接分布 ipvsadm -Ln --stats # 抓VIP相关流量 tcpdump -i eth0 host 192.168.1.100 and port 80 -nn从抓包里能看到三类重要信息客户端是否请求VIP、LVS是否向后端转发、RS是否直接回包给客户端。如果LVS有转发但RS没回包大概率是RS路由或VIP配置问题如果RS回了包但客户端没收到就要看防火墙和会话跟踪了。5.3 性能调优与日常维护建议集群能跑起来之后剩下的是细水长流的维护。首先是内核参数如果LVS节点上的并发连接很大注意看conntrack是否满了cat /proc/sys/net/netfilter/nf_conntrack_max cat /proc/sys/net/netfilter/nf_conntrack_count如果nf_conntrack_count接近最大值要调高/etc/sysctl.conf里的net.netfilter.nf_conntrack_max同时把超时时间调短。LVS的DR模式不完全依赖conntrack但Keepalived在健康检查和部分调度算法下还是会创建conntrack条目不能忽略。第二是文件描述符ulimit -n建议调到65535以上特别是要转发大量长连接的场景。net.core.somaxconn也建议调大避免高并发下TCP半连接队列溢出这个常常藏在连接超时问题的背后。第三是日常维护节奏。我通常会做这几件事每天检查一次ipvsadm -Ln --stats的流量分布确认没有单台RS流量飙升每周做一次主备切换演练最简单就是重启keepalived观察VIP漂移和回切时间每次变更RS或应用发布都要在生产环境外先测试健康检查接口给Keepalived进程、VIP可用性、后端RS健康检查配独立监控告警。扩容也很简单新RS配置好VIP和ARP参数后在Keepalived的virtual_server里加一个real_server然后systemctl reload keepalived规则会重新加载。如果当时有存量长连接reload可能中断它们所以建议低峰期操作。缩容时我一般先把权重改成0让流量自然降为零再移除real_server这样对线上影响最小。6. 写在最后这套集群让我学到的几件事如果让我给刚接触这套架构的人一句建议那就是先把DR模式的原理彻底想明白再动手配。很多人配置完发现不通绕来绕去查防火墙最后发现是ARP参数没生效。原理通了配置就是照着填空。另一个体会是工具越老越稳。LVS和Keepalived都是很多年前就成熟的技术没有花哨的UI但确确实实扛住了我经历过的大流量。反而是那些复杂的新架构在故障时更难定位。高可用不只是靠软件更要靠监控和演练。VIP漂移这个动作演练过几十次真出故障时你才敢笃定地说“等一下三秒后自动恢复”。最后再分享一个小技巧上线前把VIP绑定到拨测系统每隔一分钟从外部发一次HTTP请求。一旦VIP丢失或双主第一时间收到告警。这套集群不会替你解决所有问题但有了它后端再怎么折腾用户的入口始终是稳定的。希望这篇从选型到排障的完整记录能让你少走我踩过的那些坑。