前阵子帮一个朋友排查线上性能问题,两台后端应用服务器,一台CPU跑到了80%,另一台闲得只有10%。我第一反应是Nginx负载均衡没配好,结果进去一看,Nginx前面没有入口层,所有四层长连接流量全靠Nginx转发,连接数一上来,Nginx本身成了瓶颈。我给他的建议很简单:入口层四层流量交给LVS,Nginx退到七层只做业务路由。改完搭配压测,整体吞吐翻了近一倍。
这篇文章我就把LVS的原理和部署完整拆一遍。不管你是刚接触负载均衡的运维新手,还是想优化现有架构的后端开发,看完应该都能明白LVS为什么快、怎么选模式、怎么落地一套高可用的LVS集群。
1. LVS到底解决了什么问题
1.1 从一次线上故障说起
上面说的那个场景其实非常典型。很多团队从单机架构起步,后来流量涨了,就在前面加了一台Nginx做反向代理,后端挂两台服务器。这样确实能用,但当你把网络包打开看一遍就会发现问题:Nginx作为七层负载均衡,它要完整解析HTTP协议,每一个请求都要经历“接收请求、解析头部、转发给后端、接收响应、再回传给客户端”的完整过程。这一套在HTTP短连接场景下还好,一旦遇到WebSocket长连接、大文件上传下载、视频流这类四层流量,Nginx的并发能力和吞吐上限很快就会被拉满。
我们当时的压测数据是:纯Nginx七层转发,单机最多扛住2万左右的并发连接,CPU已经打满。而LVS跑在内核态,直接在内核网络栈里做转发,单机并发轻松到10万以上,CPU开销却低得多。所以对于高并发、长连接的入口层,LVS几乎是必选项。
1.2 LVS的核心架构与三大组件
LVS全称Linux Virtual Server,是章文嵩博士在1998年发起的开源项目。它的核心思想非常朴素:在Linux内核层把流量调度到一组后端服务器上,对客户端来说,整个后端集群就像一台虚拟服务器,只有一个入口IP。
LVS的架构由三部分组成:
- 负载均衡器(Director Server):也就是LVS的前端调度器,所有客户端请求先进到这里。这里运行着内核模块ip_vs,负责接收、修改和转发网络包;配套的ipvsadm是用户态的管理工具,用来配置转发规则、查看连接状态。
- 后端服务器池(Real Server):真正处理业务的服务器,可以是一组Web服务器、应用服务器或数据库中间件。它们接收Director转发过来的请求并返回结果,本身不感知客户端的真实存在。
- 共享存储(可选):对于需要保持一致数据的服务(比如多个Web节点共享同一套静态文件),后端服务器可以挂载共享存储,保证数据一致。这个不是必须的,但很多LVS集群会配上。
理解了这三部分,LVS的整体流程就清楚了:客户端请求到达Director,Director根据预设的调度算法挑选一台后端服务器,然后通过特定的转发方式把请求送过去。后端处理完,响应再按模式不同选择回传路径。
1.3 为什么现在还要学LVS:四层和七层的分工
经常有朋友问我:现在Kubernetes、Nginx Ingress这么普及,直接用Service、Ingress做流量管理不就行了吗?为什么还要单独学LVS?我一般会用一句通俗的话回答:四层负载均衡管“把请求送到哪台机器”,七层负载均衡管“HTTP请求该路由到哪个服务”。
Kubernetes里的kube-proxy,其实在iptables/ipvs模式下用的就是类似LVS的内核转发能力;云厂商的SLB、CLB底层也大量使用LVS或者类LVS的方案。你部署的很多高端方案,底层逻辑都是LVS这套东西。所以把它学透,你再看其他负载均衡产品,基本能一眼看出底层套路。
此外,LVS的三个特点让它至今没有被淘汰:
- 高性能:工作在内核态,不需要像Nginx那样频繁地在用户态和内核态之间拷贝数据,转发能力非常高。
- 高可用:配合Keepalived可以轻松实现双机热备,调度器挂了VIP会自动飘到备用节点。
- 灵活多样:三种转发模式(NAT、DR、Tunnel)覆盖了不同网络场景,可以做到本地转发、跨网段转发、甚至跨机房转发。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 三种工作模式的原理深度拆解
LVS支持的三种转发模式是NAT、DR和Tunnel,也是面试和实战中最常被问到的。很多人只知道名字,但说不清内核到底做了什么改动。我把三种模式从数据包层面完整讲一遍。
2.1 NAT模式:最直观的“改地址”转发
NAT(Network Address Translation)模式是最容易理解的一种。它的核心就是做两次地址转换,和家用路由器上网的原理一样。
请求方向:客户端发送请求包,目标地址是VIP(Virtual IP,虚拟IP)。包到达Director后,Director做DNAT(目的地址转换),把包的目标地址从VIP改成选中的Real Server的IP地址,然后转发出去。注意,这时的源地址仍然是客户端的IP。
响应方向:Real Server处理完请求后,把响应包发送出去。因为Real Server的默认网关指向了Director,所以响应包会回到Director。Director收到后做SNAT(源地址转换),把响应包的源地址从Real Server的IP改成VIP,再回传给客户端。
这个模式最大的特点是请求和响应都经过Director,所以Director本身就变成了性能瓶颈,后端服务器的规模稍大一点就撑不住了。但同时它也有不可替代的优势:Real Server只需要配置一个同网段的IP,网关指向Director即可,不需要额外配置VIP,不需要修改ARP。所以NAT模式特别适合后端服务器数量不多、流量不算高的场景,或者后端服务器运行在云虚拟机里、不方便加VIP的情况。
2.2 DR模式:性能之王的“改MAC”转发
DR模式是生产环境用得最多的模式。它的思路很巧妙:Director只负责修改二层网络中的MAC地址,把包转发给选中的Real Server,不修改IP层任何信息。响应数据包则由Real Server直接回传给客户端,完全绕开Director。
具体流程是这样的:
- 客户端请求包到达Director,目标IP是VIP,源IP是客户端IP。
- Director根据调度算法选出一台Real Server,然后把这个请求包的二层MAC帧头改掉:把目标MAC改成Real Server的MAC地址,源MAC改成Director的MAC地址。
- 包通过二层交换机转发到Real Server。Real Server收到后,发现目标IP是VIP,而自己的lo接口上恰好绑定了这个VIP,于是内核网络栈正常接手处理。
- Real Server处理完,响应包的目标IP是客户端IP,源IP是VIP。它直接查路由发给网关,这个包就完全不需要经过Director了。
这里的关键是:Real Server必须配置VIP在自己的回环接口(lo)上,并且要抑制对VIP的ARP响应。如果不做抑制,当客户端请求VIP的ARP时,所有Real Server都会抢答,那流量就会分散到各台Real Server上,而没有经过Director调度,整个LVS就失效了。
DR模式的优点是性能极高,因为Director只处理入站方向的请求,响应流量完全不经过它;缺点是要求Director和Real Server必须在同一个二层广播域内,且Real Server要支持配置VIP和修改MAC地址。如果你的机房网络可以满足这两个条件,DR模式基本上就是首选。
2.3 Tunnel模式:跨网段的IP封装转发
Tunnel模式又叫IPIP隧道模式,它解决的是DR模式跨网段能力不足的问题。它的做法是:Director收到请求后,在原有的IP包外面再套一层新的IP头,新头部的源IP是Director自己的IP,目标IP是选中的Real Server的IP。这个封装过程叫作IP-in-IP隧道。
Real Server收到这个封装包后,解掉外层IP头,看到内层的目标IP还是VIP,而自己已经在tunl隧道接口上配置了VIP,于是正常处理请求。响应也直接回给客户端,不经过Director。
理解这个模式要抓住一个核心区别:NAT模式是改IP,DR模式是改MAC,Tunnel模式是多套了一层IP头。因为多了这层封装,LVS Tunnel模式可以在物理网络拓扑上跨网段部署,适合做跨机房、跨地域的负载均衡。
代价是:Real Server需要加载ipip内核模块,并配置tunl接口;同时由于封装和解封装本身会带来一定的CPU开销,性能略低于DR模式。另外,很多云厂商的安全组、防火墙会过滤未知协议,IPIP封装在这种环境容易被拦,所以Tunnel模式在自建机房用得更多。
2.4 三种模式怎么选
把三种模式的核心差异整理成一张表,方便你直接对照选型:
| 对比项 | NAT模式 | DR模式 | Tunnel模式 |
|---|---|---|---|
| 后端服务器收获 | 只需要同网段IP,网关指向Director | 必须配置VIP在lo接口,需抑制ARP | 必须配置VIP在tunl接口 |
| Director是否处理响应 | 是,双向经过 | 否,只有请求经过 | 否,只有请求经过 |
| 是否跨网段转发 | 不行,必须同网段(否则网关不生效) | 不行,必须同二层网络 | 可以跨网段 |
| 后端操作系统限制 | 几乎无限制 | 必须支持MAC修改和VIP配置,多数Linux发行版都可以 | 必须支持IPIP隧道 |
| 性能 | 最低,Director容易成为瓶颈 | 最好 | 中等偏上 |
| 适用场景 | 小型集群、后端不便配VIP | 绝大多数同机房高并发场景 | 跨机房、跨地域调度 |
简单来说,如果你在做机房内的负载均衡,默认优先用DR模式;如果后端实在不能配VIP,退而求其次用NAT;如果集群跨机房,再考虑Tunnel。
3. 调度算法:流量分配给谁,算法说了算
LVS的调度算法决定了“新请求到底发给谁”,对负载均衡的均衡效果至关重要。LVS提供了十种算法,我按静态和动态两类来讲。
3.1 静态算法:RR/WRR/DH/SH
静态算法不关心后端服务器的实时负载,只按照固定规则分发。
- RR(Round Robin,轮询):最简单,请求轮流发给每台Real Server。适合后端性能基本一致、请求处理时间差不多的场景。缺点很明显,如果一台服务器配置高、一台配置低,轮询会导致较弱的服务器堆积请求。
- WRR(Weighted Round Robin,加权轮询):给每台Real Server配一个权重值,权重越高的服务器被分配到的请求越多。这个算法弥补了RR不考虑性能差异的问题,但仍然是静态的,不会根据实时连接数调整。
- DH(Destination Hashing,目标地址哈希):对请求的目标地址做哈希计算,把相同目标的请求固定发给同一台Real Server。这个算法最适合使用缓存的后端,因为固定节点可以保证缓存命中率。注意它关注的是目标IP而不是客户端IP。
- SH(Source Hashing,源地址哈希):对客户端IP做哈希计算,同一个客户端的请求总是发给同一台Real Server。它的典型应用场景是保持会话(Session),比如无状态后端的登录状态、购物车信息等。
3.2 动态算法:LC/WLC/SED/NQ/LBLC/LBLCR
动态算法会结合后端服务器的实时状态(主要是活动连接数)来决策,均衡效果更精准。
- LC(Least Connections,最少连接):把新请求发给当前活动连接数最少的Real Server。这个算法比较公平,适合请求处理时间差异较大的场景。它的缺陷是没考虑权重,如果配了不同性能的机器,纯LC会显得不够智能。
- WLC(Weighted Least Connections,加权最少连接):在LC的基础上加入权重因子,开销计算公式大概是
(活动连接数 + 1) / 权重,选取值最小的服务器。WLC是LVS的默认算法,综合表现最好,我也推荐刚上手的朋友直接用这个。 - SED(Shortest Expected Delay,最短期望延迟):基于WLC做了优化,公式是
(活动连接数 + 1) * 256 / 权重。它的思路是不仅看连接数,还要预估计延迟,优先选择延迟预期最低的节点。 - NQ(Never Queue,永不排队):SED的一种变体。它规定:如果所有服务器都有空闲连接,就按轮询分;只有当所有服务器都忙时才用SED公式分配。这个算法能避免“有些服务器已经空闲了,新请求还根据公式分给了别的节点”的尴尬。
- LBLC(Locality-Based Least Connections,基于局部性的最少连接):当后端服务器集群做缓存服务时(比如Squid、Memcached),这个算法会根据请求的目标IP找到上次处理它的那台Real Server;只有那台服务器负载过高时,才会调度到其他节点。它本质上是对DH算法的补充,能在保持缓存命中的同时兼顾负载。
- LBLCR(Locality-Based Least Connections with Replication,带复制的基于局部性最少连接):LBLCR的改进版。不止记录目标IP和一台服务器的映射,而是记录一个目标IP可以对应多个后端服务器,它们互为备份,负载高时可以灵活切换。这个一般用得少,只有大型缓存集群才需要考虑。
3.3 算法选型的几个实操经验
算法没有绝对的最好,只有谁更适配你的场景。我总结几条自己的选型经验:
- 默认集群:后端性能均衡、处理时间差异不大的,直接选WRR或WLC。WLC是默认值,省心。
- 有缓存依赖的后端:要保证相同资源落在同一台节点上,优先考虑DH或LBLC。比如后面挂的是图片缓存服务,命中率高不高直接决定整体性能。
- 需要保持会话:Session没有独立缓存的话,用SH做源地址哈希。不过我建议会话最好外置到Redis,让每一层都可以水平扩展,不要被算法绑住。
- 混合性能节点:选了WRR要看权重比例是否合理;如果感觉权重不好定,直接用WLC让算法自动调节,比人拍脑袋调权重更稳。
4. 部署实操:LVS+Keepalived双机热备集群
理论讲完,上实操。这一部分我以最常见的DR模式为例,带你把一台LVS调度器从零搭起来,并用Keepalived实现双机热备。整套架构是生产级的,可以直接套用。
4.1 架构规划与环境准备
假设我们要搭建一个提供Web服务的LVS集群,画一个实际的地址规划:
| 角色 | 主机名 | IP地址 | 说明 |
|---|---|---|---|
| Director Master | lvs-master | 192.168.1.10 | 主调度器 |
| Director Backup | lvs-backup | 192.168.1.11 | 备调度器 |
| Real Server 1 | web-01 | 192.168.1.20 | 后端Web节点 |
| Real Server 2 | web-02 | 192.168.1.21 | 后端Web节点 |
| VIP | - | 192.168.1.100 | 对外提供的虚拟IP |
操作系统我都用CentOS 7.9,内核3.10自带ip_vs模块,不用额外编译。所有机器都需要在同一个二层网络内,因为DR模式依赖交换机二层通信。
搭建前先做两件事:
第一步,检查Director内核是否支持ipvs:
bash复制modprobe ip_vs
lsmod | grep ip_vs
如果看到ip_vs的模块输出,说明内核已经支持。然后安装ipvsadm管理工具:
bash复制yum install -y ipvsadm keepalived
第二步,确认后端Web服务已启动,这里我建议先在两台Real Server上装好Nginx或Apache,并确保直接访问它们的真实IP能返回正常页面。这是最基础也是最重要的前置条件,别在LVS搭完才发现后端web都没起来。
4.2 调度器安装与Keepalived配置
调度器上我们不直接用ipvsadm写规则(因为重启会丢),而是通过Keepalived统一管理VIP和LVS规则。Keepalived负责两件事:一是通过VRRP协议实现VIP的高可用,二是把虚拟服务器和Real Server的配置加载到内核ip_vs模块。
Master节点的/etc/keepalived/keepalived.conf配置如下:
conf复制! Configuration File for keepalived
global_defs {
notification_email {
admin@example.com
}
smtp_server 127.0.0.1
smtp_connect_timeout 30
router_id LVS_MASTER
vrrp_skip_check_adv_addr
}
vrrp_instance VI_1 {
state MASTER
interface eth0
virtual_router_id 51
priority 150
advert_int 1
authentication {
auth_type PASS
auth_pass 1234
}
virtual_ipaddress {
192.168.1.100
}
}
virtual_server 192.168.1.100 80 {
delay_loop 6
lb_algo wlc
lb_kind DR
nat_mask 255.255.255.255
persistence_timeout 0
protocol TCP
real_server 192.168.1.20 80 {
weight 1
TCP_CHECK {
connect_timeout 10
nb_get_retry 3
delay_before_retry 3
}
}
real_server 192.168.1.21 80 {
weight 1
TCP_CHECK {
connect_timeout 10
nb_get_retry 3
delay_before_retry 3
}
}
}
几个关键参数解释一下:
virtual_router_id 51:VRRP实例号,Master和Backup必须一致,否则无法组成一个虚拟路由器。priority 150:优先级,数值越大越优先成为Master。Backup节点要设成比150小,比如100。advert_int 1:Keepalived每隔1秒发一次VRRP通告。lb_algo wlc:选择我们之前的加权最少连接算法。lb_kind DR:指定转发模式为DR,这个必须和实际模式一致。persistence_timeout 0:持久连接超时时间,0表示不做会话保持。如果你需要同一个客户端IP固定访问同一台RS,可以设成300之类,但副作用是流量可能不均,我一般默认设0。TCP_CHECK:健康检查方式,Keepalived每6秒(delay_loop)尝试连接一次后端服务器的80端口,连不上就自动摘除这台RS,恢复后自动加回来。
Backup节点的配置和Master几乎一样,只需要改两处:
conf复制state BACKUP
priority 100
配置完,在两台Director上分别启动Keepalived服务:
bash复制systemctl enable keepalived
systemctl start keepalived
启动后,在Master上执行 ip addr show,应该能看到VIP 192.168.1.100已经绑定在eth0上;如果Master宕机,VIP会漂移到Backup上。
4.3 后端Real Server的关键配置(DR模式)
DR模式下Real Server的配置是整个部署里最容易出错的地方,也是新手踩坑最多的环节。这一步的目标有两个:给Real Server的lo接口绑定VIP,并让它不能对外应答这个VIP的ARP请求。
先写一个配置脚本,直接在Web节点上执行:
bash复制#!/bin/bash
VIP=192.168.1.100
# 绑定VIP到回环接口
ifconfig lo:0 $VIP netmask 255.255.255.255 up
route add -host $VIP dev lo:0
# 抑制ARP应答
echo "1" > /proc/sys/net/ipv4/conf/lo/arp_ignore
echo "2" > /proc/sys/net/ipv4/conf/lo/arp_announce
echo "1" > /proc/sys/net/ipv4/conf/all/arp_ignore
echo "2" > /proc/sys/net/ipv4/conf/all/arp_announce
注意几个细节:
netmask 255.255.255.255:这里的掩码必须写全四个255,表示VIP只属于本机回环接口,不会干扰其他网段的通信。很多教程这里写写成24位掩码,会导致路由混乱,直接影响转发。arp_ignore = 1:只回答目标IP是本网络接口IP的ARP请求。这样Real Server不会响应针对VIP 192.168.1.100的ARP查询。arp_announce = 2:对外发送ARP通告时,始终使用与目标地址最匹配的本地地址。配合上面的ignore,让Real Server在局域网内“隐身”,不去抢VIP。
这两条sysctl参数是临时的,重启失效。如果想永久生效,把参数写入/etc/sysctl.conf,然后用sysctl -p加载。
做完这一步,可以分别在Real Server上用 ip addr show lo 确认VIP已经绑定。
4.4 功能验证与压测
配置完成后,先做基础验证。在客户端机器上:
bash复制curl -I http://192.168.1.100
多执行几次,应该能看到响应。为了确认请求真的被分发到了不同Real Server,可以临时在每台后端的Nginx首页写上不同的标识,比如“This is web-01”。如果反复curl VIP能看到两个不同标识轮流出现,说明LVS转发正常。
再在LVS Master上查看连接转发情况:
bash复制ipvsadm -Ln
ipvsadm -Lnc
第一条命令查看当前配置的虚拟服务器和RS状态,后端节点前面显示Route表示DR模式,状态ActiveConn和InActConn能直观看到每台RS的实时连接数。第二条命令查看当前活跃的连接表,能看到客户端IP、VIP、选中的RS以及连接状态。
压测推荐用ab或wrk。以ab为例:
bash复制ab -n 100000 -c 1000 http://192.168.1.100/
压测过程中同时观察ipvsadm -Ln的输出,你会看到连接在web-01和web-02之间不断分配,且wlc算法下连接数大致均匀。如果发现某台机器始终没有流量,优先检查这台RS的ARP抑制参数和VIP绑定时否正确。
5. 常见问题与排查技巧实录
5.1 问题速查表
结合我自己的实战,把最常遇到的问题整理成了速查表:
| 现象 | 可能原因 | 排查命令/解决办法 |
|---|---|---|
| 客户端ping不通VIP | Keepalived未启动或VIP未绑定;ARP抑制配置错误 | ip addr show看VIP是否存在;检查systemctl status keepalived |
| curl VIP超时,但直连RS正常 | Director或RS的防火墙拦截;Keepalived健康检查把RS摘除 | 检查Director和RS的iptables规则,放行VIP的80端口;看ipvsadm -Ln里RS状态是不是显示不可用 |
| 请求只到一台RS | RS的ARP抑制未配置好,其中一台抢答了ARP;调度算法选错 | 在抢答的RS上重新执行ARP抑制脚本;检查arp_ignore/arp_announce参数 |
| 压测时LVS Master网卡流量暴涨 | 响应走了回包路径,通常是DR模式配置不对,响应经过Director | 检查Real Server的默认网关和路由,DR模式不应该走Director |
| Master宕机后VIP不漂移 | backup的priority设置不对或VMAC冲突 | 确认Backup的priority小于Master;确认两台机器的virtual_router_id一致 |
| 后端连接数严重不均 | 权重配置不合理;长连接场景选了RR等静态算法 | 检查weight设置;改用WLC;确认没有persistence_timeout干扰 |
5.2 排查思路与方法论
LVS出问题,我一般按照“链路五层”的方法排查:从IP层开始,再到ARP、路由、调度、后端服务。
第一步,确认VIP和Director本身。先在Master上执行ip addr,确认VIP存在;再用curl --interface或ping从客户端测VIP,确认基本可达性。如果VIP丢了,直接查Keepalived的日志:journalctl -u keepalived -f。
第二步,确认ARP和二层链路。在RS上执行arping -I eth0 -c 3 192.168.1.100,观察是否有回应。如果RS回复了VIP的ARP请求,说明ARP抑制没配好,立刻重新设置sysctl参数。
第三步,确认内核转发规则。用ipvsadm -Ln查看配置,核对VIP、端口、算法、模式是否和预期一致。特别注意lb_kind是否为DR,如果手滑配成NAT,请求方向可能直接不通。
第四步,确认健康检查正常。Keepalived通过TCP_CHECK探活,如果RS的防火墙拦了来自Director的探测,RS会被标记为不可用,流量就不会转发过去。这一步最容易背锅,所以我建议在RS上先把88等管理端口、80等业务端口全部放行,等整体通了再收紧防火墙规则。
5.3 独家避坑经验
最后分享几个常规文档里不会写的细节经验,都是我踩过的坑:
关于AOP和软连接的联想,虽然热搜词里有不少“aop原理”“lvs软连接”之类的内容,但我想提醒大家,LVS的转发不是软连接那种逻辑关系,它是完全在内核态做的真实数据包转发,别被概念混淆。LVS的“虚拟服务器”指的是对外表现一致的一个虚拟IP,而不是某种应用层软链接。
关于Keepalived的健康检查间隔,delay_loop默认5秒,我经常看到有人为了“及时”把间隔改成1秒。这么做其实没必要,反而会因网络抖动导致RS被频繁摘除。一般3~6秒比较合理,业务方真超过6秒无响应,说明后端本身已经出问题了,摘除晚几秒影响不大。
关于修改内核arp参数的顺序,一定要先设置/proc/sys/net/ipv4/conf/all/下的参数,再设置/proc/sys/net/ipv4/conf/lo/下的参数,并且all和lo两个都要设置。很多人只改了all,导致实际生效的是lo接口的默认值,VIP照样被应答,流量调度瞬间失效。
关于压测时吞吐上不去,先检查Director的网卡中断是否均衡。如果所有中断都落在同一个CPU核上,即使内核转发再快,单核瓶颈也会拖垮整体性能。可以开启RPS(Receive Packet Steering),把软中断分散到多核,压测结果会有明显提升。
我个人的经验是,LVS部署本身不难,难点全在细节。DR模式下的ARP抑制、Keepalived的探活配置、内核参数的持久化,这三样只要有一处疏忽,线上就会出幺蛾子。所以生产环境改完配置,一定要先在小流量下观察几分钟,确认转发正常再切入全量流量,稳妥永远是第一位的。
