☰
企业级LVS负载均衡实战:架构选型、高可用部署与性能调优
2026/10/14 11:48:39 网站建设 项目流程

1. 企业级流量入口的架构选型思考

1.1 为什么负载均衡是绕不开的第一道坎

做后端架构这些年,我越来越觉得负载均衡是整个系统里最容易被低估、却又最不能出错的一环。业务代码写崩了,大不了回滚一个版本;数据库慢查询了,加个索引还能救;但负载均衡这一层要是出了问题,那就是整个服务入口直接瘫痪,所有下游节点全部失联,用户端看到的就是白屏或者502。这种故障的杀伤力,跟单点服务挂掉完全不是一个量级。

LVS(Linux Virtual Server)在国内互联网公司的普及率非常高,尤其是那些日活千万级以上的业务,几乎都能看到它的身影。原因很直接:它是基于内核态的四层转发,性能损耗极低,单台机器扛几十万并发连接是常规操作。相比Nginx这种七层代理,LVS不解析应用层协议,只做IP和端口的转发决策,所以它的吞吐能力要高出好几个数量级。当然代价就是功能相对"朴素",不能做URL路由、不能改Header、不能做SSL卸载,这些活儿得交给后端的七层代理或者应用本身去处理。

这篇文章我想聊的是,怎么把LVS真正用起来,不是那种"装个ipvsadm敲两条命令就完事"的玩具级演示,而是企业环境里需要考虑高可用、会话保持、健康检查、内核调优、故障切换的完整方案。适合已经有一定Linux基础、正在搭建或者优化自己服务入口的运维和后端同学。如果你还在用单台Nginx扛所有流量,或者对"四层"和"七层"的区别只有模糊概念,那这篇内容应该能帮你把思路理清楚。

1.2 四层和七层到底差在哪里

很多人一开始会纠结:既然Nginx也能做负载均衡,为什么还要多引入一层LVS?这个问题我在不同团队里被问过不下十次。核心答案就一个字:性能。但这个"性能"背后涉及的东西值得展开说。

四层负载均衡工作在传输层,它只看数据包的源IP、目标IP、源端口、目标端口,然后根据调度算法决定把这个包转发给哪台后端服务器。整个过程在内核空间完成,不需要把数据从内核态拷贝到用户态,也不需要建立完整的TCP连接再转发。你可以把它想象成一个非常聪明的邮局分拣员,只看信封上的地址就把信扔到对应的邮筒里,根本不拆开看里面写了什么。

七层负载均衡则工作在应用层,它需要先和客户端建立完整的TCP连接,然后解析HTTP请求,根据URL、Header、Cookie等信息做转发决策。这个过程涉及大量的用户态和内核态之间的数据拷贝,还要维护连接状态,所以单机性能天花板要低得多。但它的优势在于灵活,能做基于路径的路由、能做灰度发布、能改写请求内容。

企业里的常见做法是两者配合:LVS在最前面做四层转发,把流量分给一组Nginx,Nginx再做七层处理转发给真正的应用服务器。这样LVS扛住了海量连接和DDoS攻击的第一波冲击,Nginx专注于业务层的灵活路由。这个架构在电商大促、直播活动这种流量尖峰场景下特别管用。

1.3 三种转发模式的取舍逻辑

LVS支持三种主要的转发模式:NAT、DR(Direct Routing)和TUN(IP Tunneling)。这三种模式的选择直接决定了你的网络拓扑和性能上限,必须在一开始就想清楚。

NAT模式最简单,但性能最差。它的原理是LVS修改请求包的目标IP为后端服务器IP,后端处理完再把响应包发回LVS,由LVS改回源IP返回给客户端。问题在于所有响应流量都要经过LVS,LVS成了瓶颈,而且后端服务器需要把网关指向LVS。这种模式适合小规模场景,比如后端只有几台机器、流量不大的内部系统。

DR模式是生产环境用得最多的。它的巧妙之处在于:LVS只修改请求包的MAC地址,把包转发给后端,后端处理完后直接把响应包发给客户端,不经过LVS。这样LVS只处理入站流量,出站流量由后端自己搞定,吞吐能力大幅提升。代价是LVS和后端必须在同一个二层网络里,而且后端服务器需要在回环接口上配置VIP,并且抑制ARP响应,否则会跟LVS抢VIP。

TUN模式适合跨机房场景,LVS把请求包封装在IP隧道里发给后端,后端解封装后处理,响应直接返回客户端。这种模式支持后端和LVS不在同一网段,但需要后端支持IP隧道协议,而且多了一层封装解封装的开销。

