
上周帮朋友排查一个线上负载均衡问题又翻回LVS-DR这套老方案。说实话LVS这项目从Linux 2.4内核时期就存在了到现在仍然有不少生产环境在用。DR模式更是其中部署最广的一种很多互联网公司早期四层负载均衡就是靠它扛过来的。我做这个LVS-DR实验不是为了追新而是想彻底搞清楚它为什么能承载那么大的并发流量以及实验过程中那些诡异的ARP问题到底是怎么产生的。如果你正在学负载均衡、准备面试或者刚接手一套LVS集群这篇内容应该能直接帮到你。我会把整套实验的环境规划、配置命令、验证思路和踩坑记录都拆开来讲力争你照着敲一遍就能跑通。1. 项目背景与方案选型思路1.1 LVS-DR到底是什么LVSLinux Virtual Server是一个基于Linux内核的负载均衡项目DR是Direct Routing直接路由的缩写。用一句话概括DR模式客户端请求先到达负载均衡器负载均衡器通过调度算法挑一台后端真实服务器Real Server下称RS然后把请求的二层帧直接转发给这台RSRS处理完响应后不经过负载均衡器直接回给客户端。关键在于理解“为什么响应可以不走负载均衡器”。客户端请求的目标IP是VIPVirtual IP虚拟IP负载均衡器收到数据包后只改写目标MAC地址不改写源IP和目标IP。RS的lo接口上绑定了同一个VIP所以RS收到数据包后认为自己就是这个VIP处理完请求后以VIP作为源IP直接构造响应报文发给客户端。客户端看到响应来源就是自己访问的那个IP完全感知不到中间还有一层负载均衡。DR模式的优势很明显负载均衡器只处理入站请求出站响应不经过它所以在高并发场景下Director的网卡、CPU压力比NAT模式小很多。一般NAT模式下Director很容易成为瓶颈DR模式则可以支撑更大的流量规模。1.2 为什么选DR而不是NAT或TUNLVS一共有三种工作模式NAT、DR、TUN。我在实验里选DR是因为它在生产环境中最具代表性而且配置难度适中实验现象也很直观。NAT模式强制所有流量都过Director请求和响应都要做地址转换Director硬件压力大扩容成本高。TUN模式虽然也能做到响应直接回客户端但要求RS支持IPIP隧道协议配置链路复杂对网络环境要求也更苛刻。DR模式只有一个硬前提Director和所有RS必须在同一个二层网络内。对机房部署来说这个条件基本都能满足。三者对比如下模式请求路径响应路径Director压力配置复杂度典型场景NAT客户端 → Director → RSRS → Director → 客户端高低中小规模、后端跨网段DR客户端 → Director → RSRS → 客户端低中高并发、同二层网络TUN客户端 → Director → RSRS → 客户端低高跨地域、RS在不同网段1.3 DR模式的核心难点ARP问题这个实验最大的价值就是让你直面DR模式最经典的ARP问题。RS的lo接口绑定了VIP之后理论上整台RS对外就多了一个VIP地址。如果内网里的其他机器包括网关向VIP发起ARP请求Director和RS都可能会响应因为大家都有这个IP。这样一来ARP缓存就会乱掉某些请求可能直接越过Director被送到某台RS上负载均衡直接失效。解决方法是让RS对外网接口的ARP请求保持沉默只让VIP在本地回环接口上生效并且通过内核参数控制对外通告的源地址。具体参数就是arp_ignore和arp_announce后面配置部分会详细讲。提示如果你已经配置好了整个集群但压测时发现只有某台RS流量暴涨Director的流量反而不高那十有八九是ARP抑制没设对。这是DR模式的第一大暗坑。2. 实验环境准备与网络规划2.1 节点规划与系统选型实验环境我用的是三台CentOS 7.9虚拟机VMware和VirtualBox都可以网络模式选择“仅主机模式”或者同一个自定义网段确保所有节点二层互通。如果你手头只有一台物理机用三台虚拟机跑完全没问题关键是把网卡MAC地址固定下来不然虚拟机每次克隆或迁移后MAC变化后续排查会非常困惑。节点规划如下角色主机名IP地址说明LVS Directorlvs-director192.168.1.10负载均衡器绑定VIPReal Server 1rs1192.168.1.11后端Web服务lo绑定VIPReal Server 2rs2192.168.1.12后端Web服务lo绑定VIP虚拟IPVIP192.168.1.100对外提供服务的IP系统方面CentOS 7.9是相当稳的选择IPVS内核模块天然支持ipvsadm和keepalived的yum源也很全。想用Rocky Linux 8或Ubuntu 22.04也完全没问题核心配置思路一致只是包管理命令和部分文件路径稍有差别。2.2 基础环境初始化实验环境我建议先关闭防火墙和SELinux减少干扰项。生产环境当然不能这么粗暴但实验阶段先把问题域缩小后面再慢慢补安全策略会舒服很多。systemctl stop firewalld systemctl disable firewalld setenforce 0 sed -i s/SELINUXenforcing/SELINUXdisabled/ /etc/selinux/config然后在两台RS上分别安装并启动nginx用来作为后端的测试服务。yum install -y nginx echo This is RS1 (192.168.1.11) /usr/share/nginx/html/index.html systemctl start nginxRS2同样操作只是index.html内容改成RS2对应的主机名和IP。后面验证的时候只要看curl返回的是哪台RS的内容就知道负载均衡有没有生效。2.3 理解VIP与网卡配置的关系VIP建议作为辅助IP挂在Director的物理网卡上同时以lo接口回环地址的形式挂在每台RS上。这里要刻意区分Director上的VIP是真实对外发布的地址需要参与ARP响应用来吸引流量RS上的VIP只“自己用”不参与对外ARP通告。理解了这一层后面配置内核参数时就不会稀里糊涂。我见过不少新手图省事直接在RS的物理网卡上绑VIP结果ARP抑制怎么配都不对。其实RS必须把VIP绑在lo接口上配合arp_ignore1才能实现“接收发给VIP的包但不对外宣告自己是VIP”。3. 核心配置实操过程3.1 Director端配置VIP和ipvsadm规则先给Director的网卡添加VIP地址这里用的是临时命令方便实验验证。注意子网掩码是/32代表一个单独的主机地址不会影响物理网卡原有的通信。ip addr add 192.168.1.100/32 dev ens33接着安装并配置ipvsadm管理工具。yum install -y ipvsadm然后添加虚拟服务器和后端真实服务器# 添加虚拟服务调度算法为rr轮询 ipvsadm -A -t 192.168.1.100:80 -s rr # 添加后端真实服务器-g表示DR模式 ipvsadm -a -t 192.168.1.100:80 -r 192.168.1.11:80 -g ipvsadm -a -t 192.168.1.100:80 -r 192.168.1.12:80 -g参数说明-A添加一个虚拟服务器条目-a在虚拟服务器下添加真实服务器-t使用TCP协议格式为IP:端口-s rr调度算法为轮询Round Robin-r后端真实服务器地址-gDR模式也叫做Gatewaying模式-m是NAT模式-i是TUN模式配置完用ipvsadm -Ln查看输出结果大概长这样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 rr - 192.168.1.11:80 Route 1 0 0 - 192.168.1.12:80 Route 1 0 0这里Forward列显示Route就表示DR模式生效。顺便开一下内核转发虽然DR模式本质上不走IP转发但实验过程中偶尔会用到其他调试手段开着没坏处echo 1 /proc/sys/net/ipv4/ip_forward3.2 RealServer端配置VIP与ARP抑制RS端的配置是整个实验的灵魂所在也是踩坑高发区。我强烈建议按以下顺序操作先设置内核参数抑制ARP再绑定VIP。顺序反了内网ARP表一瞬间就可能乱掉。先配置ARP抑制echo 1 /proc/sys/net/ipv4/conf/all/arp_ignore echo 1 /proc/sys/net/ipv4/conf/lo/arp_ignore echo 2 /proc/sys/net/ipv4/conf/all/arp_announce echo 2 /proc/sys/net/ipv4/conf/lo/arp_announce然后绑定VIP到lo接口ip addr add 192.168.1.100/32 dev lo ip route add local 192.168.1.100 dev lo这两条命令的作用分别是让RS在本地生成一个VIP地址以及确保发往VIP的本地回环流量能正确路由。如果漏掉第二条route命令部分内核版本下访问VIP会出现意外问题。这两个内核参数解释一下arp_ignore1只回答目标IP地址是本地某个接口地址的ARP请求。因为VIP绑定在lo上而ARP请求通常是发给物理网卡的所以RS会忽略所有针对VIP的ARP请求控制权就全部留给Director。arp_announce2对外发送ARP报文时总是使用最合适的本地地址而不是lo接口上的VIP。这能防止RS向局域网通告“192.168.1.100是我”。生产环境不可能每次重启都手动敲命令建议把整套配置写成脚本开机自动执行。下面是我常用的初始化脚本#!/bin/bash # RS初始化配置VIP ARP抑制 VIP192.168.1.100 echo 1 /proc/sys/net/ipv4/conf/all/arp_ignore echo 1 /proc/sys/net/ipv4/conf/lo/arp_ignore echo 2 /proc/sys/net/ipv4/conf/all/arp_announce echo 2 /proc/sys/net/ipv4/conf/lo/arp_announce ip addr add $VIP/32 dev lo ip route add local $VIP dev lo另外为了让sysctl配置永久生效把关键参数持久化到/etc/sysctl.conf也不可少net.ipv4.conf.all.arp_ignore 1 net.ipv4.conf.lo.arp_ignore 1 net.ipv4.conf.all.arp_announce 2 net.ipv4.conf.lo.arp_announce 23.3 验证负载均衡效果配置完成后在一台客户端机器上反复访问VIPfor i in {1..8}; do curl -s http://192.168.1.100/; done正常结果应该是RS1和RS2的页面内容交替出现。如果连续多次都是同一台RS的内容说明要么调度算法配置有误要么ARP抑制没生效要么客户端缓存了ARP记录。再在Director上查看连接调度情况ipvsadm -Lnc这条命令显示当前连接表能看到每个连接被转发到了哪台RS。用ipvsadm -Ln --stats可以看累计的流量统计ipvsadm -Ln --stats输出里Conns和InOctets等指标能帮你判断两台RS的负载是否相对均衡。压测工具我习惯用Apache Bench或者wrk随手一个命令就能发很多请求过来比浏览器刷新更能看出调度效果。我还习惯在Director上抓包确认二层转发行为tcpdump -i ens33 -p tcp port 80 -c 5抓包结果里可以看到外网请求到达Director后Director修改目标MAC地址为RS的MAC并转发出去。你会直观感受到DR模式确实只是改了二层头部三层IP地址没变。3.4 引入keepalived做健康检查和VIP管理手动的ipvsadm规则在实验里没问题但生产中如果某台RS宕机Director还会继续把请求转发到故障节点这时候就需要keepalived上场。keepalived一方面可以做VRRP高可用实现VIP在主备Director之间漂移另一方面它能自动检测RS的健康状态发现异常就把它摘除。我这次实验先不搞主备双机只部署单台keepalived来统一管理VIP和RS状态效果已经很接近生产了。keepalived配置文件如下global_defs { router_id LVS_DIRECTOR } vrrp_instance VI_1 { state MASTER interface ens33 virtual_router_id 51 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 192.168.1.100/32 dev ens33 } } virtual_server 192.168.1.100 80 { delay_loop 6 lb_algo rr lb_kind DR protocol TCP real_server 192.168.1.11 80 { weight 1 TCP_CHECK { connect_timeout 3 nb_get_retry 3 delay_before_retry 3 } } real_server 192.168.1.12 80 { weight 1 TCP_CHECK { connect_timeout 3 nb_get_retry 3 delay_before_retry 3 } } }注意如果之前你已经手动用ip addr add绑定了VIP启动keepalived前要先清掉免得IP冲突。keepalived启动后会自动添加VIP并加载ipvs规则systemctl start keepalived systemctl enable keepalived此时再用ipvsadm -Ln查看你会发现Director端会自动生成对应的虚拟服务器和真实服务器条目健康检查也会周期性探测RS的80端口。注意keepalived里的lb_kind DR必须和实际模式一致同时RS端仍然需要做ARP抑制和VIP绑定keepalived只负责Director侧的逻辑RS端配置不能省。4. 常见问题与排查技巧实录4.1 客户端无法访问VIP请求一直超时这是实验里出现频率最高的问题。按以下顺序排查基本能定位Director上VIP是否绑定成功。执行ip addr show确认VIP在网卡上。RS上lo接口是否绑定VIP。在每台RS上执行ip addr show lo确认192.168.1.100存在。RS的nginx是否正常监听80端口。ss -lntp | grep 80看一下。Director的ipvs规则是否正常加载。ipvsadm -Ln看有没有丢失条目。最后再怀疑ARP问题清理客户端ARP缓存后重试。还有个容易忽略的情况客户端本身也在192.168.1.0/24网段内客户端访问VIP时如果ARP缓存里保留的是某台RS的MAC那请求可能根本不会经过Director。这种问题在清理ARP缓存之后会暂时恢复但过一段时间又可能复发。根治办法只有在RS端严格配置ARP抑制。4.2 请求全部打在一台RS上另一台完全空闲先确认调度算法是不是rr。如果用的是wrr且默认权重没配也可能出现偏向某台的情况。但实验环境里最常见的还是客户端复用了HTTP持久连接或者压测工具连接池没有关闭导致所有请求都在同一台RS的一条TCP连接上循环。解决办法是压测时加参数禁用连接复用比如ab命令加-k反而不对不加-k就每次新建连接。或者临时换用curl循环来看效果确保每次都是独立连接。另外用ipvsadm -Lnc详细看连接表判断当前活动连接是不是被分配到了同一台RS。如果是连接表里看起来均衡但实际流量偏斜那问题基本不在LVS层要检查后端服务本身的长连接策略。4.3 RS不做ARP抑制导致的诡异流量倾斜这个坑我在第一次实验时踩得很深。当时Director上明明配好了rr算法但压测时Director流量低得可怜其中一台RS却顶着全量流量。抓包一看客户端发出的请求里目标MAC直接就是RS的MAC也就是说二层帧压根没经过Director。问题根源就是RS绑定了VIP后没有设置arp_ignore和arp_announce。局域网里最先响应的ARP应答者抢占了VIP的MAC映射客户端直接把VIP当成了那台RS。实验里重新配置ARP抑制后还要在客户端上执行ip neigh flush all把错误缓存的邻居条目清掉再重新测试。这个案例非常典型几乎每个做LVS-DR实验的人都会遇到一次。4.4 重启后配置全部丢失手动执行的ip addr和echo命令都是临时配置服务器一重启就没了。解决方式很简单把VIP绑定、ARP抑制参数写入脚本交给systemd管理或者把参数写到/etc/rc.local里。sysctl参数一定要持久化到/etc/sysctl.conf并执行sysctl -p验证。我最推荐的方式是写成一个标准的systemd service因为依赖顺序可控启动时确保网卡已就绪后执行配置脚本。虽然实验环境用rc.local就行但养成标准化习惯对以后维护生产集群有帮助。4.5 顺手澄清几个容易混淆的“DR”概念搜索“LVS-DR”常会混进来一些完全不相关的词。这里直接说清楚避免浪费大家时间OSPF里的DR/BDR选举OSPF是路由协议DR和BDR是它在广播链路上选举出的指定路由器和备份指定路由器作用是减少邻接数量。虽然缩写相同但和LVS-DR没有任何关系。DR航位推算Dead Reckoning导航定位领域的概念通过已知位置和方向推算当前位置属于惯性导航范畴。ADC到DR的转换一般指模拟数字转换器ADC量化后的数据涉及到的某种参考或比值关系多出现在硬件设计语境里。万东DR维修手册这里的DR是数字X射线摄影系统Digital Radiography医疗影像设备相关。这些词和LVS负载均衡八竿子打不着。想搜索LVS相关内容时尽量用“LVS DR模式实验”“LVS Direct Routing配置”这类完整关键词过滤效果会好很多。5. 实验扩展与进阶思考5.1 尝试更多调度算法基础实验用的是rr轮询但生产环境很少只用rr更常见的是wrr加权轮询和wlc加权最少连接。你可以把-s rr改成-s wlc然后给性能更好的RS设置更高权重观察连接分配的变化ipvsadm -a -t 192.168.1.100:80 -r 192.168.1.11:80 -g -w 2 ipvsadm -a -t 192.168.1.100:80 -r 192.168.1.12:80 -g -w 1如果要处理有状态服务比如需要保持Session的Web应用可以用sh源地址哈希算法保证同一客户端的请求总被转发到同一台RS。这个改动非常小只要把-s rr换成-s sh就行实验现象也足够明显。5.2 结合监控工具观察Director压力DR模式之所以受欢迎就是因为它把响应流量剥离开Director的压力小很多。实验时可以在Director上装一个dstat或nload压测时对比一下Director的网卡流量和RS的网卡流量。你会发现Director的出站流量很低但RS的出站流量很高这就直观证明了DR模式的优点。5.3 安全加固与生产化改造实验里把防火墙和SELinux都关了生产环境自然不能这么干。建议在Director上只放通VIP的服务端口并限制来源IP。在RS端同样要限制外部访问VIP的流量因为RS的lo接口上绑着VIP如果不加限制外部机器直接访问RS的VIP也能访问到后端服务这相当于绕过了负载均衡还会暴露RS真实身份。通常会用iptables在RS上设置规则只允许来自Director的流量访问本机VIP其余一律丢弃。最后想说的做LVS-DR实验真正宝贵的不是把那些命令敲通而是搞明白数据包每一步是怎么走的、ARP问题为什么会产生、又是怎么被参数解决掉的。把这个实验吃透你再看Nginx、HAProxy这些负载均衡方案的核心逻辑都会觉得顺畅很多因为它们解决的是同一个问题只是角度不同。我个人建议你把实验环境保留下来后续可以继续加测keepalived双机热备、多调度算法对比、真实压力工具测试每加一个环节你对这套系统的理解就会深一层。我现在维护的很多集群仍然在用LVS-DR这套方案每次遇到性能问题回头看这个实验里的基本原理很多疑问都会迎刃而解。