1. 先搞清楚:为什么到现在还要学LVS这套老东西
聊到负载均衡,现在很多人第一反应就是Nginx、HAProxy,或者直接上云原生的Ingress Controller、云厂商的SLB。我最早也是从Nginx开始接触反向代理和负载均衡的,后来在生产环境里遇到真实的性能瓶颈,才回头把LVS这套"老古董"认真学了一遍。学完之后最大的感受是:Nginx解决的是应用层的路由问题,LVS解决的是系统级的流量分发问题,两个压根不在一个层次上。
LVS全称Linux Virtual Server,中文一般叫Linux虚拟服务器,由章文嵩博士在1998年发起,算是国内开源的元老级项目之一。它的核心思路非常朴素:用一台Linux服务器作为前端入口,把进来的网络请求按照某种策略分发给后面的一组真实服务器去处理,对外只暴露一个虚拟IP(VIP),客户端感知不到后端的实际拓扑。
为什么到今天还要学LVS?两个字:性能。因为LVS工作在Linux内核态,直接操作的是网络协议栈和TCP/IP报文,用户态拷贝和上下文切换的开销被压到了极低。我自己在测试环境里用单台LVS Director压过数据,纯转发场景下,万兆网卡打满、CPU占用还能控制在单核百分之二三十的水平,这种表现Nginx跑在小包高并发场景下很难做到。如果哪天面试官问你"Nginx和LVS有什么区别",能说出"工作在四层、走内核态转发、天然支持更大并发"这一层,已经能证明你不是只停留在配置文件层面的人。
本文不是说让你在生产环境里放弃K8s那套东西,而是把LVS的核心机制、实验方法、常见坑位讲透。适合的人群是:想在简历里加一条"熟悉LVS负载均衡"的运维或后端开发、学校里需要交网络实验报告的计算机专业学生、以及正在排查线上四层负载问题但想弄明白原理的排查者。文末的实验我全部基于CentOS 7.9环境跑过,VirtualBox和VMware都能复现,原理部分不依赖具体版本。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. LVS的看家本领:三种工作模式究竟怎么选
LVS之所以能屹立这么多年不倒,核心原因是它的三种工作模式覆盖了从内网到公网、从简单到复杂的各种场景。这三种模式分别是NAT模式、DR模式(Direct Routing,直连路由)、Tunnel模式(IP隧道)。面试八股里常考,实际选型时也容易纠结,我结合自己的理解和实验结论逐个拆开讲。
2.1 NAT模式:最符合直觉但最容易成为瓶颈
NAT模式的工作原理是:客户端把请求发到Director的VIP上,Director通过调度算法挑一台后端的Real Server,把报文的目标地址改写成Real Server的IP,然后转发出去。Real Server处理完响应后,再把结果还给Director,由Director改写源地址后发回给客户端。
用大白话说,Director在这里扮演了"总出入口"的角色——进也走它,出也走它。好处是Real Server只需要配置私网IP,网关指向Director就行,对后端机器的网络配置几乎零侵入,所以实验环境里最容易搭起来。缺点是所有流量都要在Director上过一遍,转发带宽直接由Director的网卡物理上限决定。你后端有十台千兆服务器,如果Director只有一块千兆网卡,那总吞吐量就是千兆,后端再多也白搭。
NAT模式适合Realserver数量不多、业务对带宽要求没那么极端的场景。我见过一些传统机房里跑内部OA系统的,用一台双网卡的小服务器做NAT模式的LVS,后端挂三五台Web服务器,足够用了。
2.2 DR模式:生产环境用得最多的方案
DR模式的全称是Direct Routing,思路和NAT完全不同。客户端请求到达Director后,Director只做一件事:把数据帧的目标MAC地址改成选中的那台Real Server的MAC地址,然后原封不动地扔到二层网络里。Real Server收到这个帧后,因为数据包的目标IP就是VIP(Real Server上配置了VIP的lo别名地址),所以可以正常收下来处理。响应时,Real Server直接用VIP作为源地址回给客户端——响应流量根本不经过Director。
这个"请求进Director、响应直接走Real Server回客户端"的模型,就是LVS高性能的关键。Director只是做了个二层的帧转发,几乎不产生额外的协议开销,所以能支撑的并发量和吞吐量都非常可观。
但DR模式有个让人头疼的前提:所有的机器必须在同一个二层网络里,而且Real Server必须对ARP广播"装死"——默认情况下,一台Linux机器收到针对自己IP的ARP询问时会立刻响应,如果Real Server也响应了VIP的ARP请求,客户端的流量就直接打到Real Server上了,Director就失去了调度意义。这个问题通常靠修改内核参数、在Real Server的lo网卡上绑定VIP来解决,实验环节我会给出完整操作。
2.3 Tunnel模式:跨网段时的DR延伸
Tunnel模式可以理解成DR模式的"远程版"。Director收到请求后,把原始IP报文原样封装进一个新的IP报文里,源地址是Director自己的IP,目标地址是Real Server的真实IP,然后发出去。Real Server解封装取出原始报文后,发现目标IP是VIP,就照常处理,响应不再经过Director,直接走自己的默认路由出去。
这个模式的价值在于:Real Server和Director不要求在同一个二层网络,可以跨网段部署。比如Director在IDC的A机房,Real Server在B机房,中间走三层网络也能把流量送过去。代价是封包和解包会带来额外的CPU开销,而且要求Real Server的内核支持IP隧道协议(modprobe ipip)。实际生产里部署得不如DR广泛,我在实验环节也不会重点展开,但原理一定要能讲明白。
2.4 三种模式横向对比与选型建议
我把三种模式的关键差异整理成了一张表,做技术方案评审时直接拿来用:
| 对比项 | NAT模式 | DR模式 | Tunnel模式 |
|---|---|---|---|
| Director的作用 | 入口和出口都经过,改写目标地址 | 只改MAC帧头,响应不经过Director | IP报文二次封装,响应不经过Director |
| Real Server网络要求 | 内网私网IP,网关指向Director | 与Director同二层网络,需隐藏对VIP的ARP响应 | 可不跨网段,但需支持IPIP隧道 |
| Director性能瓶颈 | 响应流量也过Director,吞吐上限明显 | 几乎无瓶颈,性能极高 | 封包有CPU开销,但响应不过Director |
| 配置复杂度 | 最低 | 中等,ARP问题要处理 | 较高,需要加载隧道模块 |
| 适用场景 | 小规模、后端数量少 | 绝大多数局域网生产环境 | 跨机房、跨网段的规模化场景 |
我的建议是:实验和入门先用NAT模式把"调度器-后端服务器"这套模型跑通,然后立刻切换到DR模式,因为这个模式你将来在职场上碰到概率最大。Tunnel模式了解原理即可,真要在生产环境用,先想清楚网络打通和MTU问题再说。
3. 调度算法不是随便选的:十种算法背后的适用逻辑
很多教程会把LVS的十种调度算法罗列一遍,然后告诉你"自己看着选"。但实际工作中,算法选错了,后端压力失衡甚至雪崩都是有可能的。我按自己的理解把算法分成三大类来讲,每一类说清楚机制、适合场景和典型坑。
3.1 基础轮询类:rr、wrr
rr(Round Robin,轮询)是最朴素的算法:请求按顺序轮流分发给每台Real Server,不关心每台机器的当前连接数、负载高低。wrr(Weighted Round Robin)在轮询基础上加了权重——比如两台机器权重分别是3和1,那么前三台新请求都发给第一台,第四台给第二台。权重可以简单理解成"能力比值",但要注意,wrr在长连接场景下经常出现权重高的机器连接数越堆越多的情况,因为它只保证"请求轮流来",不保证"活跃连接均匀"。
我的经验是:rr适合后端机器配置完全一致的场景,wrr适合后端机器有新旧差异、需要按能力分配流量的场景。但这两兄弟都管不了"某个后端正在处理一个慢请求,连接还没释放"这类动态情况。
3.2 连接数感知类:lc、wlc、lblc、lblcr
lc(Least Connections,最少连接)比较好理解:新请求来了,谁当前的活跃连接数最少就发给谁。但lc在现实中容易被"连接长时间不释放"的场景坑到——比如保持连接(keep-alive)很长,某台机器分到的连接一直没有断开,新请求就源源不断地发给别的机器。
wlc(Weighted Least Connections)在lc基础上,按公式"负载 = 活跃连接数 / 权重"来计算,选负载最小的那台。这是LVS默认的调度算法,也是生产环境里最常用的。lblc(Locality-Based Least Connections,基于局部性的最少连接)是针对缓存类业务设计的,简单说就是"同一个目标IP的请求尽量发到同一台Real Server",因为缓存命中的效益最高。但lblc只在所有后端处理能力相当、缓存太小换机器没太大意义时才有优势。
lblcr(Locality-Based Least Connections with Replication,带复制的基于局部性的最少连接)在lblc基础上更进一步:它会维护一个"目标IP到Real Server集合"的映射,同一目标IP的请求优先发到已经被映射的服务器,如果那台负载太高,就把请求发给集合里负载最低的服务器,并且把它也加进映射集合。这个算法适合目标IP相对固定的场景,比如某些内网办公系统。
3.3 目标散列类:dh、sh
dh(Destination Hashing,目标地址散列)把目标IP做哈希,映射到一台Real Server上。sh(Source Hashing,源地址散列)则是对源IP做哈希。这类算法的核心价值是"同一个客户端IP,永远被分到同一个后端服务",这就是所谓的会话保持(session sticky)。比如你做无状态改造之前,登录用户的session还保存在后端服务器内存里,用sh算法就能把用户请求稳定地固定在一台机器上。
需要注意,sh虽然能实现会话保持,但后端扩容缩容时,哈希结果会大变,大量用户的会话会失效。现代架构里一般会用Redis、Memcached这类集中式会话存储来替代这种"低级"的会话保持方案,如果你能在方案评审时说清楚这一点,面试官通常会高看一眼。
怎么选?我的建议是:不要盲目追求"高级",先把wlc用好——绝大部分场景下它已经足够优秀。如果你的业务是典型的缓存服务、API网关,再回头看lblc和sh也不迟。
4. 亲手搭一个DR模式实验环境
下面进入正题。我用两台虚拟机加一台宿主机网络桥接的方式,搭了一个最小化的DR模式LVS集群,整个过程完全可复现。实验组网如下:
- Director:一台CentOS 7.9虚拟机,两块网卡,一个内网IP(192.168.56.10),一个VIP(192.168.56.100)。
- Real Server 1:CentOS 7.9虚拟机,内网IP 192.168.56.11。
- Real Server 2:CentOS 7.9虚拟机,内网IP 192.168.56.12。
有人会问:DR模式要求同二层网络,为什么Real Server不给公网IP?因为实验环境里我让three台机器跑在同一个NAT网络或Host-Only网络里,从宿主机的角度它们就是一个二层网络,效果完全够用。需要说明的是,DR模式下VIP选择和Real Server的物理IP在同一个子网,这是为了让Director通过二层广播就能把VIP和Real Server所在子网的机器进行通信,真实生产里通常用公网网段的VIP做类似设计。
4.1 环境准备:关防火墙、关SELinux、装ipvsadm
先把三台机器的公共事项处理掉。CentOS 7的防火墙和SELinux对新手来说是最容易卡壳的地方——如果没关,director的转发、real server的访问都会莫名奇妙的失败。
bash复制# 三台机器都执行
systemctl stop firewalld
systemctl disable firewalld
sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config
setenforce 0
然后给Director安装ipvsadm管理工具:
bash复制yum install -y ipvsadm
这个包提供ipvsadm命令行,用来配置和管理内核里的LVS规则。安装好后先用ipvsadm -L看一下当前规则列表,确认是空的即可。
4.2 Director配置:定义VIP和Real Server池
Director上需要做三步配置:添加VIP、开启转发、定义调度规则。VIP我直接绑定在ens33这块网卡上:
bash复制ifconfig ens33:0 192.168.56.100 netmask 255.255.255.0 up
先手动加上这个临时的子接口,确认LVS实验能通,后面要持久化再写到配置文件。
开启内核IPv4转发。DR模式虽然不像NAT模式那样直接转发IP报文,但Director自己也要能处理多网卡之间的报文流动,所以开启转发没有坏处:
bash复制echo 'net.ipv4.ip_forward = 1' >> /etc/sysctl.conf
sysctl -p
配置ipvsadm规则。这里我选择wlc(加权最少连接)算法,它最适合观察"真实服务器之间的动态分配效果":
bash复制# 清空已有规则(实验重来用)
ipvsadm -C
# 添加VIP服务,指定调度算法为wlc
ipvsadm -A -t 192.168.56.100:80 -s wlc
# 给这个VIP服务添加两台Real Server,权重都设为1
ipvsadm -a -t 192.168.56.100:80 -r 192.168.56.11:80 -g -w 1
ipvsadm -a -t 192.168.56.100:80 -r 192.168.56.12:80 -g -w 1
这条命令的-g参数就表示使用DR模式(gatewaying),因为DR模式本质上就是在二层网关的层面把报文转给Real Server。如果用-m则是NAT模式,-i则是Tunnel模式——这三个参数一定要记牢。
设置完用ipvsadm -L -n查看,正常情况下输出类似:
text复制IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 192.168.56.100:80 wlc
-> 192.168.56.11:80 Route 1 0 0
-> 192.168.56.12:80 Route 1 0 0
这里Forward那列显示Route,说明规则已生效。
4.3 Real Server配置:隐藏ARP是关键
DR模式最不容马虎的环节就在这里。Real Server上要做两件事:第一,把VIP绑定到lo网卡的别名上,这样它能正常接收目标IP是VIP的报文;第二,修改内核ARP参数,确保它不对VIP的ARP请求作出响应。
bash复制# 在两台Real Server上分别执行
ifconfig lo:0 192.168.56.100 netmask 255.255.255.255 up
# 添加路由:访问VIP时走本地lo接口
route add -host 192.168.56.100 dev lo:0
为什么掩码必须是255.255.255.255?这是很多新手会犯的错。如果掩码写255.255.255.0,等价于告诉系统"192.168.56.x这个网段都是本地直连的",系统会认为VIP是这个网段的一部分,ARP逻辑会变乱,导致请求无法正常转发到Real Server的处理栈中。写成32位掩码,意思就是"只有VIP这一个地址是本地逻辑接口地址",这样最干净。
然后修改ARP参数:
bash复制echo 'net.ipv4.conf.all.arp_ignore = 1' >> /etc/sysctl.conf
echo 'net.ipv4.conf.all.arp_announce = 2' >> /etc/sysctl.conf
echo 'net.ipv4.conf.lo.arp_ignore = 1' >> /etc/sysctl.conf
echo 'net.ipv4.conf.lo.arp_announce = 2' >> /etc/sysctl.conf
sysctl -p
这两个参数的作用是:
arp_ignore = 1:只回答目标IP是本机某个网络接口IP的ARP请求。VIP虽然绑在lo上,但外界问VIP的MAC时,因为VIP不是物理网卡的直接地址,按这个规则就不回。arp_announce = 2:对外声明ARP时,总是使用最能代表本机的物理网卡IP,而不是VIP。
这两招配完之后,Director发出的"谁是192.168.56.100"的ARP广播,只有Director自己会回答,Real Server保持沉默。
别忘了在两台Real Server上装Nginx并开启服务,用于区分请求到底被分发到了哪台:
bash复制# Real Server 1
yum install -y nginx
echo "This is RS1 192.168.56.11" > /usr/share/nginx/html/index.html
systemctl start nginx
# Real Server 2
yum install -y nginx
echo "This is RS2 192.168.56.12" > /usr/share/nginx/html/index.html
systemctl start nginx
我在这里故意把页面内容设置成不同的标识,方便观察负载均衡效果。
4.4 验证实验:从VIP发起连续请求
从宿主机或另外一台测试机发起HTTP请求:
bash复制curl http://192.168.56.100/
多执行几次,观察返回值:
text复制This is RS1 192.168.56.11
This is RS2 192.168.56.12
This is RS1 192.168.56.11
This is RS2 192.168.56.12
交替出现就说明负载均衡基本跑通了。再用ipvsadm -L -n --stats查看连接分布和统计信息:
text复制Prot LocalAddress:Port Conns Packets Bytes
-> RemoteAddress:Port
TCP 192.168.56.100:80 12 48 5152
-> 192.168.56.11:80 6 24 2576
-> 192.168.56.12:80 6 24 2576
两台Real Server的连接数基本对半,调度正常。到这里一个最简DR实验就成功了。
5. 实验做完还不够:这些隐藏坑和细节值得深挖
只是把实验跑通,说实话价值不大。LVS真正的经验积累在于"出了问题时怎么定位"以及"如何做得更像生产环境"。这一节我把实操中遇到的高频问题和我的排查思路整理出来。
5.1 常见故障一:curl VIP没有响应
这是实验里最常出现的问题。按下面顺序排查,一般十分钟内能定位:
- 先在Director上确认VIP是否正常绑定:
ip a show ens33,如果看不到VIP就重新配置,注意子接口不会自动持久化。 - 再确认ipvsadm规则列表是否存在:
ipvsadm -L -n,如果规则为空,说明规则没加上,重跑第4.2节里的命令。 - 接着检查Real Server上Nginx是否启动:
curl http://192.168.56.11/。 - 最关键的一步,看Real Server的内核日志:
tail -f /var/log/messages,如果看到arp_ignore/arp_announce相关的报错或者VIP被拒绝的日志,基本都是ARP参数没生效。
还有一个常见低级错误:Real Server的lo:0没配或者掩码写错,然后Real Server把VIP当作一个不可达的目标丢弃了,流量到了Real Server却没人接管,表现也是curl卡住。
5.2 常见故障二:数据包到达Real Server,但nginx访问不了VIP
这个场景多见于"Real Server能ping通Director,但curl VIP无响应"。核心原因是ARP隐藏没有做彻底。检查方法:
bash复制# 在Real Server上执行
cat /proc/sys/net/ipv4/conf/all/arp_ignore
cat /proc/sys/net/ipv4/conf/all/arp_announce
如果输出不是1和2,就把sysctl.conf里的配置重新加载。另外注意,有些发行版会有多个网卡,你还需要对每张物理网卡都做同样的配置:
bash复制echo 'net.ipv4.conf.ens33.arp_ignore = 1' >> /etc/sysctl.conf
echo 'net.ipv4.conf.ens33.arp_announce = 2' >> /etc/sysctl.conf
我见过一台机器上配了all和lo的ARP参数,但忘了配主网卡的,结果问题依旧。
5.3 生产环境进阶:keepalived是不可或缺的搭档
实验环境里Director只有一台,如果Director挂了,整个集群就瘫痪了。生产环境绝不允许这种单点存在,解决办法就是keepalived。
Keepalived做的事情有两件:一是通过VRRP协议让两台Director共享同一个VIP,平时VIP在Master上,Master挂了VIP自动漂移到Backup上;二是LVS规则的健康检查——如果某个Real Server的HTTP服务探测失败,keepalived自动把它从ipvsadm规则里摘除,恢复后再加回来。
这里要特别注意Keepalived配置里的一个常见误区:虚拟IP地址(virtual_ipaddress)和real_server的健康检查端口必须和ipvsadm里配置的端口一致。如果业务监听的是80端口但健康检查写成了443,那Real Server永远会被判定失败,导致所有后端都被摘除。
有些团队会直接用keepalived代替手动配置ipvsadm,因为keepalived会把LVS规则主动下发到内核里,比手动维护ipvsadm命令更自动、更好管理。这也是目前最常见的生产部署方式。我强烈建议搭建实验的时候,先把手动ipvsadm跑通,再引入keepalived,否则你很难分清问题到底出在LVS层还是VRRP层。顺序很重要。
5.4 这都2025年了,LVS还有用武之地吗
这个问题几乎每次分享都会被问到。我的真实看法是:LVS在传统的物理机机房和混合云架构里依然占有一席之地;但在K8s环境里,它更多是以kube-proxy的iptables/IPVS模式存在,普通业务开发者确实不太会直接操作ipvsadm命令了。
有一点非常值得注意:Kubernetes的kube-proxy专门提供了IPVS模式,通过LVS来实现更高效的Service负载均衡,解决iptables在大规模Service下性能衰退的问题。所以哪怕你以后做云原生,底层依然需要理解LVS的调度和转发模型。如果你连LVS都不懂,kube-proxy的IPVS模式出问题时会非常被动。从这个角度来说,学LVS绝对不是学一个过时技术,而是在为理解现代云原生基础设施打地基。这也是我把这篇文章写出来的原因——越底层的知识,保质期越长。
我给想做进阶实践的同学留几个思考题:如果后端机器跨机房部署,Tunnel模式下MTU(最大传输单元)应该怎么设置?如果Real Server的默认网关指向了Director,会对DR模式的响应流量产生什么影响?Keepalived的心跳网络和业务网络是否应该分开?想明白这几个问题,你就不是"用过LVS的人",而是"懂LVS的人"了。
我在实验中踩过最深的坑就是ARP参数配置不完整,导致三台机器在两个多小时里表现时好时坏,到了最后用tcpdump抓包才发现是Real Server抢答了VIP的ARP请求。所以提醒所有做实验的人,遇到诡异问题先抓包,别瞎猜。