我个人的经验是:同机房内优先用DR,跨机房考虑TUN,NAT只在测试环境或者极简场景下用。下面这张表可以帮你快速对比:

对比维度NAT模式DR模式TUN模式
性能低高中
网络要求后端网关指向LVS同一二层网络支持IP隧道
响应路径经过LVS直接返回客户端直接返回客户端
端口映射支持不支持支持
适用场景小规模测试同机房生产跨机房部署

2. 核心组件与调度算法深度拆解

2.1 ipvsadm与内核模块的配合机制

LVS的核心其实分两部分:内核里的IPVS模块和用户空间的ipvsadm工具。IPVS模块负责实际的数据包处理和转发决策,ipvsadm则是我们用来配置和管理转发规则的工具。理解这个分工很重要,因为很多"配置了不生效"的问题,根源就在于内核模块没加载或者版本不匹配。

在开始配置之前,第一件事是确认内核是否支持IPVS。大部分主流发行版的内核都默认编译了IPVS模块,但有些精简版或者定制内核可能没有。你可以用modprobe ipvs尝试加载,然后用lsmod | grep ip_vs确认。如果加载失败,可能需要重新编译内核或者安装对应的内核模块包。

ipvsadm的配置逻辑围绕三个概念展开:虚拟服务(Virtual Service)、真实服务器(Real Server)和调度算法。虚拟服务就是你对外暴露的VIP和端口,真实服务器就是后端实际处理请求的节点。一条典型的配置命令长这样:

ipvsadm -A -t 192.168.1.100:80 -s wrr ipvsadm -a -t 192.168.1.100:80 -r 192.168.1.101:80 -g -w 100 ipvsadm -a -t 192.168.1.100:80 -r 192.168.1.102:80 -g -w 100

第一行是添加虚拟服务,-t指定TCP协议和VIP端口,-s wrr指定加权轮询算法。后面两行是添加真实服务器,-g表示DR模式,-w是权重。这些命令看起来简单,但每一条背后都有讲究,比如权重怎么定、算法怎么选,后面会详细说。

2.2 调度算法的选择不是拍脑袋

LVS提供了十几种调度算法,但实际生产环境常用的就那么几种。选错了算法,轻则负载不均,重则某些后端被打爆而其他后端闲着。我把常用的几种列出来,结合场景说说怎么选。

轮询(RR)是最简单的,请求依次分给每台后端。适合后端配置完全一致、处理能力相同的场景。但现实中很少有完全一致的机器,所以纯轮询用得不多。

加权轮询(WRR)在轮询基础上加了权重,权重高的分到的请求多。这个权重需要根据后端的CPU、内存、带宽来定。我一般会先给一个初始权重,然后观察一段时间的实际负载再调整。比如两台机器配置是8核16G和4核8G,权重可以设成2:1,但实际可能设成3:1更合适,因为性能不是线性关系。

最少连接(LC)把新请求分给当前连接数最少的后端。这个算法在请求处理时间差异大的场景下表现很好,因为它能动态感知后端的忙闲程度。但有个坑:如果某台后端因为慢查询导致连接堆积,LC会暂时不再给它新请求,等它慢慢消化,这其实是好事。但如果所有后端都堆积了,LC也救不了。

加权最少连接(WLC)是LC的加权版本,也是我实际用得最多的算法。它在连接数的基础上除以权重,相当于认为权重高的机器能承受更多连接。公式是(active_conns * 256 + inactive_conns) / weight,值最小的后端获得新请求。这个算法在异构集群里表现很稳。

源地址哈希(SH)根据客户端IP做哈希,同一个IP的请求总是落到同一台后端。这个算法主要用于会话保持,但有个明显缺陷:如果大量客户端经过同一个NAT网关出来,它们的源IP相同,就会全部落到同一台后端,导致负载严重倾斜。所以SH只适合客户端IP分散的场景。

目标地址哈希(DH)根据目标IP做哈希,主要用于后端是缓存服务器的场景,保证同一份缓存数据总是落在同一台机器上。

算法适用场景注意事项
RR后端配置完全一致实际很少用
WRR后端配置有差异权重需动态调整
LC请求处理时间差异大动态感知忙闲
WLC异构集群通用生产首选
SH需要会话保持NAT场景慎用
DH缓存服务器集群保证缓存命中

2.3 会话保持的几种实现路径

