
聊到负载均衡大家第一反应多半是Nginx、是云上的SLB但真正要扛住超大流量服务器集群的入口LVSLinux Virtual Server是一堵绕不过去的墙。我第一次搭集群入口就是十年前用LVS那时候对“四层”和“七层”还没那么敏感只知道用Nginx反代后端机器多了之后自身CPU和连接数开始吃紧后来把最前面换成LVS压测数据的提升非常明显。这篇文章把LVS负载均衡集群的理论体系完整梳理一遍它到底是什么、三种工作模式怎么选、调度算法怎么配、生产环境怎么落地再聊到近年大流量架构里“等开销负载均衡”ECMP如何把单点LVS变成多活集群。适合正在搭建服务器集群、做负载均衡选型或者看了一堆云产品文档但想搞懂底层原理的读者。1. LVS在整个负载均衡体系里的位置1.1 LVS是什么一个跑在Linux内核里的四层转发器LVS诞生于1998年是章文嵩博士发起的开源项目全称Linux Virtual Server。它的核心并不在用户态而是Linux内核里的IPVS模块IP Virtual Server基于netfilter框架对IP报文做改写和转发。我们日常操作用的ipvsadm只是它的管理工具。你可以把流量比作快递。七层负载均衡像营业部小哥会拆开包裹看内容根据收件人、品类、备注做精细分拣而四层的LVS像转运中心里的高速分拣线只看目的地址和端口扫一眼就把包裹扔向对应派送点。不看内容、不做应用层解析意味着每个包的处理路径极短吞吐和并发能力做得很高。这也是LVS几十年下来仍然活跃在生产前端的原因——内核态处理带来的性能优势用户态软件很难完全追平。我第一次接触LVS时的直观感受就是“规则真少”。相比Nginx那一堆location、upstream配置ipvsadm就几条命令。但配置少不代表原理浅真正决定集群稳定性的恰恰是它背后那套网络转发细节。1.2 四层入口和七层网关到底怎么分工早期的单体架构一台机器扛流量后来扛不住了就上Nginx做反向代理再往后流量继续涨Nginx成了瓶颈。于是就有了经典的分层组合最前面是LVS四层入口后面挂多个Nginx做七层路由再往后才是应用集群。LVS只把连接分发给某一个Nginx节点它不管URL是什么、cookie是什么、用户端是手机还是PC。Nginx拿到流量后再按照Host、路径、Header去做应用级分发。这样做的原因很简单LVS负责高并发连接接入和高可用框架Nginx负责灵活的路由和灰度能力各自做最擅长的事。X-Forwarded-For这类头部信息也是七层网关加的四层LVS不会碰payload。顺带说一个常识不少云厂商的四层SLB产品底层就是基于LVS或者与LVS同类内核转发方案构建的。理解了LVS你就理解了云上负载均衡很多行为特征的来源比如它为什么支持TCP和UDP透传、为什么不做SSL卸载、为什么会话保持要靠源IP而不是Cookie。客户端 | v VIP --- LVS Director四层转发 |-------- Nginx/HAProxy七层路由 |-------- 应用集群 |-------- 应用集群2. LVS三种工作模式的原理与取舍2.1 NAT模式原理简单但入口出口都过LBNAT模式VS/NAT最符合普通人对负载均衡的直觉。客户端访问VIPDirector收到请求后按照调度算法挑选一台真实服务器RS把报文目标地址改成RS的内网IP转发出去RS处理完把响应回给DirectorDirector再把报文源地址改回VIP送回客户端。整个过程请求和响应流量都要经过Director。听起来很顺但代价也在这里Director同时承担入站和出站的全部带宽很容易成为集群瓶颈。要是后端服务全是下载、视频流这类响应远大于请求的业务Director的网卡会先被撑爆。NAT模式还要求Director开启net.ipv4.ip_forward而且RS的默认网关必须指向Director的内网地址否则响应包发不出去。优点也有RS可以完全不用绑定VIP服务器可以跨网段、用任何操作系统Director还能做端口映射比如外部访问VIP的80端口转发到RS的8080端口。如果集群规模不大、流量一般NAT模式配置最简单适合练手和小场景。但生产环境我很少建议用它原因后面会反复提到单点瓶颈太明显。2.2 DR模式性能王者回程流量直接走RSDR模式VS/DRDirect Routing是生产环境最常用的方案。请求到达Director后它不改目的IP只把二层帧的目的MAC改成选中的RS的MAC然后原样从本地网络发出去。RS收到包以后发现目标IP是VIP——因为VIP事先绑定在RS的lo接口上——于是本机处理响应包以VIP为源地址直接回给客户端完全不需要再经过Director。因为回程流量全部绕开DirectorDirector的负载非常低转发能力接近线性扩展。我实测过一个4核8G的Director挂两台Nginx压测10万QPS时Director的CPU占用只有30%左右同样的压力放在Nginx stream反代上CPU和连接表占用明显高一个量级。当然这个数字不是绝对基准机型和网卡不同会有差异但趋势是确定的。DR模式有两个关键前提一是RS必须绑定VIP到lo接口二是必须做ARP抑制。如果不抑制ARPRS会响应VIP的ARP请求交换机或客户端学到VIP的MAC就变成了某台RS流量绕过Director直接打到RS调度规则全部失效现象就是集群时而正常时而异常。这块细节我踩过坑后面排查章节还会再提。DR模式还要求Director和RS在同一个二层网络里跨网段不行这也是它和TUN模式最大的差别。2.3 TUN模式跨网段靠IP隧道TUN模式VS/TUN解决跨网段部署的问题。Director把原始请求包用IP-in-IP隧道封装外面再套一层新IP头源地址是Director目的地址是RS的真实IPRS收到后解封装看到内层目的地址是VIP本机已绑定直接处理响应从RS以VIP为源地址返还客户端。TUN模式的好处是RS不需要和Director二层可达跨机房、跨网段也能用。代价是需要所有RS支持并加载IPIP隧道模块同时每个包都要做封装和解封装CPU消耗略高。在云环境里还要确认网络策略放行了IPIP协议协议号4很多安全组默认不放行这是个隐藏坑。从实际占比看TUN模式用得不算多。跨网段的流量分发多数场景直接用上层DNS、云负载均衡或硬件设备解决了真到需要自己管四层入口时优先考虑用VxLAN或专线打通二层走性能更好的DR模式。2.4 三种模式的对比与选型建议模式请求是否经过LB响应是否经过LB对RS的要求网络要求性能NAT是是无需绑定VIP三层可达RS网关指向Director中等LB容易成瓶颈DR是否绑定VIP并抑制ARP二层可达非常高TUN是否绑定VIP并支持IPIP三层可达高隧道有少量CPU开销选型其实不复杂。绝大多数场景我直接选DR省带宽、省连接处理Director即使普通配置也能扛很高的转发量。RS跨网段又没办法打通二层的再考虑TUN。NAT模式基本只在实验环境、或者后端RS不方便绑定VIP的特殊场景才用。很多教材把NAT放在第一位讲是因为它好画图、好解释但生产架构不能只图好理解。3. 调度算法逐个拆解从轮询到最短期望3.1 先看静态算法轮询、加权轮询和哈希LVS的调度算法决定“来一个连接分给哪台RS”。静态算法不看实时负载纯粹按固定规则分。rrRound Robin轮询按顺序循环分给每台RS。后端配置一样、请求处理成本差不多的时候最省事。wrrWeighted Round Robin加权轮询给高配机器设更大的weight按权重比例分发。实际生产里权重不直接等于QPS比例但可以用来大致控制分流。shSource Hashing源地址哈希同一个源IP固定分到同一台RS天然做了一种简单的会话保持。注意节点变动时哈希映射会整体重排可能造成某台RS瞬间压力升高。dhDestination Hashing目标地址哈希同一个目标地址固定分到同一台RS早期常用于缓存集群让相同内容的请求集中命中同一台缓存节点。静态算法的优点是开销小、确定性强。缺点是不管后端机器是不是已经忙不过来该分还是分。以前我见过一套后端三台机器配置差异很大的集群硬用rr结果高配机器闲着低配机器被打满。这种情况要么换wrr要么上动态算法。3.2 再看动态算法最少连接、加权最少连接和那些变体动态算法会参考RS当前的连接数或负载状态再做决策。lcLeast Connections最少连接谁当前活动连接少就分给谁。wlcWeighted Least Connections加权最少连接在连接数和权重之间取平衡。内核实现里不是简单拿连接数除以权重而是类似把连接数放大后做加权比较的机制结论是权重越大越容易被选中。总体来说wlc是生产环境比较稳妥的默认选择。sedShortest Expected Delay最短期望延迟按(active1)/weight的思想估算延迟优先选期望延迟最小的RS。nqNever Queue永不排队对sed的改进有空闲RS就直接分给空闲的没有空闲再按sed计算。适合延迟敏感的业务。lblc/lblcrLocality-Based Least Connections基于局部性的最少连接及其带复制的变体专门给Web Cache这类集群设计的尽量让同一内容的请求集中在同一台cache节点上提升命中率lblcr允许热点内容复制到多台节点。如果不是缓存场景基本用不上。动态算法看起来更“智能”但它依赖连接数这个指标。连接数只能间接反映负载如果后端请求大小差异很大连接数少的机器未必最闲。所以生产里我还是以wrr和wlc为主特殊场景再换sh或dh。3.3 生产环境调度算法选型经验选算法这件事我的建议是先按业务类型排除再按实测数据定。无状态Web集群选wrr或wlc基本不出错需要基于源IP的会话保持就选sh缓存场景优先考虑lblc系列延迟敏感的接口可以考虑nq。实际操作中有一个很爽的点LVS的调度算法支持在线热切换改完立刻生效不用重启服务。所以你可以先跑一轮wrr看看各RS的连接分布和响应时间觉得哪台有问题再切wlc对比调参成本很低。但算法只解决“分给哪台”的问题不解决“这台挂了怎么办”的问题健康检查和高可用必须靠另一套体系。4. 生产落地配置与高可用4.1 用ipvsadm搭一个最小DR模式环境光讲理论没意思直接上一个最小可复现环境。假设VIP是203.0.113.10Director的物理地址是192.168.1.2两台RS分别是192.168.1.10和192.168.1.11后端跑Nginx。Director上先装工具并加载内核模块yum install -y ipvsadm keepalived modprobe ip_vs echo modprobe ip_vs /etc/rc.local配置VIP并添加负载均衡规则ip addr add 203.0.113.10/32 dev eth0 ipvsadm -A -t 203.0.113.10:80 -s wrr ipvsadm -a -t 203.0.113.10:80 -r 192.168.1.10:80 -g -w 1 ipvsadm -a -t 203.0.113.10:80 -r 192.168.1.11:80 -g -w 2 ipvsadm -L -n-A是新增虚拟服务-a是添加RS-g表示DR模式-m是NAT-i是TUN-w是权重。两台RS上需要绑定VIP到lo并开启ARP抑制ip addr add 203.0.113.10/32 dev lo echo 1 /proc/sys/net/ipv4/conf/all/arp_ignore echo 2 /proc/sys/net/ipv4/conf/all/arp_announce echo 1 /proc/sys/net/ipv4/conf/lo/arp_ignore echo 2 /proc/sys/net/ipv4/conf/lo/arp_announce这些sysctl参数最好写进/etc/sysctl.conf不然重启就丢了。配置完成后用curl -H Host: example.com http://203.0.113.10/测试连续访问几次可以看到RS日志里有请求交替进来。我第一次搭DR的时候最常犯的错就是忘在RS上做ARP抑制。结果交换机ARP表学走了VIP流量全打到某台RS上现象时好时坏排查了大半天。这类坑几乎人人踩一次所以建议RS上的VIP和ARP参数在系统初始化阶段就固化进模板。4.2 用keepalived做VIP漂移和健康检查单台Director挂了整个入口就断了所以生产至少要1主1备。keepalived是LVS最常用的搭档它同时干两件事通过VRRP协议实现VIP在主备节点间漂移以及探测后端RS的健康状态自动增删ipvsadm里的RS条目。一个最小化的keepalived主节点配置大概是这样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 1111 } virtual_ipaddress { 203.0.113.10/32 dev eth0 } } virtual_server 203.0.113.10 80 { delay_loop 6 lb_algo wrr lb_kind DR persistence_timeout 60 protocol TCP real_server 192.168.1.10 80 { weight 1 TCP_CHECK { connect_timeout 3 nb_get_retry 3 delay_before_retry 3 } } real_server 192.168.1.11 80 { weight 2 TCP_CHECK { connect_timeout 3 nb_get_retry 3 delay_before_retry 3 } } }备节点把state改成BACKUP、priority调低即可。这里有个操作体会TCP_CHECK只探测端口能不能连上如果后端端口开着但应用已经返回500keepalived照样认为RS健康。对HTTP应用建议用HTTP_GET检查具体的URL状态码或者用MISC_CHECK调用自定义脚本检测粒度要按业务来。persistence_timeout是一个容易忽略的参数。它表示在设定时间内来自同一个源IP的新连接都发给同一台RS。如果业务会话已经放到Redis里了这个值可以直接设0让负载更均匀如果后端是本地Session就得根据Session有效期设置否则用户会反复掉线。大促期间尤其别把persistence时间设太大否则某个出口IP下的所有用户都会被压到同一台机器上。4.3 排查实录ARP混乱、权重归零、会话丢失生产里LVS的问题说来说去就那么几类我把最常见的整理成速查表。现象常见原因排查与解决访问VIP时通时不通RS响应了VIP的ARP交换机ARP表指向RS检查RS的arp_ignore/arp_announce确认VIP只绑在lo请求全打到同一台RSkeepalived探测失败其他RS weight被置0看ipvsadm -L -n里的权重状态查keepalived日志确认探测原因NAT模式下客户端看到的源IP全是DirectorNAT模式固有行为应用侧日志分析需改用其他方式记录真实IP或直接上DR同一用户频繁掉线rr算法把同一用户的不同连接分到不同RS本地Session丢失改用sh算法或设置合理的persistence_timeoutDirector连接表暴涨、丢包NFS conntrack耗尽常见于NAT模式调大nf_conntrack_max但更根本是换DR模式降低LB压力长连接应用卡死LVS默认对长连接没有空闲超时控制TCP保活或应用心跳没配好在应用层做心跳确认防火墙、keepalived没有把空闲连接判定失效有一个很实用的排查命令组合在Director上看ipvsadm -L -n --stats看累计流量cat /proc/net/ip_vs_conn看当前连接表再用tcpdump -i eth0 host VIP抓包确认包的MAC是不是RS的。多网卡RS还要小心出口路由只要RS配置多条默认路由响应从错误网卡发出去TCP握手就建立不起来这时候需要策略路由保证回包路径一致。5. 从单LVS到多活LVS集群5.1 单LVS性能高但它扛不住单点故障LVS单机的转发能力已经足够高但生产环境有两个现实问题绕不开一是Director宕机二是流量超过单机网卡或CPU的极限。前面说的keepalived主备方案本质上同一时刻只有一台LVS在转发另一台是冷备机器资源只有一半在干活。如果我们能通过上层网络设备把流量同时分给多台活着且独立的LVS节点也就是让LVS层变成“多活”那么LVS节点就可以水平扩展彻底解决单机瓶颈和单点故障。这就是等开销负载均衡出场的场景。5.2 等开销负载均衡ECMP如何把LVS扩容成多活“等开销负载均衡”这个词对应路由领域就是ECMPEqual-Cost Multi-Path routing。它的核心思路是去往同一个目的地址存在多条开销相等的下一跳路径路由器或交换机按哈希算法在多个下一跳之间分配流量。哈希因子通常是五元组源IP、目的IP、协议、源端口、目的端口这样能保证同一个TCP连接的所有包都走同一条路径不会乱序。把ECMP用在LVS集群上拓扑是这样的上游交换机/路由器ECMP | | | LVS-1 LVS-2 LVS-3 | | | ---- RS集群Nginx/API Server多台LVS配置相同的VIP上层路由设备配置多条等价路由下一跳分别是每台LVS的地址。流量到达路由设备后被hash到不同LVS节点每个LVS再各自用DR模式转发给RS。某台LVS挂了上层设备通过BFD、OSPF联动等机制检测到下一跳失效自动把原来分给它的一半流量收敛到其他LVS。所有LVS都在干活容量几乎线性扩展这是大流量集群比较理想的一个形态。ECMP是网络设备能力不是软件包具体配置命令因厂商而异比如华为、H3C、思科的实现细节都有区别。实施时要关注两个点一是hash算法的粒度尽量做到五元组一致避免同一个连接的不同包被分到不同LVS二是路由收敛速度节点故障后要让上层设备尽快感知否则故障的LVS还会持续收到流量。没有交换机操作权限的团队用云厂商的负载均衡产品也是一种等效方案底层思路是相似的。5.3 大数据组件集群的统一入口场景很多人在搭Kafka、Redis Cluster、Spark、Doris、Hadoop这类集群时会遇到一个共性问题客户端要连接的节点越来越多运维侧希望对外只暴露一个VIP让负载均衡层去屏蔽后端节点的变化。这个需求刚好是LVS的典型场景。以Doris为例多个FE节点都提供MySQL协议服务用LVSkeepalived把多个FE聚合成一个VIPJDBC连接串只填VIP后端FE可以随扩缩容调整对业务完全透明。Hadoop的NameNode HA也类似Active和Standby节点前面挂一个VIP切换时客户端连接不感知。Spark、Hadoop集群的资源管理UI和REST接口同样适合用四层转发统一暴露。但Kafka和Redis集群要特别小心。Kafka客户端通过metadata机制获取broker地址后会直连broker如果只把bootstrap.servers配成VIP而broker的advertised.listeners仍然写真实IP那么LVS只中转最初的握手请求实际数据连接根本不经过LVS后端的扩缩容信息也会暴露给客户端。Redis Cluster也有类似的redirect机制。所以在大数据场景用LVS之前必须先确认组件的“节点发现机制”是否允许通过VIP访问所有节点否则可能搭了半天流量根本没进LVS。最后分享一点个人体会LVS虽然是个上世纪就出现的技术但在今天的大并发架构里位置一点没降。我见过不少团队把入口全押在云负载均衡产品上等遇到自定义四层协议、超大连接数、跨地域多活的场景时才发现还是得回到LVS这套体系。建议至少把DR模式、ECMP多活、keepalived健康检查这几个点弄清楚不管用不用得上以后看到集群入口、统一网关这类方案时能第一眼判断它走的是四层还是七层底层的瓶颈可能出现在哪里。这些判断能力往往比单纯会敲配置命令值钱得多。