首页 / 资讯中心 / 文章详情

LVS DR模式全解析:原理、配置与高可用实战

LVS DR模式全解析:原理、配置与高可用实战 ★ FEATURED ARTICLE
做了好几年负载均衡相关的工作我越来越觉得 LVS DR 模式Direct Routing是四层负载均衡方案里最值得花时间吃透的那一个。它不像 NAT 模式那样所有流量都堆在入口也不像 TUN 模式那样要额外维护隧道封装却能在高并发场景下把吞吐、延迟和成本平衡得很舒服。这篇文章不是简单抄一遍 ipvsadm 命令而是想把我理解的 Direct Routing 数据包流转过程、真实环境配置步骤、以及那些让我半夜爬起来查日志的坑认认真真讲一遍。无论你是正在给后端集群搭入口还是面试前想把 DR 模式说清楚这篇内容应该都能派上用场。1. 为什么是 DR四层负载均衡方案的取舍与选型逻辑1.1 LVS 的几种工作模式到底差在哪LVS 本身有三种经典模式NAT、TUN、DR后来一些衍生方案里又看到过 FULLNAT。很多新手第一次接触这套东西容易被“改 MAC、改 IP、隧道封装”这些词绕晕。我的习惯是先想清楚一个问题这份流量到底谁来回NAT 模式下Director 既要改写目标 IP还要承担全部响应流量。哪怕后端 RS 已经把数据准备好了也得原路返回给 Director再由 Director 送回客户端。这意味着 Director 的网卡、CPU、连接表全都暴露在双向流量压力下带宽很容易成为瓶颈。TUN 模式则是把原始 IP 报文再包一层新的 IP 头通过隧道送去后端的 RS。它的优势是可以跨越三层网络部署后端但代价是每台 RS 都要支持隧道接口并且 MTU、分片问题会时不时冒出来排错成本并不低。DR 模式走的是另一条路Director 和所有 RS 在同一个二层广播域里Director 收到客户端请求后只改写数据帧里的目标 MAC 地址IP 层完全不动然后把帧从网卡扔出去。RS 拿到这个帧发现目的 IP 是 VIP本地恰好也有这个 VIP于是像处理普通请求一样处理响应包则由 RS 直接回给客户端完全不经过 Director。三种模式整理成表格会更清楚模式Director 改什么响应包路径后端要求主要瓶颈NAT目标 IP/端口必须回 Director可跨网段Director 双向流量TUNIP 隧道封装RS 直达客户端需隧道接口可跨网段封装开销、MTUDR二层帧 MACRS 直达客户端同二层广播域无但受二层范围限制我自己在选型时除非后端机器明确分布在多个机房否则第一选择基本都是 DR。原因很朴素它把“转发”这件事降到最低成本后端只要会写应用不需要理解复杂的隧道协议。1.2 选 DR 之前要接受的三个限制DR 模式不是没有代价。它之所以能这么轻量是因为它把一个重要矛盾推给了网络设计后端必须能直接响应客户端并且必须和 Director 在同一个二层网络里。这个条件决定了三个限制。第一所有 RS 必须和 Director 处于同一个 VLAN 或者可二层互通的广播域。如果网络被划分成多个隔离网段DR 默认就玩不转了。虽然通过策略路由、ARP 代理之类的手段也能做扩展但那已经属于生产环境的特殊操作不建议新手一上来就碰。第二后端 RS 必须自己持有 VIP并且要保证不应该对外响应 VIP 的 ARP。这句话听起来矛盾实际是 DR 模式最精髓的地方VIP 必须存在于每台 RS 上好让内核接收发往 VIP 的数据包但同时这个 VIP 又不能“漏”到二层网络里否则交换机的 ARP 表会把 VIP 对应的 MAC 学成多份客户端请求就乱了。第三端口必须保持一致。Director 不能像 NAT 模式那样把 80 端口映射成 8080因为请求到了 RS 之后目标 IP 和端口都还是原来的值。如果 RS 上业务监听的是 8080请求打过来访问 80 端口RS 连接就建立不起来。所以在立项的时候我通常会先确认三件事后端能不能直接上网机房网络是不是同一个二层业务端口能不能统一只要这三个问题都能答“是”DR 模式基本就是最优解。2. Direct Routing 的数据包旅程一次请求里藏着整个方案的秘密2.1 从客户端到 Director再到 Real Server 的完整路线Direct Routing 这个名称很容易被误读成“直接路由转发”其实它更接近“二层直连”的意思。为了把原理讲明白我先给一套具体的 IP 规划客户端 CIP198.51.100.50VIP192.0.2.100Director 物理 IP192.0.2.10RS1 IP192.0.2.11RS2 IP192.0.2.12网关192.0.2.1一次完整的 HTTP 请求数据包经历的过程大概是这样的客户端首先把 TCP SYN 发往 VIP 192.0.2.100:80。交换机通过 ARP 查询得知VIP 对应的 MAC 是 Director 的网卡 MAC于是这个帧进入 Director 的 eth0。Directro 的内核收到数据后ip_vs 模块根据虚拟服务器规则选出一台 RS比如 RS1。关键动作发生在第二层Director 把这个帧的目标 MAC 从自己的 MAC 改成 RS1 的 eth0 MAC源 MAC 改成自己的 MAC然后从 eth0 再扔出去。这个过程中帧里的源 IP、目标 IP、TCP 端口全部都没有变。交换机看到目标 MAC 指向 RS1于是把帧送到 RS1。RS1 的 eth0 收到帧后IP 层发现目标 IP 是 192.0.2.100而本地 lo:0 接口上正好配了同一个地址因此内核把它当作本机数据交给监听 80 端口的应用。应用处理完请求生成响应报文源 IP 自然就是 VIP 192.0.2.100。那响应报文怎么回去RS1 查路由表发现目标 IP 198.51.100.50 不属于本地网段于是走默认路由通过网关 192.0.2.1 出去。整个响应过程不需要再绕回 Director。这就是 DR 模式最让人舒服的地方入站流量只决定“把请求引导给哪台机器”出站流量全部由 RS 自己完成。2.2 为什么这套模式能有这么高的吞吐很多人把 LVS 叫作七层代理这是不对的。LVS 的核心是一个四层连接转发表它不终结 TCP 连接也不解析 HTTP 内容。客户端和 RS 之间真正完成了 TCP 三次握手、数据传输、挥手全流程Director 只是负责在关键节点上决定“这个数据包应该交给谁”。我用一个生活化的类比来讲Director 不是快递员快递员是 RS 自己Director 更像小区门口那个指路的保安他不需要亲自帮每一户把快递搬上楼他只需要知道每栋楼在哪个位置然后告诉送快递的人往哪走。因为只做“指路”Director 能扛的并发规模就远远高于那种既要接单又要派送的模式。当然这里也不是真的“指完路就再也不管”。LVS 会在内部维护一张连接转发表记录五元组信息和选中的 RS。属于同一条连接的后缀数据包到达 Director 后会被查表并继续转发给同一台 RS。所以严格说入站方向的每个包都会经过 Director只是 Director 不需要做复杂计算工作量大为降低。正因为如此DR 模式特别适合那种“请求很小、响应很大”的业务比如文件下载、图片加载、视频片段分发。入站可能只有几个 KB 的请求回包却可能达到几十 MB如果回包也要经过 Director那瓶颈会非常明显。2.3 只改 MAC 不改 IP为什么这点很关键理解 DR 模式一个重要支点就是“为什么只改 MAC”。如果 Director 把目标 IP 改成 RS 的物理 IP那么 RS 响应时源 IP 就会变成物理 IP。客户端收到的响应来源不是 VIPTCP 连接自然对不上必须靠 NAT 再把源 IP 改回来这就被迫把响应流量也拉回 Director 处理。一旦把目标 IP 改成 VIP而 VIP 又存在每台 RS 上那么 RS 可以用 VIP 作为响应源地址客户端看起来就是一台稳定的服务器。MAC 地址的作用范围只在二层网络。Director 和 RS 处于同一个广播域时通过改写目标 MAC 就能把帧送到指定主机。这个过程不需要修改 IP 报文避免了 NAT 带来的性能消耗也避免隧道封装带来的额外协议头。简单总结就是改 MAC 是为了在“同一个二层网络内”完成导流不改 IP 是为了让“RS 能以自己的 VIP 身份直接回包”。这两个条件缺一不可也正好解释了 DR 模式为什么要依赖二层互通的网络结构。3. 从零搭一套 DR 共享网段实验环境3.1 网络拓扑和 IP 规划纸上谈兵不如动手。下面的实验环境是我在本地用虚拟机常搭的一套结构三台机器都跑在同一个虚拟交换机上模拟生产环境里一个普通 VLANDirectoreth0 为 192.0.2.10/24负责承载 VIP 192.0.2.100/24并担任 LVS 转发节点RS1eth0 为 192.0.2.11/24业务监听 80 端口RS2eth0 为 192.0.2.12/24业务监听 80 端口网关192.0.2.1负责把出网流量带走有一点要特别交代VIP 不要配在交换机上它只是一台或多台 Director 网卡上的逻辑地址。实验里也不用做 VLAN 隔离所有机器都在同一个子网即可。我在规划阶段最想强调的其实是反向思考VIP 应该看成“谁提供服务谁持有”的地址。Director 持有它是为了对外接收请求RS 持有它则是为了能以内核认可的方式接收转发过来的请求。两边都要有 VIP但两边对 ARP 的响应策略完全不同。3.2 准备三台机器与基础检查机器我建议用最小化安装的 Linux 系统版本新一点没关系关键是内核要支持 IPVS。现在主流发行版默认都带了 ip_vs 模块只是不一定自动加载。开始操作前先把模块抓出来看看modprobe ip_vs lsmod | grep ip_vs如果 lsmod 输出里有 ip_vs 相关的行说明内核模块已经就绪。如果找不到优先检查是不是内核没有加载模块或者包管理工具里有没有 ipvsadm 和 keepalived。RHEL 系的话直接装yum install -y ipvsadm keepalivedDebian 系对应的是apt install -y ipvsadm keepalived装完之后先把三台机器的网络都调通。至少要做三件事确认 eth0 都获得了规划好的 IP、确认彼此之间能 ping 通、确认默认路由都指向 192.0.2.1。很多 DR 问题最后查出来都是默认路由不对这一步不能省。检查命令很简单ip addr ip route ping -c 3 192.0.2.11 ping -c 3 192.0.2.123.3 需要提前确认的路由与转发问题Director 要负责转发数据包第一个要开的系统参数是 ip_forwardsysctl -w net.ipv4.ip_forward1如果不开启这个参数Director 收到目标是 VIP 的包之后即使 IPVS 规则存在也可能不会继续往 RS 送。这属于底层转发行为不是 IPVS 自己就能覆盖的。第二个要关注的是反向路径过滤。Linux 内核默认可能有 rp_filter 保护用来防止源地址伪造攻击。但在 LVS DR 场景下数据包从 eth0 进入源 IP 是客户端地址反向查路由可能会因为路由表不够“对称”而丢包。我在不少内核版本上遇到过这种情况建议实验阶段先把相关过滤关掉避免它干扰排错sysctl -w net.ipv4.conf.all.rp_filter0 sysctl -w net.ipv4.conf.eth0.rp_filter0第三个要注意的是RS 的默认路由必须保留。很多人看完 DR 的原理误以为响应包只要从 lo 口出去就行于是把默认路由改到 lo 上结果机器直接失去和外界的通信。RS 的默认路由必须指向真实网关出网流量要能从 eth0 出去这一点后面细说。4. Director 与 Real Server 的配置落地照着敲就能跑通4.1 Director 侧让内核和 ipvsadm 进入工作状态Director 上的配置分两层一层是网络地址一层是 IPVS 规则。先配置 VIP。我习惯用 ip 命令直接操作快速验证时最方便ip addr add 192.0.2.100/24 dev eth0 label eth0:0这个命令会在 eth0 上叠加一个别名接口 eth0:0地址是 192.0.2.100。配置完成后Director 才会对这个地址回应 ARP交换机也才能学会 VIP 对应 Director 的 MAC。接着添加 LVS 虚拟服务。以 HTTP 为例使用加权轮询算法ipvsadm -A -t 192.0.2.100:80 -s wrr ipvsadm -a -t 192.0.2.100:80 -r 192.0.2.11:80 -g -w 1 ipvsadm -a -t 192.0.2.100:80 -r 192.0.2.12:80 -g -w 1第一条创建虚拟服务第二条和第三条把两台 RS 加入服务组。-g表示使用 DR 模式-w是指定权重。如果这里忘了写-g默认可能进入 NAT 模式那响应路径就完全不是 DR 了。查看规则和统计信息ipvsadm -L -n --stats ipvsadm -L -n --rate如果--stats里的 InBytes 和 OutBytes 都在涨说明转发已经开始工作。不过要注意DR 模式下 OutBytes 通常很小因为响应流量不经过 Director。如果只做临时验证这些命令就够了。正式环境一般会配合 Keepalived规则由 Keepalived 动态下发而不是直接写在 ipvsadm 里。4.2 RS 侧lo:0、ARP 抑制、默认路由缺一不可RS 的配置是 DR 模式最容易出问题的地方。少了任何一环连接都可能建立不起来。先把 VIP 放到回环接口上。注意这里用的是 /32ip addr add 192.0.2.100/32 dev lo label lo:0为什么不用 /24因为 RS 上的 VIP 只是一个“让内核认为这是本机地址”的标志它不需要参与广播域里的网络段计算。配成 /32 最干净避免路由表各种奇奇怪怪的问题。然后配置 ARP 抑制。这是最关键的一步也是很多新手最懵的一步。RS 上有 VIP但对外不能抢答 VIP 的 ARP 请求否则邻居会认为 VIP 同时存在于多台机器。标准参数是sysctl -w net.ipv4.conf.all.arp_ignore1 sysctl -w net.ipv4.conf.all.arp_announce2 sysctl -w net.ipv4.conf.lo.arp_ignore1 sysctl -w net.ipv4.conf.lo.arp_announce2 sysctl -w net.ipv4.conf.eth0.arp_ignore1 sysctl -w net.ipv4.conf.eth0.arp_announce2arp_ignore1的意思是不再对所有“目标 IP 等于本地任意接口地址”的 ARP 请求都回复而只回复目标 IP 正好属于请求网络接口的那个地址。RS 的 eth0 上没有 VIP所以外界询问 VIP 时RS 保持沉默。arp_announce2的意思是让本机在对外发送 ARP 通告时尽量使用最合适的本地 IP 作为源地址避免把 lo:0 上的 VIP 当作源地址通告出去。这一条在 RS 需要对外主动发送报文时特别重要。为了保险还可以顺手关闭反向路径过滤sysctl -w net.ipv4.conf.all.rp_filter0 sysctl -w net.ipv4.conf.eth0.rp_filter0再把 eth0 的默认路由确认一遍ip route add default via 192.0.2.1 dev eth0最后启动业务进程。监听地址可以写 0.0.0.0:80也可以写 192.0.2.100:80。如果写后者一定要确保 VIP 已经配置在 lo:0 上否则服务根本起不来。4.3 验证链路用 ipvsadm 和 tcpdump 确认转发路径配置全做完不要急着欢呼。先做个端到端验证在客户端持续访问 VIP然后在 Director、RS 上分别抓包对比路径。客户端可以用一个持续请求curl http://192.0.2.100/在 RS 上抓包应该能看到来自 Director 转发过来的请求包以及本机回给客户端的响应包tcpdump -ni eth0 tcp port 80在 Director 上抓包正常情况下只能看到客户端发往 VIP 的入站请求响应方向的包不应该出现。如果 Director 同时抓到大量响应包说明网络里可能发生了路径回流或者 RS 配置有问题响应被错误地送回了 Director。再回到 Director 上查看连接状态ipvsadm -L -n -c这里能看到活跃的连接记录每一行都记录着客户端 IP、VIP、RS IP 以及连接状态。看到这些条目不断出现、消失、再出现基本可以确认数据通路是通畅的。5. 我踩过的 DR 模式生产坑ARP、默认路由和长连接5.1 ARP 通杀问题VIP 出现在所有 RS 上的后果DR 配置里最阴险的坑就是 ARP 通杀。有些文章为了省事只让你在 RS 上加sysctl -w net.ipv4.conf.all.arp_ignore1没有让你同时配置具体接口。我在生产环境里遇到过这么一次客户端访问 VIP时通时不通大概每三五次请求就有一次超时。一开始怀疑后端服务不稳定后来发现问题是所有 RS 都对 VIP 的 ARP 请求作了应答。因为 VIP 配置在每台 RS 的 lo:0 上如果不限制 ARP 响应规则Linux 会把这个地址当作“本机拥有的地址”来响应整个二层网络的 ARP 请求。于是交换机的 ARP 表里192.0.2.100 一会儿对应 Director 的 MAC一会儿对应 RS1 的 MAC一会儿又变成 RS2 的 MAC。客户端发出去的报文可能被交换机随机送到任意一台机器而只有 Director 上的 IPVS 才知道怎么转发其他机器收到后自然就是黑洞。解决起来不算复杂就是把我前面写的那几条 sysctl 参数全部配置到位特别是接口级的conf.lo和conf.eth0也要一起写。配置改完后最好在两台 RS 上分别执行ip neigh flush all同时清掉交换机的动态 ARP 缓存。如果交换机可以重启接口也会加速收敛。另外提醒一句不要试图用防火墙把 RS 的 ARP 请求挡掉ARP 是二层协议iptables 对它的拦截非常有限。与其折腾防火墙不如老老实实配好 sysctl。5.2 RS 上的默认路由不能乱来第二个大坑是路由。我见过有人在 RS 上执行了这样一条命令ip route add default dev lo这人以为“DR 模式下响应包要从 lo 走到 VIP”结果整台 RS 的所有出网流量都走回环接口TCP 三次握手的 SYN 都能收到但响应包永远送不出去。客户端表现就是连接一直卡在握手状态超时后失败。理解这个坑之前要先分清两个概念VIP 放在 lo:0 上是为了让内核识别“这个 IP 是本机的”而不是为了让流量从 lo 出去。真正要出去的流量必须经过 eth0 和网关。所以 RS 上的路由表至少应该有两条核心路由一条是 eth0 对应的网段路由另一条就是默认路由default via 192.0.2.1 dev eth0。如果因为某些自动化脚本把默认路由改坏了立刻改回来即可ip route replace default via 192.0.2.1 dev eth0还有一种容易被忽略的情况RS 上如果配置了多块网卡源地址选择可能会踩到策略路由的问题。DR 模式下我习惯把业务网卡和其他管理网卡分开并用ip rule明确主备关系但新手阶段先不要引入太多策略路由保持一张网卡、一条默认路由最不容易出错。5.3 调度算法、会话保持和长连接超时LVS 支持的调度算法不少但不是越复杂越好。我自己的选型经验是算法适合场景rrRS 配置完全一致请求成本均匀wrrRS 配置有差异需要按权重分配wlc长连接多、连接存活时间差异大的场景sh希望同一个来源 IP 始终打到同一台 RSwlc 全称是 Weighted Least Connections它会把新请求优先分配给当前活跃连接数最少的 RS。后端连接处理时间差异大的业务用 wlc 效果往往比轮询好。但如果是无状态短连接、RS 性能又一致rr 和 wrr 足够。会话保持方面如果业务自身不依赖 session尽量别开持久连接因为持久连接会让某个来源 IP 的请求长时间固定在一台 RS 上导致负载不均。如果必须开用ipvsadm -p指定超时时间比如保持 10 分钟ipvsadm -E -t 192.0.2.100:80 -s rr -p 600或者添加规则时直接带上-p 600。另一个很容易踩的坑是 LVS 自身的 TCP 连接表超时。默认配置下TCP 空闲连接超过一定时间后LVS 会认为连接已经结束把连接表里的记录回收。如果客户端和后端 RS 之间有一条还活着的长连接但长时间没有数据传输下一个数据包到来时 LVS 可能把它当成新连接调度到另一台 RS而旧 RS 上根本没有这个 TCP 连接于是连接被重置。碰到这种业务可以手动调大超时时间。比如把 TCP 连接超时改到 1 小时ipvsadm --set 3600 120 300这条命令分别设置 TCP、TCP FIN、UDP 的超时秒数。调整完之后长连接就不容易被 LVS 半路“遗忘”了。如果你同时在使用 Keepalived 管理 IPVS需要注意 Keepalived 启动时可能会重置部分 IPVS 规则超时参数最好在 Keepalived 配置里也体现或者在业务真正起来后再执行ipvsadm --set确保规则生效。6. 结合 Keepalived 做高可用DR 模式下的实践配置6.1 Keepalived 如何接管 VIP 和虚拟服务器单台 Director 做得再好也存在单点风险。生产环境里我通常用两台 Director 配合 Keepalived组成一主一备靠 VRRP 协议实现 VIP 漂移。Keepalived 的配置分成两段一段负责 VRRP一段负责 IPVS 虚拟服务器。主节点配置大致如下global_defs { router_id LVS_DR_MASTER } vrrp_instance VI_1 { state MASTER interface eth0 virtual_router_id 51 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 1234 } virtual_ipaddress { 192.0.2.100/24 dev eth0 label eth0:0 } } virtual_server 192.0.2.100 80 { delay_loop 6 lb_algo wrr lb_kind DR persistence_timeout 60 protocol TCP real_server 192.0.2.11 80 { weight 1 TCP_CHECK { connect_port 80 connect_timeout 3 retry 3 } } real_server 192.0.2.12 80 { weight 2 TCP_CHECK { connect_port 80 connect_timeout 3 retry 3 } } }备用节点只需要把state改成BACKUPpriority改低并在global_defs里换一个router_id其他内容保持一致。VRRP 会在主节点故障后让备用节点接管 VIP 并发送免费 ARP把交换机里 VIP 对应的 MAC 更新到备用 Director 的网卡。需要注意auth_pass在 Keepalived 的配置里不要设置太复杂的特殊字符两台机器必须完全一致否则 VRRP 包可能验证失败。很多人会问既然 Keepalived 能自动管理 IPVS那第 4 节里手动敲的 ipvsadm 还需要吗我的建议是先手动搭一遍确认网络和转发逻辑没问题再交给 Keepalived 接手。因为如果一开始就自动化配置出现问题时反而不知道是网络问题还是配置问题。6.2 故障切换时 RS 侧要不要跟着改这个问题经常有人搞混。Keepalived 接管的是 Director 上的 VIP不是 RS 上的 VIP。RS 的 lo:0 上依然保留着 192.0.2.100不管主备 Director 怎么切换RS 都不需要改任何配置。原因就在于 ARP 抑制参数。RS 上的 VIP 虽然存在但对外不响应 VIP 的 ARP 请求。整个二层网络里只有当前处于 MASTER 状态的 Director 会响应这个 VIP 的 ARP。主备切换后新 MASTER 发出免费 ARP交换机的 MAC 表随之更新客户端感知不到任何变化。所以这里有一个硬性禁止绝对不要为了“高可用”而把 VIP 配置到 RS 的 eth0 上。如果 VIP 出现在 RS 的物理接口上即使配置了 ARP 抑制也无法完全保证交换机的 ARP 学习行为符合预期。最稳妥的做法就是让 VIP 只出现在 Director 的 eth0 别名和 RS 的 lo 别名上中间不要有任何混淆。6.3 健康检查还要注意什么Keepalived 默认的 TCP_CHECK 只能确认 TCP 端口能连上但它不能判断业务是否真的可用。比如后端服务卡死端口还能 accept但 HTTP 请求已经 5 秒不回这时 TCP_CHECK 依然会判断节点健康。生产环境我见过两种做法。一种是在 real_server 里配置 HTTP_GET 检查让 Keepalived 定期请求一个固定 URL通过响应状态码判断服务是否真正可用。这个方法更贴近用户视角但配置稍微复杂要注意请求超时不要影响业务本身。另一种做法是保留 TCP_CHECK 作为兜底同时在外面加一层独立的拨测系统定时请求 VIP 上的业务 URL发现异常就告警。这两种方式我建议至少有一个毕竟 LVS 只能保证“流量转发到了”不保证“转发到了之后应用一定没问题”。回到我自己的实践每套 DR 高可用环境验收时都会做三件事先临时把备用 Director 停掉确认 VIP 能快速回切到主节点再临时把主 Director 的网卡断掉确认备用节点能接管且业务无损最后把所有 RS 的 lo:0 临时去掉确认 VIP 的 ARP 只会由 Director 响应不会存在多 IP 多 MAC 的混乱情况。经历过几次线上故障之后我现在再看 DR 模式心态已经比较坦然。它确实高效但高效不等于无脑。只要遵循“VIP 归属清晰、ARP 响应收敛、默认路由可靠”这几条原则绝大多数诡异问题都能提前规避。希望这篇从一个运维和开发双视角写下来的实践记录也能帮你少走一条弯路。
阅读完成 · 觉得有帮助?
咨询建站