会话保持是负载均衡里绕不开的话题。用户登录后,后续请求必须落到同一台后端,否则session丢了就得重新登录。LVS本身是四层转发,它不理解HTTP协议,所以不能像Nginx那样基于Cookie做会话保持。但LVS提供了几种替代方案。

第一种是前面提到的源地址哈希(SH)算法。配置简单,但NAT场景下会出问题。而且如果后端某台机器挂了,那部分用户的session就丢了,需要重新登录。

第二种是会话共享,把session存到Redis或者数据库里,后端无状态。这是最彻底的方案,也是我推荐的做法。虽然引入了一个新的依赖,但它解决了会话保持的根本问题,后端可以随意扩缩容,不用担心session丢失。

第三种是在LVS后面加一层Nginx,由Nginx基于Cookie做会话保持。这样LVS只管四层转发,Nginx处理七层的会话逻辑。这个方案兼顾了性能和灵活性,但架构复杂度增加了。

第四种是持久连接模板,LVS可以配置在一定时间内,同一源IP的请求都转发到同一台后端。这个跟SH类似,但可以设置超时时间。配置命令是ipvsadm -p 600,表示600秒内的同一源IP请求都走同一后端。

提示:会话保持方案的选择取决于你的业务对session丢失的容忍度。金融类业务通常要求session绝对不丢,那就必须用共享存储方案;普通资讯类业务,偶尔重新登录用户也能接受,用SH或者持久连接模板就够了。

3. 高可用架构与实操部署全流程

3.1 Keepalived+LVS的双机热备方案

单台LVS本身就是单点,它挂了整个服务就没了。所以生产环境必须做高可用,最常见的方案是Keepalived+LVS双机热备。Keepalived通过VRRP协议实现VIP的漂移,主节点正常时持有VIP,主节点故障时备用节点接管VIP,整个过程对客户端透明。

这个方案的原理说起来简单,但配置细节很多。首先是VRRP的优先级设置,主节点优先级要高于备用节点,比如主150备100。然后是抢占模式和非抢占模式的选择:抢占模式下,主节点恢复后会抢回VIP;非抢占模式下,主节点恢复后不抢,VIP继续留在备用节点。我一般用非抢占模式,避免VIP频繁漂移导致连接中断。

Keepalived的配置文件主要分三块:global_defs、vrrp_instance和virtual_server。global_defs里配置路由ID和通知脚本;vrrp_instance定义VRRP实例,包括状态、接口、优先级、认证方式;virtual_server定义LVS的转发规则,包括VIP、端口、调度算法和真实服务器列表。

一个容易踩的坑是防火墙。VRRP协议用的是组播地址224.0.0.18,如果防火墙没放行,主备之间无法通信,会导致双主(两台都认为自己是主)的严重问题。所以配置之前一定要确认防火墙规则,或者直接关掉防火墙(内网环境)。

另一个坑是Keepalived的健康检查。默认的健康检查是TCP连接检查,但有些服务TCP端口开着但应用已经假死了,这时候需要更精细的检查,比如HTTP状态码检查或者自定义脚本检查。Keepalived支持配置MISC_CHECK来执行自定义脚本,脚本返回0表示健康,返回非0表示故障。

3.2 DR模式后端服务器的ARP抑制配置

DR模式有一个必须处理的细节:后端服务器需要在回环接口上配置VIP,但同时又不能让外界感知到这个VIP,否则会跟LVS抢流量。解决办法是配置ARP抑制。

具体来说,需要修改两个内核参数:

# 忽略来自其他接口的ARP请求 echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore # 使用最合适的源地址响应ARP请求 echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce

然后在回环接口上配置VIP:

ifconfig lo:0 192.168.1.100 netmask 255.255.255.255 up

这里有个细节:netmask必须设成255.255.255.255,不能设成255.255.255.0。因为如果设成后者,后端会认为VIP所在的网段是直连的,可能会发出ARP请求,导致网络混乱。

这些配置需要持久化,否则重启后就失效了。可以把它们写到/etc/sysctl.conf和网络配置脚本里。我见过不少团队在测试环境配好了,上线后重启服务器发现VIP没了,排查半天才发现是没做持久化。

3.3 完整部署流程与验证方法

下面我把DR模式+LVS+Keepalived的完整部署流程梳理一遍。假设你有两台LVS节点(主备)和两台后端服务器,VIP是192.168.1.100。

第一步:LVS节点安装软件

yum install -y ipvsadm keepalived

