每次看到“DR”这个词,不同圈子的人都能引申出完全不同的含义。搞网络的人想到OSPF里的指定路由器,做导航定位的人想到航位推算Dead Reckoning,医院设备科的人第一反应是数字化X射线摄影设备。而在运维圈,尤其在一线处理高并发业务的工程师看来,“DR”十有八九指LVS的直接路由模式(Direct Routing)。这篇我就围绕LVS-DR实验展开,把这个经典四层负载均衡方案从原理、实验环境规划、配置细节,到抓包验证、健康检查和高可用特性,按实际操作过的顺序从头过一遍。适合刚接触LVS的运维工程师,也适合准备搭建高可用负载均衡架构、需要先厘清原理的系统架构师。
1. 先把 LVS-DR 放进整个负载均衡体系里看
1.1 三种工作模式的横向对比
LVS的底层是Linux内核里的IPVS模块,它工作在四层,通过netfilter框架在数据包进入协议栈时拦截并改写关键字段,把请求转发给后端真实服务器。用户态通过ipvsadm命令管理规则,内核替你完成转发。整个体系里最常用的有三种转发模式:NAT、TUN和DR。
| 模式 | 转发机制 | 响应报文路径 | 后端要求 |
|---|---|---|---|
| NAT | 调度器同时修改目的地址和源地址 | 响应必须再回到调度器 | 后端默认网关必须指向调度器 |
| TUN | 调度器把请求封装进IP隧道 | 后端解封装后直接回包 | 后端需要支持隧道设备 |
| DR | 调度器只改写二层MAC帧头 | 后端直接把响应发给客户端 | 后端与调度器同一二层网络,且绑定VIP |
DR模式的核心思路就一句话:只动二层,不碰三层。调度器收到客户端的请求后,把数据帧的目标MAC改成某台真实服务器的网卡MAC,再把帧发出去。真实服务器看到目标IP是VIP,而且自己lo接口上确实绑着这个VIP,于是接受处理。处理完之后,响应报文直接以VIP为源地址发给客户端,完全不回调度器。
打个比方:调度器像个前台接待,只负责把访客分配到工位。工位上的同事做完活,直接把结果送到客户手上,前台完全不介入回程。这和NAT模式那种"所有进出都必须经过前台"的模式有本质区别。
1.2 DR 模式的优势、限制和适用场景
DR模式最大的好处就是响应路径短。调度器只处理入站请求,不用承担回程大流量,CPU、带宽和连接跟踪的压力都比NAT小很多。对于"入站小、出站大"的典型读多写少业务,比如图片服务器、视频点播、静态资源网关,DR能把吞吐量拉到非常高的水平,这是生产环境大量选择LVS-DR的首要原因。
代价也相当明确。第一,所有真实服务器必须和调度器处于同一个二层广播域,跨机房、跨VLAN部署会比较麻烦,得靠VLAN或VXLAN把二层拉通。第二,真实服务器必须把VIP绑到lo接口上,并且压制ARP响应,否则整个网段的VIP归属会乱掉。第三,DR模式不能做端口映射,调度器转发时不改端口,所以后端服务必须监听和VIP服务一致的端口。你在ipvsadm里写8080,后端就也得监听8080。
适用场景上,DR模式特别适合支撑公司内部的高并发API网关、文件下载集群和CDN源站。NAT模式虽然配置直观,但回程全走调度器,流量一上来调度器就成了瓶颈;TUN模式能跨网段,但隧道封装有一定CPU开销,而且很多系统默认不开IPIP模块。DR均衡了性能和复杂度,是性价比较高的方案。
1.3 顺手纠正几个“DR”误区
搜索LVS-DR时很容易被联想词带偏,我在这里统一澄清。LVS的DR是Direct Routing,和OSPF里的DR/BDR指定路由器没有关系。有人搜“OSPF协议每个区域都有DR吗”,这个问题得看网络类型,只有广播型多路访问网络里才需要选举DR/BDR,点对点链路不需要,所以答案是"不是每个区域都必然有"。也有人搜“ADC->DR是什么”,这通常出现在自动化采集或医疗影像设备的数据转换流程里,跟在服务器上做负载均衡也是两条路。至于“航位推算”Dead Reckoning,更多是定位导航领域的概念。缩写撞车不是新鲜事,但做实验时认准方向和上下文,能少走很多弯路。
2. 实验环境规划:拓扑、IP 与 ARP 关键点
2.1 最小可验证拓扑与角色分配
我这次用的是VMware Workstation创建的三台CentOS 7虚拟机,系统层面换成Ubuntu 20.04或22.04也完全没问题。实验要保证调度器和后端真实服务器之间只有一台二层交换机,或者干脆就接在同一个虚拟交换机上,所以VMware网络模式建议选择桥接或仅主机模式,不要用NAT模式,因为VMware自带的NAT会多一层地址翻译,干扰对DR转发路径的判断。
| 角色 | 主机名 | 物理IP | VIP | 说明 |
|---|---|---|---|---|
| Director | lvs-dir | 192.168.10.10/24 | 192.168.10.100/24(eth0) | 安装ipvsadm和keepalived |
| RS1 | rs-1 | 192.168.10.11/24 | 192.168.10.100/32(lo) | 运行Nginx,监听80 |
| RS2 | rs-2 | 192.168.10.12/24 | 192.168.10.100/32(lo) | 运行Nginx,监听80 |
| Client | client | 192.168.10.20/24 | 无 | 发请求做验证 |
注意看表里的VIP掩码,调度器上写/24,真实服务器上写/32。这个差异不是随手写的,是DR模式能不能跑通的关键之一。调度器作为VIP的实际持有者,必须让同网段的客户端和真实服务器能通过ARP找到它,所以掩码要和物理网段一致;真后端服务器把VIP挂在lo上时,如果也写/24,会产生一条指向前端物理网段的路由,容易干扰Linux路由决策,写/32才能把VIP的影响范围限制在环回接口内。
2.2 VIP 到底该挂在哪台设备的哪个接口
初做LVS实验的人最容易犯的错误,是给所有机器都只配物理IP,忘了VIP该往哪儿放。Director一侧必须持有VIP,否则客户端没有目标地址可以发请求;后端真实服务器也必须持有VIP,否则它收到目标IP为VIP的数据包时,会认为这个包“不是发给我的”,然后在路由表里找不到匹配项,直接丢弃。
那为什么后端要把VIP挂到lo而不是eth0呢?因为如果每台RS的eth0都绑定了192.168.10.100,它们会用自己的物理MAC地址响应ARP请求,客户端和交换机都会蒙圈:这个VIP到底属于谁?把VIP放在lo上,再配合ARP抑制参数,后端就能“收包但不应答”。这里用到了Linux弱主机模型:系统判断一个包是不是发给本机的依据,是本地是否存在目标IP,而不管它从哪个接口进来。所以即使VIP配置在lo上,eth0收进来的数据包一样能被正常处理。理解这一点,DR模式“所有机器都有VIP、但只有调度器宣称自己拥有VIP”的机制就通了。
2.3 ARP 抑制参数:理解两个内核参数的工作逻辑
后端RS在lo接口配置VIP之后,必须调整两个ARP相关内核参数:arp_ignore和arp_announce。ARP抑制是整个DR模式里最容易出问题、也最考验基础原理的部分。
- arp_ignore = 1:只回应“目标IP等于本接口IP”的ARP请求。因为VIP只配置在lo接口,如果有人查询192.168.10.100对应的MAC,eth0收到这个广播请求时会发现目标IP不是eth0的IP,于是选择不响应。
- arp_announce = 2:发送ARP报文时,使用最适合当前出口接口的地址作为源IP,避免把VIP当作源地址发送ARP通告,防止后端主动宣告自己拥有VIP。
每台RS上执行:
cat >> /etc/sysctl.conf <<'EOF' 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 = 2 EOF sysctl -p配置完成后用sysctl -a | grep arp_检查实际生效值。不同内核版本对all和lo的继承逻辑略有差别,我建议all和lo两个维度都写,宁可多想一步,也不要为了少几行配置埋坑。这个参数组合的意义不是让VIP“不可达”,而是让VIP“只被调度器宣告,后端只默默接收”。
3. 实操步骤:一个下午搭出一套完整环境
3.1 Director 安装并在内核里添加 IPVS 规则
先装工具,再加载模块:
yum install -y ipvsadm keepalived modprobe ip_vs lsmod | grep ip_vsipvsadm是用户态管理工具,真正干活的是内核模块ip_vs。lsmod能看到ip_vs说明模块加载成功。初次实验建议先手动添加规则,不要一上来就上keepalived。手动规则能让你把“转发层”单独跑通,之后再叠加高可用,出问题时定位范围会小很多。
手工规则如下:
ipvsadm -A -t 192.168.10.100:80 -s rr ipvsadm -a -t 192.168.10.100:80 -r 192.168.10.11:80 -g ipvsadm -a -t 192.168.10.100:80 -r 192.168.10.12:80 -g ipvsadm -L -n-A是添加一个虚拟服务,-a是往虚拟服务里添加真实服务器,-t指定TCP协议和地址端口,-r指定后端RS,-g表示DR模式,-s rr表示轮询调度算法。可见的迹象是ipvsadm -L -n输出里出现了两条RealServer记录,每条后面都有Route标记,代表DR模式。
3.2 RS 的 Nginx 与 lo 接口 VIP 配置
每台RS上先装Nginx,然后写一个独立页面,方便后面确认请求到底落在了哪台机器:
yum install -y nginx echo "RS1" > /usr/share/nginx/html/index.html # RS2上改成RS2 systemctl start nginx接着配置lo接口VIP。直接执行ip addr add 192.168.10.100/32 dev lo立刻生效,但重启会丢,所以我习惯写成一个systemd unit文件,方便开机自启和统一管理:
# /etc/systemd/system/vip.service [Unit] Description=Setup LVS VIP on loopback After=network.target [Service] Type=oneshot ExecStart=/sbin/ip addr add 192.168.10.100/32 dev lo ExecStop=/sbin/ip addr del 192.168.10.100/32 dev lo RemainAfterExit=yes [Install] WantedBy=multi-user.target启动并设置开机自启:
systemctl daemon-reload systemctl enable --now vip.service在没关keepalived之前,手工规则在Director上跑着,RS上的VIP也配好了,ARP抑制参数也已经生效,这时候可以先做一轮最基础的请求验证。
3.3 从 Client 发请求,验证轮询和连接表
在Client机器上连续发起请求:
for i in $(seq 1 6); do curl -s http://192.168.10.100/; sleep 1; done正常情况下会交替输出RS1和RS2,说明IPVS按轮询算法把请求分发到了两台后端。同一时间在Director上执行:
ipvsadm -Lnc可以看到当前连接表里的条目,每次curl请求都会产生一条新的TCP连接记录,这条记录会指向其中一台RS。能出现这个现象,说明从调度规则到后端收包再到回包路径,整条链路已经基本打通。
如果某个请求超时,优先检查三件事:后端Nginx是否监听80端口、后端能否直接访问自己的VIP、ARP抑制是否生效。这个顺序是我在多次排障里固定下来的,效率最高。
4. 叠加 keepalived,给实验补上健康检查能力
4.1 为什么生产环境不会让 IPVS 规则裸奔
只靠手工ipvsadm规则,转发本身能跑通,但有个致命问题:IPVS不检查后端是否存活。如果你手动停掉RS2的Nginx,Director上的规则依然存在,它依然会把请求分给RS2,结果就是客户端时不时超时,因为请求被送进了一个没有进程监听的端口。
生产环境解决这个问题的主流方案是使用keepalived,做的事情有两件:一是给调度器集群做VRRP主备保障,也就是Director本身挂了,备用Director能接管VIP;二是对后端真实服务器做健康检查,发现失败就自动从IPVS转发池里摘除,恢复后自动加回。这也是LVS在生产环境真正可用、可运维的关键。
4.2 keepalived 主备配置与 VRRP 行为
在Director上写/etc/keepalived/keepalived.conf:
vrrp_instance VI_1 { state MASTER interface eth0 virtual_router_id 51 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 123456 } virtual_ipaddress { 192.168.10.100/24 dev eth0 } } virtual_server 192.168.10.100 80 { delay_loop 6 lb_algo rr lb_kind DR protocol TCP real_server 192.168.10.11 80 { weight 1 TCP_CHECK { connect_timeout 3 nb_get_retry 3 delay_before_retry 3 } } real_server 192.168.10.12 80 { weight 1 TCP_CHECK { connect_timeout 3 nb_get_retry 3 delay_before_retry 3 } } }这段配置里vrrp_instance负责虚拟IP管理和主备切换,virtual_server负责虚拟服务和真实服务器群组。需要注意,DR模式下keepalived把VIP加到eth0时掩码写/24,和手工RS上lo接口的/32不冲突,因为一个物理IP需要响应ARP,一个环回地址只是收包不响应ARP,语义完全不同。如果这里写错掩码,keepalived起来后可能不会正常宣告VIP,客户端会一直找不到网关。
VRRP协议默认基于组播报文通信,优先级高的成为MASTER并持有VIP,BACKUP处于监听状态。实验里只用单台Director,state写MASTER就能顶上;生产环境搭双机时,两台都要跑keepalived,virtual_router_id要一致,priority要不同,还要确保防火墙放行VRRP协议(协议号112)。
4.3 健康检查失败时的摘除与恢复机制
配置里delay_loop 6表示每6秒做一轮健康检查。TCP_CHECK的意思是对真实服务器的80端口发起TCP连接,连接超时3秒,失败重试3次,每次间隔3秒。这套参数很常用,但要注意:如果后端服务本身响应很慢,比如高峰期部分接口要等5秒才返回,那么connect_timeout和nb_get_retry要适当放宽,否则健康检查会误判,把正常节点摘掉,反而破坏可用性。
启动keepalived后,原来的手工ipvsadm规则其实会被keepalived覆盖管理。可以直接用ipvsadm -L -n观察,会看到两条RealServer记录。此时手动停掉RS1的Nginx,等最多十几秒,再执行ipvsadm -L -n,RS1就会被从IPVS转发池里摘除;再启动Nginx,它会自动加回。这个摘除和恢复的循环,就是生产环境后端扩容、缩容、发版时经常依赖的机制。
5. 用抓包和故障注入验证 DR 的完整工作过程
5.1 tcpdump 抓包看“请求进、响应出”的二层细节
实验做完不能只看到“curl能通”就收工,我强烈建议用tcpdump把包抓出来看一遍,你会发现DR模式的真相藏在二层帧头里。在RS1上执行:
tcpdump -i ens33 host 192.168.10.100 and host 192.168.10.20 -nn然后从Client访问一次VIP。观察抓包结果,入方向可以看到客户端的请求包到达RS1的ens33,目标IP是192.168.10.100(VIP),但目标MAC是RS1网卡的MAC。这个细节说明Director已经完成了MAC地址改写,包不是广播收到的,而是被精确送到了RS1。源IP还是客户端的IP,源MAC是Director的MAC。也就是说,三层地址没变,二层路径变了。
出方向更明显:RS1发出的响应包源IP是192.168.10.100,目标IP是192.168.10.20,但直接发给了下一条网关或客户端侧交换设备,完全不会经过Director。如果你在另一种模式里看到响应包又折返回Director,那就是NAT模式的回程特征。抓一次包,DR与NAT的本质区别就刻在脑子里了。
5.2 停止一台 RS,观察调度与恢复
在keepalived已经接管配置的基础上,做一次故障注入。登录RS2执行:
systemctl stop nginx在Director上持续观察ipvsadm -L -n,几秒钟后RS2从列表消失。这时候再从Client连续curl,会发现所有请求都由RS1响应,不再出现超时或连接拒绝。然后把RS2的Nginx再启动,等健康检查窗口过去,RS2自动回到转发池,流量重新变为轮询分配。
这个操作模拟的就是生产环境里某台后端服务发版失败、进程挂掉、再重启恢复的完整过程。真正有价值的不是看到它恢复,而是理解掉线窗口期里调度器做了什么、健康检查周期是多少、失败重试参数怎么影响摘除速度。把这些参数记熟,遇到故障时才不会手忙脚乱。
5.3 一套可反复用的验收清单
| 检查项 | 命令/方法 | 预期结果 |
|---|---|---|
| 客户端访问VIP | curl http://192.168.10.100 | 交替输出RS1/RS2 |
| 连接表查看 | ipvsadm -Lnc | 能看到发往两台RS的TCP记录 |
| ARP抑制生效 | arping -I eth0 -c 5 192.168.10.100 | 只有Director的MAC响应 |
| 健康检查摘除 | systemctl stop nginx后观察ipvsadm | 对应RS从转发池移除 |
| 健康检查恢复 | systemctl start nginx后观察ipvsadm | 对应RS自动加回 |
| 回包路径 | tcpdump在RS上抓包 | 响应包不经过Director |
这套清单几乎可以直接当作给新环境做交付验收时的标准动作,每一条都能帮你快速定位DR模式的哪一环出了问题。
6. 常见问题速查与避坑心得
6.1 高频问题与排查顺序
| 现象 | 常见原因 | 处理建议 |
|---|---|---|
| VIP能ping通但curl超时 | 后端Nginx未监听80,或防火墙拦截 | 先在后端curl 127.0.0.1验证服务,再放行80端口 |
| curl返回内容始终来自同一台RS | 轮询算法被改成持久算法,或健康检查只保留一台 | 检查ipvsadm算法参数和keepalived配置 |
| 客户端ARP表中VIP的MAC来回跳 | ARP抑制没有生效 | 重新检查sysctl.conf,确认lo和all两个维度均已配置 |
| 多台Director同时持有VIP | VRRP参数不一致或防火墙封了组播 | 确认virtual_router_id和priority,放行协议112 |
| 请求被分到RS但RS不处理 | RS上未配置lo的VIP | 在RS上ip addr确认,并检查vip.service是否启动 |
| 换端口访问失败 | DR模式不能做端口映射 | 把调度器和后端服务配置在同一端口 |
前一节提到的故障定位顺序也放在这里:先查服务监听,再查VIP是否存在,最后抓包看ARP和回包路径。照着顺序来,基本不会排查到一半迷路。
6.2 几份实操习惯,能少踩很多次坑
第一,先手工ipvsadm验证,再上keepalived。手工规则让你直接面对内核转发的原始状态,出了问题更容易定位;一上来就叠keepalived,所有故障都会混合在一起。第二,每次调整ARP参数都重新用arping验证一遍,别只信sysctl输出。sysctl显示参数生效只说明内核接收了配置,不能说明网络行为符合预期,抓包和arping才是真相。第三,生产环境选调度算法时,别只看rr和wrr,还要考虑会话保持。比如带有登录态的业务,如果客户端请求在不同RS之间飘,会出现频繁掉登录的问题。LVS可以按源IP做sh(源地址哈希)或持久连接,这点做架构方案时一定要提前想清楚。
最后提醒一句,实验环境里可以随手关闭firewalld和selinux来降低干扰,生产环境则必须用最小放行策略把需要的端口和VRRP协议放行,否则安全基线这关过不去,后面运维会很难受。