资讯动态

LVS负载均衡实战:DR模式部署与Keepalived高可用全解析

发布时间:2026/9/18 6:15:26 来源:尧图企业网站定制
直接给你结论如果你的服务需要扛住高并发、多节点横向扩展又不想在负载均衡这一层花费太多商业软件授权费LVSLinux Virtual Server会是一个非常值得花时间研究的东西。我在生产环境里摸爬滚打过几年从最早用Nginx做七层转发到后来业务量上来之后被连接数打爆才真正沉下心把LVS这套方案啃透。这篇文章不打算讲那些从入门到放弃的官方手册也不做概念复读机。我按照自己实际部署时的思考路径把这个方案拆成几个部分它到底解决什么问题、三种工作模式怎么选、部署时每一条命令背后是什么意图、以及最关键的——为什么有时候你配置看起来全对但就是转发不了。最后我会把生产环境里踩过的坑和压测数据一并放出来供你参考。1. 为什么业务量上来之后我转向了LVS方案很多人一开始接触负载均衡接触到的都是Nginx或者HAProxy这类软件。它们确实好用配置直观社区资料也多。但当并发连接数到一定量级事情就开始起变化。Nginx工作在七层也就是HTTP层。它需要完整接收请求、解析头部信息、再根据location规则或者upstream配置做出转发决策。这个流程带来的直接代价是每一条连接都要经过用户态协议栈、应用层逻辑处理、再回到内核态转发出去。连接数少时无所谓一旦达到几十万甚至上百万并发光是维护这些连接状态就会占满CPU时间片。LVS不一样。它的全称是Linux Virtual Server核心工作位置在内核空间通过Netfilter框架挂载钩子函数直接对数据包做转发处理。它不关心你传输的是什么协议内容、不解析HTTP头部它只认IP和端口基于四层做转发。相当于你家里的智能门锁和小区保安的区别智能门锁认卡就放行快保安还要问你找谁、登记、再放行安全但慢。我用一组压测数据说明问题。同一台4核8G的云主机使用Nginx做HTTP负载均衡极限QPS大概在4万到6万同样的硬件换上LVS做DR模式的TCP转发仅转发层就能跑到40万以上的连接处理能力。这个差距不是靠调参能追回来的这是工作层级决定的。还有一个被很多人忽略的点LVS本身并不需要维护每一条连接的完整状态。在DR模式下它只改数据包的MAC地址就重新扔回网络返回流量由后端服务器直接发给客户端不需要再绕回负载均衡器。也就是说负载均衡器的带宽压力会大幅下降它只承担入站流量的负担。正是因为这一点一台普通的LVS节点能扛住非常大的流量规模瓶颈往往在网卡而不在服务本身。我当时做的决策很简单四层的事情交给四层工具去办七层的东西留给Nginx去办。LVS负责流量入口把请求均匀散给后端的Nginx集群Nginx再根据业务规则做路径分发、缓存、限流。这套架构至今依然是我向团队推荐的默认方案。2. 三种工作模式的选择逻辑NAT、DR、Tunnel到底怎么挑第一次接触LVS的人最容易被三种工作模式绕晕。先别去背区别表格先理解一个最核心的问题数据包怎么去、怎么回。2.1 NAT模式最直观但最容易让负载均衡器变瓶颈NAT模式很好理解。客户端把请求发给负载均衡器负载均衡器把目标IP改成后端某台真实服务器的IP转发过去后端处理完再把响应发回负载均衡器由它把源IP改回VIP然后回给客户端。这套逻辑天然有个致命限制所有进出流量都要经过负载均衡器。响应包如果比较大比如图片、视频、大文件接口回程带宽会直接把负载均衡器的网卡塞满。我用一个简单比喻小区只有一个大门上下班高峰所有人都挤这一个门进出那门就是整个小区的通行瓶颈。所以NAT模式只适合后端服务本身响应体积很小的场景比如短小的API请求、验证码服务、内部管理系统这种流量规模可控、响应体量小的业务。还有一点要注意NAT模式下后端服务器需要把默认网关指向负载均衡器的内网IP否则响应包发出去之后没法回到负载均衡器手里。这个细节在部署时非常容易漏漏掉之后表现就是请求偶尔通、经常不通非常折磨人。2.2 DR模式生产环境里的绝对主力DR全称是Direct Routing中文一般叫直接路由模式。它的核心思路是客户端请求到达负载均衡器后它只修改数据链路层的目的MAC地址把数据包重新广播到同一物理网段内由真实服务器直接处理。真实服务器处理完之后直接把响应包通过自己的网卡发回客户端完全不经过负载均衡器。这就要求负载均衡器和所有真实服务器在同一个物理二层网络里而且每台真实服务器的回环接口上都要绑定一个VIP地址同时关闭对这个VIP的ARP通告。这样才能保证客户端请求到达负载均衡器时后端服务器不会抢答而负载均衡器把目标MAC改掉后后端服务器又能正常接收和处理。我生产环境里几乎全部用了DR模式。原因就一个字省。负载均衡器只承载一半流量后端服务器直接把响应吐给客户端整个链路没有多余的转发跳数延迟也压到了最低。延迟和吞吐量这两项指标DR模式都是三种模式里最优的。2.3 Tunnel模式跨机房分布式架构的备选方案Tunnel模式又叫做IP封装模式。它的原理是在原始数据包外面再包一层新的IP头通过隧道把请求发给在不同网段的后端服务器。最大的价值在于解决了DR模式要求二层网络的问题后端服务器可以和负载均衡器跨机房、跨网段部署。但一个容易踩的坑是后端服务器必须支持IP隧道协议而且在Linux上需要加载ipip模块。很多云主机默认内核里没有编译这个模块或者云厂商的安全组不放开IP协议号4IPIP协议导致隧道根本建立不起来。所以Tunnel模式看着美好落地时依赖的底层条件反而更多。我的建议很直接同一机房场景优先DR模式只有当你确实有多地多机房容灾需求而且底层网络可控、操作系统内核可调的时候才考虑Tunnel模式。NAT模式我一般只推荐给学习实验用或者网络环境被限制死、只有单网卡可用的情况。三种模式的对比我整理成一个表方便你保存对比维度NAT模式DR模式Tunnel模式工作位置网络层改IP数据链路层改MAC网络层IP封装后端服务器要求网关指向负载均衡器回环接口绑定VIP关闭ARP支持IPIP隧道协议是否支持跨网段支持不支持必须在同一二层支持回程流量必须经过负载均衡器服务器直连客户端服务器直连客户端后端操作系统无特殊要求以Linux为主必须支持隧道协议性能一般最好良好典型场景小规模API转发高并发读多写少业务跨机房容灾3. 一台负载均衡器的完整落地过程从安装部署到调度策略3.1 基础架构规划VIP、DIP与RIP的映射关系先约定几个术语不然下面讲命令你会对不上号。VIP是虚拟IP地址也就是客户端访问的入口地址对外唯一暴露。DIP是负载均衡器自身的物理网卡IP。RIP是后端真实服务器的IP地址。我以一主一备双节点、后端三台Web服务器为例规划如下角色主机名IP地址说明LVS主节点lvs-master192.168.1.10DIP负责VIP承载和转发LVS备节点lvs-backup192.168.1.11DIPVRRP热备主节点故障时接管VIPVIP-192.168.1.100客户端真正访问的地址Web服务器1web-01192.168.1.21RIP回环接口绑定VIPWeb服务器2web-02192.168.1.22RIP回环接口绑定VIPWeb服务器3web-03192.168.1.23RIP回环接口绑定VIP这套结构里客户端永远只知道192.168.1.100这个地址。它不关心后面有几台服务器、流量怎么分配、服务器是否健康这些全部由LVS集群负责。3.2 内核参数调优为什么ARP问题必须最先处理在配置LVS之前必须先处理ARP问题。特别是DR模式下后端服务器的回环接口绑定了VIP如果不做任何限制当客户端在同一个局域网内发起对VIP的ARP请求时后端服务器和负载均衡器都会应答客户端拿到的MAC地址可能是任何一台服务器流量直接就散乱了。解决这个问题的方法是调整Linux内核参数让服务器对来自外部网卡的ARP请求不响应VIP地址只对内部配置的RIP网卡做正常响应。具体要修改/etc/sysctl.conf增加以下内容net.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 2arp_ignore定义的是收到ARP请求时的应答策略。设为1表示只回答目标IP地址是本接口上配置的地址的请求。arp_announce定义的是发送ARP请求时的源地址选择策略。设为2表示总是使用最合适的本地地址作为ARP请求的源地址这样能确保外部看到的VIP通告只来自负载均衡器。修改完成后用sysctl -p重新加载。我对每一台新增的后端服务器都会在初始化脚本里直接写入这两条配置避免哪天手工部署时忘记。3.3 ipvsadm命令实战用一套脚本构建转发规则LVS本身是内核模块操作它的工具是ipvsadm。先确认内核模块是否已经加载modprobe ip_vs lsmod | grep ip_vs如果内核支持装好工具后就可以配置虚拟服务和转发规则。下面是一个标准的DR模式配置脚本#!/bin/bash # LVS DR模式配置脚本适用于LVS主节点 # 1. 绑定VIP到负载均衡器物理网卡作为对外的服务入口 ifconfig ens32:0 192.168.1.100 netmask 255.255.255.255 up route add -host 192.168.1.100 dev ens32:0 # 2. 清空已有的转发规则避免操作时互相干扰 ipvsadm -C # 3. 添加一个虚拟服务VIP的80端口使用加权轮询算法 ipvsadm -A -t 192.168.1.100:80 -s wlc # 4. 添加三台后端真实服务器全部使用DR模式权重设为1 ipvsadm -a -t 192.168.1.100:80 -r 192.168.1.21:80 -g -w 1 ipvsadm -a -t 192.168.1.100:80 -r 192.168.1.22:80 -g -w 1 ipvsadm -a -t 192.168.1.100:80 -r 192.168.1.23:80 -g -w 1 # 5. 查看当前规则 ipvsadm -L -n这里有几个细节需要解释。-A表示添加虚拟服务-t指定TCP协议和IP与端口-s wlc指定调度算法为加权最少连接。-a表示在虚拟服务下添加真实服务器-g表示使用DR模式-w设置权重。如果使用NAT模式-g要改成-m。配置完成后立刻用ipvsadm -L -n看输出。你会看到类似下面这样的结果IP Virtual Server version 1.2.1 (size4096) Prot LocalAddress:Port Scheduler Flags - RemoteAddress:Port Forward Weight ActiveConn InActConn TCP 192.168.1.100:80 wlc - 192.168.1.21:80 Route 1 0 0 - 192.168.1.22:80 Route 1 0 0 - 192.168.1.23:80 Route 1 0 0Forward那一列显示Route表示DR模式已经生效。如果是Masq就表示NAT模式。3.4 调度算法选型别一上来就用轮询LVS自带的调度算法有十种左右我实际用下来真正值得关注的就四种。轮询算法rr适合后端服务器硬件配置完全相同、请求处理成本也基本一样的场景。这是最省心的选择。加权轮询wrr在轮询基础上引入了权重概念适合服务器配置有差异、按能力分摊流量的情况。我在早期服务器配置参差不齐时用这个比较多。最少连接lc会把新的请求分给当前活跃连接数最少的服务器。这个算法特别适合长连接场景比如WebSocket、消息推送服务每台服务器上的连接数往往不均匀。加权最少连接wlc在此基础上增加权重。这是我在大部分HTTP场景下的默认选择因为它能同时兼顾服务器处理能力和实时负载而不是简单地按比例分。有个常见误区是觉得调度算法的选择对性能影响很大。坦白说在并发量没到几十万的阶段这类算法之间的QPS差异也就是几个百分点。真正影响用户体验的是后端服务器的实际处理能力和链路质量。所以选型时不要过度纠结先选一个合理默认项上线跑一段时间再结合连接数和响应时间来判断是否需要调整。生产环境下我常用的算法组合是普通的短连接接口用wlc长连接服务用lc如果后端是异构机器再用wrr。只要不是无脑用rr顶着不动一般不会出大问题。4. 高可用方案Keepalived LVS 组合才是真正的生产标配4.1 为什么必须上Keepalived单台LVS节点一旦宕机整个虚拟服务就全部挂了。所以LVS本身这两个字并不代表高可用它只是个转发引擎。生产环境里必须配合Keepalived来实现健康检查和故障转移。Keepalived做的事情有两件一是通过VRRP协议在LVS节点之间漂移VIP。正常情况下VIP落在master节点上master挂了之后backup节点会立刻接管VIP对客户端完全无感知。二是对后端真实服务器做健康检查。如果某台Web服务器端口探测失败Keepalived会自动把它从LVS的转发规则里摘掉不再往它身上分流量等它恢复之后再重新加入。4.2 主备节点Keepalived配置详解主节点/etc/keepalived/keepalived.conf配置如下我加了注释方便你对照理解global_defs { router_id LVS_MASTER # 路由器标识主备配置里必须不同 } vrrp_instance VI_1 { state MASTER # 主节点 interface ens32 # VIP绑定的物理网卡 virtual_router_id 51 # 虚拟路由ID主备必须一致 priority 100 # 主节点优先级高备节点调低 advert_int 1 # VRRP广播间隔单位秒 authentication { auth_type PASS auth_pass your_password # 主备之间的认证密码 } virtual_ipaddress { 192.168.1.100/32 # 虚拟IP主备漂移的对象 } } virtual_server 192.168.1.100 80 { delay_loop 6 # 健康检查间隔单位秒 lb_algo wlc # 和ipvsadm里配置的算法保持一致 lb_kind DR # 转发模式和ipvsadm保持一致 protocol TCP real_server 192.168.1.21 80 { weight 1 TCP_CHECK { connect_timeout 3 # 连接超时时间 nb_get_retry 3 # 重试次数 delay_before_retry 3 # 重试间隔 } } real_server 192.168.1.22 80 { weight 1 TCP_CHECK { connect_timeout 3 nb_get_retry 3 delay_before_retry 3 } } real_server 192.168.1.23 80 { weight 1 TCP_CHECK { connect_timeout 3 nb_get_retry 3 delay_before_retry 3 } } }备节点的配置除了state BACKUP和priority 90其余保持一致。有一个容易出问题的地方如果主节点配置了state MASTER而priority又没有高于备节点VRRP协议会发现优先级异常而出现反复切换。我早期在这个问题上栽过跟头表现是一会儿主节点有VIP过一会儿又跳到备节点上去了流量时断时续。后来查清是priority配置不规范导致的。Keepalived和LVS的规则是互相关联的。Keepalived启动时会自动把virtual_server段落里的配置加载到ipvsadm里主节点接管后就能直接看到转发规则。也就是说日常操作中我们不需要手动执行ipvsadm命令Keepalived会把规则管理起来。这个认知能帮你省去很多不必要的故障排查步骤。4.3 健康检查策略的细节TCP_CHECK是Keepalived最常用的健康检查方式但不够全面。它只能探活TCP端口是否可达无法保证服务真正的健康。举个例子如果Web服务进程还活着但因为数据库连接池耗尽导致请求全部超时TCP端口依然能连接Keepalived依然认为它是健康的流量还是会发过去。更严谨的做法是用HTTP_GET或者自定义脚本做应用层检查。如果你用的是Nginx做后端可以在Nginx里暴露一个轻量的/healthz接口返回固定内容。Keepalived配置改成这样real_server 192.168.1.21 80 { weight 1 HTTP_GET { url { path /healthz status_code 200 } connect_timeout 3 nb_get_retry 3 delay_before_retry 3 } }这个接口最好只返回一个很小的字符串不要依赖任何外部组件。如果它内部还要查询数据库那数据库稍微抖动一下后端服务器就会被摘除引发连锁故障。健康检查的目标是验证服务进程本身是否活着不是验证整个业务链路。5. 上线前必须做的一组验证连接追踪、转发链路和异常定位配置写完不代表万事大吉。我见过太多人配完一测通就急着上线结果高峰期流量一大就出问题。这里分享几个我每次上线前必做的验证环节。5.1 验证IPVS连接追踪表是否正确访问一次VIP地址然后立刻查看连接追踪表ipvsadm -L -n --stats这段输出能看到每个后端服务器收到的总连接数、包数和字节数。如果其中有服务器一直显示0说明它没有被分配到流量需要检查权重、健康状态和网络连通性。再深入一点查看当前活动连接分布ipvsadm -L -n --persistent-conn这个能看出长连接有没有被调度到正确的服务器上。如果出现了某个后端连接数特别多、其他服务器空闲的情况多半是会话保持策略配置不当或者调度算法选择不合理。5.2 用tcpdump验证DIRECT ROUTING流量路径DR模式下最怕遇到的问题是配置没问题但客户端请求永远不通。这个时候直接抓包看数据流向是最快的定位手段。在LVS节点上执行tcpdump -i ens32 host 192.168.1.100 and port 80 -n正常情况你会看到客户端IP发来的SYN包到达VIP所在网卡。然后在后端服务器上同样抓包tcpdump -i ens32 host 192.168.1.100 and port 80 -n如果后端服务器能收到请求包说明LVS转发工作正常。如果后端收到了请求但客户端等不到响应那问题出在回包路径上。这时候重点检查后端服务器的路由表和sysctl配置是否生效。可以用cat /proc/sys/net/ipv4/conf/lo/arp_ignore确认参数是否在运行内核中生效而不是只存在于配置文件里。5.3 最容易混淆的问题端口没放行但一直以为LVS配错了这是一个非常现实的坑。云环境中LVS节点和后端服务器之间通常会有安全组或者防火墙策略。LVS做转发时数据包的源IP是客户端IP目标IP是VIP但经过MAC改写后真正到达后端服务器时目标IP变成了后端服务器的RIP。也就是说后端服务器看到的访问来源是真实的客户端IP它需要在安全组里放行外部客户端来源的80端口流量而不是仅仅放行LVS节点的IP。我遇到过好几次这样的情况规则全对、内核参数全对、抓包也能看到请求进来但业务就是不成功。最后发现是云平台安全组只放行了LVS节点的IP段而后端服务器回包给客户端时客户端根本不认、握手失败。这个隐蔽性很强排查时如果没往这个方向想可能会白白消耗好几个小时。5.4 连接超时与TIME_WAIT参数的适配LVS处于四层它会维护连接的超时状态。如果你的业务有大量短连接默认的TCP超时时间可能会引起连接表被占满。此时需要调整ipvsadm的超时参数ipvsadm --set 30 10 60三个数字分别对应TCP空闲超时、TCP FIN等待超时和UDP空闲超时单位是秒。如果你的业务有大量短连接可以考虑把TCP空闲超时调低比如从默认的900秒调到30秒这样可以大幅降低连接追踪表的占用。但注意如果业务本身是长连接比如WebSocket调低这个值会导致连接被中途断开后果很严重。调整之前先确认业务类型。6. 生产环境里我踩过的坑从故障到修复的完整复盘6.1 ARP冲突导致的VIP间歇性不可达有段时间我们的LVS节点和某台物理服务器的网卡上配置了同一个IP一直没被发现。结果每逢网络扫描或者内网设备重启VIP就会间歇性丢包。排查了很久最后才发现是ARP表里出现了两条同样IP的记录请求被分散到了错误的机器上。用arping可以快速验证arping -I ens32 192.168.1.100 -c 5正常情况下所有响应都应该来自LVS节点的MAC地址。如果出现了不同MAC说明有IP地址冲突立即扫描整个二层网络找到冲突设备并处理。6.2 Keepalived脑裂问题VIP同时在主备节点上出现Keepalived靠VRRP广播来维持主备关系。如果master和backup之间网络抖动VRRP广播中断backup会在超时后认为master已经宕机自动接管VIP。这时两个节点同时持有同一个VIP客户端可能随机访问其中任意一台流量被撕裂服务表现为时好时坏。预防脑裂的方案是配置冲突检测脚本。在Keepalived的vrrp_instance里增加notify_master /etc/keepalived/check_master.sh master脚本里检测当前节点是否真的持有VIP同时通过ping网关和检查对端节点IP是否可达来判断自己该不该成为主节点。如果检测到对端节点依然存活且也持有VIP主动降级并释放VIP地址避免冲突扩大化。这类脚本网上有很多模板但一定要根据自己的网络环境调整超时时间和判断逻辑不能直接复制。6.3 权重设置不合理导致后端被打爆早期我们给三台配置不同的服务器都设置了weight 1结果压测时高配服务器闲置、低配服务器CPU直接打满。最后明白过来权重一定要和后端服务器的真实处理能力挂钩。我这边有一个非常简单的估算方式以最差配置的服务器为基准其他服务器的权重等于各自的CPU核数乘以主频比例。比如基准服务器是2核2.0GHz权重设1另一台是4核2.5GHz权重大约是(4*2.5)/(2*2.0)2.5取整设2到3之间。这类经验公式不需要精确但比盲目设1要科学得多。6.4 恢复阶段的连接断开问题如果你要对某台后端服务器做发布或者重启不要直接kill进程。先把它的权重置为0让LVS停止向它分发新连接ipvsadm -e -t 192.168.1.100:80 -r 192.168.1.21:80 -g -w 0等几秒让已有连接自然结束再操作服务器。这能避免因为连接被硬断导致客户端体验到大量报错。这个操作应该写进发布流程里坚持执行之后能显著减少线上的连接异常报警。7. 日常运维和性能调优里值得长期关注的方向7.1 连接状态的监控指标监控LVS节点除了常规的CPU、内存、网卡流量之外有两个指标我需要你特别关注。一个是ipvsadm -L -n --stats里的ActiveConn和InActConn。ActiveConn如果持续走高说明后端某个服务可能处理缓慢导致连接堆积。另一个是系统层面的cat /proc/net/ip_vs_conn这个文件记录了当前所有连接跟踪条目。如果条目数量接近内核上限需要调整ip_vs_conn_tab_bits参数但这个参数只能在加载内核模块时指定运行期改不了。modprobe ip_vs ip_vs_conn_tab_bits20conn_tab_bits默认是16最多支持6万条左右连接。调到20理论上可以支持100万条以上但每个条目消耗一些内存实际内存增长并不多。如果连接数确实巨大这个调整很有必要。7.2 与Docker和Kubernetes网络的共存问题云原生环境下LVS依然有它的一席之地。MetalLB、kube-proxy的iptables和IPVS模式都用到了类似的原理。kube-proxy在IPVS模式下本质上就是通过ipvsadm维护Service对应的转发规则把ClusterIP的流量转发给后端的Pod。理解了LVS之后再去看kube-proxy的IPVS模式会发现逻辑完全一致。它们在底层用的是同一个内核机制。如果你在Docker环境下做LVS实验要注意Docker的NAT模式和自定义网桥网络会改变数据包的源地址和目标地址在DR模式下容易造成干扰。比较干净的实验方案是使用host网络模式或者在实验时单独划分一个网段给LVS相关节点。7.3 扩展思路LVSDNS的全局负载均衡单机房高并发用LVS就足够了。如果真的需要做多机房级别的流量调度可以在LVS之上再加一层DNS GSLB根据用户来源地区解析到不同的机房VIP。这套架构下来只要DNS解析记录不写死任何一个机房整体故障时DNS层面都能把流量切到可用机房。我在负责多活项目时就是用的这套方案整体效果比较理想。如果不需要DNS那套LVS本身也支持防火墙标记FWMFirewall Mark做多端口统一调度。比如一个业务同时需要80和443端口用FWM可以把两个端口打成一个标记然后LVS针对这个标记统一做转发避免了两条规则分别配置导致连接追踪不一致的问题。具体写法是先用iptables给包打标记再在ipvsadm里针对这个标记创建虚拟服务。iptables -t mangle -A PREROUTING -p tcp -m multiport --dports 80,443 -j MARK --set-mark 100 ipvsadm -A -f 100 -s wlc ipvsadm -a -f 100 -r 192.168.1.21:80 -g -w 1这个方法在生产环境中很实用特别是现在HTTPS全面普及后HTTP和HTTPS往往并行存在。用一个转发策略统一管理配置维护上能少操不少心。说实话LVS这套技术已经非常成熟甚至有些人觉得它有点老。但换个角度看一个能在内核里稳定跑十几年的转发方案恰恰说明了它的可靠性。我至今没有找到比它在四层转发场景下更省资源、更抗压力的替代品。在理解它的过程中你会接触到Netfilter、路由、ARP、VRRP、TCP状态机等一系列网络核心知识这些积累对做架构设计非常有帮助。如果你正在规划高并发的服务架构花一个周末把LVS跑通我认为是非常值得的投入。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价