第二步:配置Keepalived

主节点配置文件/etc/keepalived/keepalived.conf:

global_defs { router_id LVS_MASTER } 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 persistence_timeout 300 protocol TCP real_server 192.168.1.101 80 { weight 100 TCP_CHECK { connect_timeout 3 nb_get_retry 3 delay_before_retry 3 } } real_server 192.168.1.102 80 { weight 100 TCP_CHECK { connect_timeout 3 nb_get_retry 3 delay_before_retry 3 } } }

备用节点的配置类似,只需要改state为BACKUP,priority改为100,router_id改为LVS_BACKUP。

第三步:后端服务器配置

# 配置ARP抑制 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 # 配置VIP到回环接口 ifconfig lo:0 192.168.1.100 netmask 255.255.255.255 up

第四步:验证

在主节点上执行ipvsadm -L -n,应该能看到虚拟服务和真实服务器的列表。然后用curl访问VIP,观察请求是否被分发到不同的后端。可以临时停掉一台后端,看LVS是否自动把它剔除。

注意:测试的时候一定要用不同的客户端IP去访问,否则因为持久连接的原因,所有请求都会落到同一台后端,你会误以为负载均衡没生效。

4. 生产环境常见故障与排查实录

4.1 后端服务器全部下线但服务正常

这个问题听起来矛盾,但确实发生过。现象是ipvsadm -L显示所有真实服务器都是inactive状态,但用户访问却正常。排查后发现,是健康检查的TCP_CHECK配置有问题,检查端口写错了,导致LVS认为后端都挂了,但实际上后端服务是正常的。

还有一种可能是健康检查频率太高,后端服务器因为并发连接数限制拒绝了检查请求,LVS误判为故障。解决办法是调整delay_loop和connect_timeout参数,给后端足够的响应时间。

4.2 VIP漂移后旧连接不释放

Keepalived做VIP漂移时,已经建立的连接不会立即断开,而是会继续走原来的路径。如果主节点已经挂了,这些连接就会超时。对于长连接业务(比如WebSocket),这个问题尤其明显。

解决办法是在Keepalived的notify脚本里,在节点变成BACKUP时主动清理IPVS的连接表:

#!/bin/bash if [ $3 == "BACKUP" ]; then ipvsadm -C fi

这个脚本在节点状态变为BACKUP时执行,清空所有转发规则和连接表,强制客户端重新建立连接。

4.3 调度不均导致部分后端过载

WRR和WLC算法都依赖权重配置,如果权重设置不合理,就会出现部分后端过载。我遇到过一个案例:两台后端配置相同,权重也相同,但其中一台的负载明显高于另一台。排查后发现是持久连接导致的,因为测试时用的同一个客户端IP,所有请求都落到了同一台。

生产环境里,如果发现调度不均,首先要确认是不是持久连接或者SH算法导致的。如果是,考虑改用WLC算法并关闭持久连接。如果确实是权重问题,根据实际负载调整权重。我一般会观察CPU使用率和连接数两个指标,CPU高的降权重,连接数多的降权重。

4.4 常见问题速查表

问题现象可能原因排查方法解决方案
VIP无法访问Keepalived未启动检查进程和日志启动Keepalived
后端全部inactive健康检查配置错误检查端口和超时修正检查配置
负载不均持久连接或SH算法查看连接分布改用WLC算法
双主现象VRRP通信失败检查防火墙和组播放行VRRP协议
响应慢后端性能瓶颈查看后端负载调整权重或扩容
VIP漂移后连接超时旧连接未清理检查notify脚本添加清理逻辑

4.5 内核参数调优的几个关键点

LVS的性能很大程度上取决于内核参数。默认参数适合通用场景,但高并发下需要调整。以下几个参数我每次部署都会检查:

net.ipv4.ip_forward必须设为1,否则LVS无法转发数据包。这个是最基础的,但有时候系统默认是0,忘了改就会导致转发失败。

net.ipv4.vs.conn_reuse_mode控制连接复用模式。默认是1,表示允许复用TIME_WAIT状态的连接。在高并发短连接场景下,这个参数能显著提升性能。但如果遇到端口耗尽的问题,可以尝试设为0。

net.ipv4.vs.expire_nodest_conn设为1时,如果后端服务器不可达,LVS会立即把连接转发到其他后端,而不是等待超时。这个参数能提升故障切换的速度。

net.ipv4.vs.schedule_icmp_error控制是否响应ICMP错误。一般设为0,避免ICMP错误影响转发决策。

