文章

【笔记】四层负载均衡的数据路径与回包模型

【笔记】四层负载均衡的数据路径与回包模型

四层负载均衡最容易产生的误解,是看到后端保留客户端 IP,就直接猜它使用了 DSR、隧道或某种 TCP Option。仅凭一个地址现象无法确定完整数据路径。

一句话心智模型是:分别追踪请求和回包经过的地址转换、下一跳与状态归属;“后端看见谁”只是其中一个观测点。

1. 一个连接有三种观察视角

客户端建立的是:

1
ClientIP:ClientPort → VIP:ServicePort

后端可能看到:

1
ClientIP:ClientPort → RSIP:BackendPort

客户端最终仍必须收到:

1
VIP:ServicePort → ClientIP:ClientPort

如果后端回包直接以 RSIP 为源地址到达客户端,客户端 TCP socket 的远端四元组对不上,连接不能正常成立。因此,后端看到真实源地址时仍然要回答两个独立问题:

  1. 请求方向如何选中并送达 RS?
  2. 回包如何恢复客户端期望的 VIP 身份?

2. 四种典型数据路径

2.1 Full NAT:两个方向都转换

sequenceDiagram
    participant C as Client
    participant L as LB
    participant R as RS
    C->>L: Client → VIP
    L->>R: LB-SNAT → RS-DNAT
    R->>L: RS → LB-SNAT
    L->>C: VIP → Client

LB 同时修改源地址和目的地址。后端看到的对端通常是 LB 地址,回包自然返回 LB。优点是路径容易闭环;代价是后端丢失网络层客户端地址,并且双向流量都经过状态设备。

2.2 DNAT + 保留源地址:后端看到 Client

请求方向只改目的端:

1
2
Client → VIP
Client → RS

回包必须再次经过掌握该连接映射的处理点,再做反向转换:

1
2
RS → Client
VIP → Client

传统网络通常通过把 RS 的回程下一跳放在 NAT 设备方向来满足;云网络可以在受控虚拟网络中实现回程引流。但“云厂商可以做到”不等于已知它具体通过策略路由、SmartNIC、ToR、集中式网关还是分布式状态机实现。

2.3 Direct Routing / DSR:请求经 LB,回包由 RS 直接发出

经典 LVS-DR 不把目的 IP 改成 RS IP,而是在二层把报文交给某个 RS。RS 需要在本地以不响应错误 ARP 的方式持有 VIP,并以 VIP 作为回包源地址:

1
2
请求:Client → VIP,经 Director 选择 RS
回包:VIP → Client,由 RS 直接发送

因此,DSR 的“直接回包”不是让客户端接受 RSIP,而是让 RS 用客户端原本连接的 VIP 身份回包。

2.4 IP Tunnel:外层负责送达 RS,内层保留 VIP

经典 LVS-TUN 对原始包再封装一层 IP header:

1
2
Outer: Director → RS
Inner: Client → VIP

RS 解封装后处理内层 Client → VIP,并可用 VIP 直接回客户端。它要求 RS 支持相应 tunnel,增加封装开销和 MTU 约束。这里的 TUN 是 IP tunnel 模式,不等同于 Linux /dev/net/tun 的通用 TUN/TAP 设备概念。

3. “真实 Client IP”不能唯一确定转发模式

下面几种情况都可能让应用或内核获知 Client IP:

  • 网络包本身保留源地址;
  • Proxy Protocol 在连接前置头里携带地址;
  • L7 代理写入 ForwardedX-Forwarded-For
  • 某些实现把地址放入 TCP Option,再由内核扩展暴露给应用。

ss/netstat 直接显示 Client IP,通常说明 Linux TCP socket 的网络层对端就是 Client,而不是仅从 HTTP header 读取。但这仍不能区分 DNAT 源地址保留、DR、TUN 或云厂商自定义数据路径。

要判断模式,至少同时观察:

1
2
3
4
5
ss -tnp
tcpdump -ni any 'tcp port 443'
ip addr
ip route show table all
ip rule

还要确认 RS 是否持有 VIP、请求包到达时的目的地址、回包的源地址和实际下一跳。

4. 四元组冲突能证明什么

假设同一个 Client socket 先后访问两个 VIP:

1
2
Client:41358 → VIP1:443
Client:41358 → VIP2:443

若两个入口最终都让同一个 RS 看到:

1
Client:41358 → RS:443

RS 的 TCP 栈失去了区分 VIP1、VIP2 的维度。如果旧连接仍处于 TIME_WAIT,新连接可能与已有四元组冲突。

从这个现场可以推导:

  • 后端确实看到了原始 Client 地址和端口;
  • 两个 VIP 在进入后端 socket 前都被归一化为相同 RS 地址和端口;
  • 云侧必须在别处保留 VIP、RS 与连接的关联,否则无法向客户端恢复 VIP 身份。

但仅凭这张图不能证明:

  • 底层一定是 Linux conntrack;
  • 一定运行 LVS-NAT、LVS-DR 或 LVS-TUN;
  • 回程一定由某种特定 Fabric、交换机或 SmartNIC 引流。

“存在等价的连接状态与回程处理”是协议行为推论;状态具体存在哪里是实现事实,需要厂商资料或数据面观测。

5. 阿里云案例的事实边界

阿里云公开文档对不同产品、监听器和服务器组提供客户端地址保留能力。是否默认开启、是否支持 Proxy Protocol、跨地域或 PrivateLink 场景有什么限制,应以具体 CLB/NLB 实例类型和当前文档为准,不能把某个产品的行为推广到所有“阿里云四层 SLB”。

结合现场 ss/netstat 与故障图,可以确认的最小结论是:

  1. 该场景的 RS socket 对端是 Client,而非 SLB;
  2. RS socket 的本地端是 RS,而非两个原始 VIP;
  3. 云网络存在让回包以 VIP 身份返回客户端的处理;
  4. 公开证据不足以确定内部回程实现。

这比“阿里云就是 LVS-DR”或“整个 Fabric 共同维护 conntrack”更弱,但证据足够,且不会把架构猜测包装成事实。

6. 一套可复用的排障表

问题观测方法能得到的结论
RS socket 对端是谁ss -tnpTCP 栈感知的远端地址
RS 收到的 IP 包是什么tcpdump到达抓包点的源/目的地址
RS 是否持有 VIPip addr是否可能采用经典 DR/TUN 的 VIP 本地处理
回包下一跳是谁ip route get <client>Guest 内核选择的路由,不代表云侧最终路径
是否有策略路由ip rule、各 routing tableGuest 内可见的回程选择
应用地址来自哪里检查 Proxy Protocol、HTTP header、socket API区分网络层透传与附加元数据

抓包位置也属于结论边界:any、物理/虚拟接口、tc/XDP 之前或之后可能看到不同形态。云厂商闭源数据面无法仅从 Guest 内一次抓包完整还原。

7. 复习索引

  • 后端看到 Client IP,不等于已经知道 LB 模式。
  • Full NAT 让回程自然经过 LB,但后端通常看不到 Client 网络地址。
  • DNAT 保留源地址时,需要额外保证回程重新进入反向转换路径。
  • DSR 的 RS 以 VIP 回包;不是让 Client 接受 RSIP。
  • TUN 用外层 IP 把仍以 VIP 为目的的内层包送到 RS。
  • 四元组冲突可以证明 VIP 维度在后端 socket 前消失,不能证明状态机部署位置。
  • 云产品行为要按产品、监听器和服务器组核对,闭源实现未知就明确保留未知。

8. 核验入口

本文由作者按照 CC BY 4.0 进行授权