这些参数可以通过sysctl -w临时修改,也可以写到/etc/sysctl.conf持久化。修改后需要重启IPVS或者重新加载配置才能生效。

5. 性能压测与容量规划经验

5.1 压测工具的选择与使用

LVS的性能压测跟普通服务不太一样,因为它本身不处理业务逻辑,所以压测的重点是转发能力和连接建立速度。常用的工具有ab、wrk、hey,但我更推荐用wrk,因为它支持多线程和长连接,能更好地模拟真实场景。

压测的时候要注意几点:一是压测客户端不能跟LVS在同一台机器上,否则会互相影响;二是要监控LVS的CPU和内存使用率,找到瓶颈点;三是要观察后端的负载是否均衡,如果后端先扛不住了,那瓶颈就不在LVS。

我一般会做几轮压测:第一轮用短连接,测连接建立速度;第二轮用长连接,测吞吐量;第三轮模拟故障,测切换速度。每轮压测都要记录关键指标,形成基线数据,方便后续对比。

5.2 容量估算的实用方法

LVS的容量估算主要看两个指标:并发连接数和每秒新建连接数。并发连接数取决于内存,每个连接大约占用几百字节的内核内存。每秒新建连接数取决于CPU,单核大约能处理几万到十几万的新建连接。

假设你的业务峰值是每秒10万请求,平均每个请求处理时间100毫秒,那么并发连接数大约是1万。这个量级单台LVS轻松搞定。但如果每秒新建连接数是10万,那就需要多核CPU,因为新建连接是CPU密集型操作。

我的经验是:单台4核8G的LVS,用DR模式,大约能扛住50万并发连接和每秒20万新建连接。当然这个数字跟具体的业务场景和内核参数有关,建议在实际环境中压测验证。

5.3 扩容与缩容的操作要点

扩容后端服务器时,直接在后端配置好服务,然后在LVS上执行ipvsadm -a添加即可。但要注意,新加的后端需要先预热,不要一上来就给满权重。我一般先给10%的权重,观察几分钟,确认没问题再逐步加到正常权重。

缩容时,先把要下线的后端权重设为0,等现有连接处理完,再执行ipvsadm -d删除。直接删除会导致正在处理的请求中断,用户体验很差。

LVS节点本身的扩容比较麻烦,因为涉及到VIP的漂移和VRRP的重新选举。一般不建议频繁扩缩LVS节点,而是通过增加后端来提升整体容量。如果LVS确实成了瓶颈,可以考虑用DNS轮询做多组LVS的负载均衡。

6. 个人实操体会与后续扩展方向

6.1 踩过几次坑之后的几点体会

第一,配置文件一定要版本管理。Keepalived的配置文件改错了,可能导致VIP漂移或者转发规则丢失。我现在的做法是把配置文件放到Git里,每次修改都提交,出问题了直接回滚。

第二,监控比配置更重要。LVS本身不产生日志,出问题了很难排查。所以一定要配置监控,监控VIP的可达性、后端服务器的健康状态、连接数的变化趋势。我一般会用脚本定期执行ipvsadm -L -n并把结果推送到监控系统。

第三,测试环境要尽量模拟生产。我见过太多团队在测试环境用NAT模式,生产环境用DR模式,结果上线后各种问题。测试环境应该跟生产环境保持一致的架构和配置,哪怕规模小一点。

第四,不要忽视文档。LVS的配置涉及网络、内核、应用多个层面,时间长了很容易忘记当初为什么这么配。我习惯在配置文件里写注释,说明每个参数的含义和调整原因,方便自己和同事后续维护。

6.2 这个架构还能怎么扩展

LVS+Keepalived的方案已经能满足大部分场景,但如果业务继续增长,可以考虑几个扩展方向。一是引入ECMP(等价多路径路由),用多台LVS同时持有同一个VIP,通过路由器的ECMP能力做负载均衡,这样LVS层也能水平扩展。二是结合DPDK或者XDP技术,把转发性能再提升一个数量级,不过这个对技术栈要求比较高。三是把LVS容器化,用Kubernetes的Service或者Ingress来管理,不过容器网络跟LVS的配合还有一些细节需要处理。

最后分享一个小技巧:如果你不确定调度算法选哪个,先用WLC跑一段时间,观察后端的负载分布。如果发现某台后端明显偏忙,再考虑调整权重或者换算法。不要一开始就追求完美配置,实际运行数据比理论计算靠谱得多。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询