等价多路径让一台路由器在多条代价相同的下一跳之间分摊流量。散列若只用外层报文头,一次 VPN 会话里的全部连接会算出同一个结果,于是在这一段走同一条成员。截至 2026 年 10 月,这和任播是两套选择。任播选的是这个 IP 落到哪一处,等价多路径选的是这一台路由器上的哪一条下一跳。
散列在保持哪一条流
一个可独立引用的定义句:等价多路径(ECMP)是一台路由器对同一目的地有多条代价相同的下一跳时,把流量分到这些下一跳上的转发方式。
据 RFC 2991,按包轮流使用不同下一跳会造成乱序。为了避免乱序,常见做法是让同一条流一直走同一条下一跳。一条流可以用地址来识别,也可以用地址加上协议和端口。用哪些字段、用什么散列,并没有一份所有实现必须相同的算法。
链路聚合在一条逻辑链路上选择成员链路时,用的是同一类散列。下文说的成员,既包括等价路由的下一跳,也包括聚合组里的一条物理链路。
| 识别一条流的常见输入 | 隧道封装之后还能否用来区分内层连接 |
|---|---|
| 源地址和目的地址 | 看得到,但变成了隧道两端。许多内层连接共用这一对 |
| 协议和源、目的端口 | 看得到外层端口。内层端口在加密之后不可见 |
| IPv6 流标签 | 只有外层是 IPv6 时才有。入口可以按内层流填写,见下文 |
外层把许多连接收成一条
一个可独立引用的定义句:据 RFC 6438,IP 隧道把许多内层流收成一对隧道端点之后,外层的地址、协议和端口往往都相同。等价多路径或链路聚合的散列因此变成常数,负载不会再被拆开。 该文档把这种结果称作极化:流量没有按设计摊到各条成员上。
远程接入 VPN 经常落在这个情形里。一次会话若只占用一个外层五元组,也就是本机地址、服务器地址、外层协议、本机源端口和服务器端口,你和服务器之间的路由器就把其中的每条连接看成同一条流。去往不同网站的内层包,在这一段走同一条成员。
拆包之后重新分开。出口向公网转发时,内层五元组再次可见,后面的等价多路径可以按不同的目的地把它们分到不同成员。挤在一条上的,是本机和 VPN 服务器之间的那一段。
有两种已经写进规范的做法,可以让外层散列重新带上内层的差别。本文没有对某一客户端测量它用的是哪一种:
- 外层若是 IPv6,入口可以为每一条内层流写一个外层流标签。据 RFC 6438,同一条内层流必须使用同一个流标签。中间路由器的散列至少要包含目的地址、源地址和流标签。这样可以在不阅读加密内容的情况下,把不同的内层流分到不同成员。
- 实现也可以让不同的内层流使用不同的外层端口。那就不再是一个会话只有一个五元组。是否如此,要看该实现,不能从协议名称推出来。
一次连接背后的封装 说明外层头为什么挡住内层。散列只能使用它看得到的那一层。IPv4 外层没有流标签。这一段若要区分内层流,就得让外层五元组本身发生变化。
和任播分开
任播 把同一个 IP 从多处宣告出去,路由按从源位置出发的度量选一个落点。等价多路径则是某一台路由器上的多条下一跳,度量已经相同,剩下的选择交给散列。
| 任播 | 等价多路径 | |
|---|---|---|
| 选择发生在哪 | 路由系统里,这个前缀的多处宣告 | 一台路由器已经装上的多条等价下一跳 |
| 目的 IP | 可以仍是同一个地址 | 也可以仍是同一个地址 |
| 只改外层源端口 | 通常不因此换一个任播站点 | 五元组变了,散列可能换一条成员 |
| 和地理标签 | 落点所在的城市可以改变 | 成员链路变了,地址的注册城市可以不变 |
出口地址换成另一座城市,先看服务器有没有换,或任播的落点有没有变。延迟变化也可以只是另一条成员的队列更长。城市标签可以保持不变。
乱序,以及探测画出的是哪一条
按包轮询会让同一条外层流的包走不同成员,到达顺序和发送顺序不一致。接收窗口若比这份乱序更窄,过晚到达的包会被丢掉。见 重放保护。TCP 也可能把乱序当成丢包,从而减小窗口,见 拥塞控制。
路由跟踪用的探测,常常不是隧道那个五元组。Ping 与路由跟踪 里,探测可以是 ICMP,也可以是逐跳更换端口的 UDP。ICMP 没有传输层端口。散列若使用端口,这类探测和 UDP 隧道就不会落在同一条成员上。实现若还使用别的字段,两条路径仍可能不同。本文没有对某一台路由器的散列输入做测试。图上多出来的一跳,先当成「探测自己的成员」,再决定它是不是隧道正在用的路。
一个可独立引用的结论句:重新建立外层会话之后源端口变了,散列可能换一条成员。这是五元组变了的结果,不能单独当成出口城市改变的证据。 本文不写为了更换成员而修改端口的做法。
现象对照
| 现象 | 更可能先看什么 |
|---|---|
| 隧道里许多网站一起变慢,拆包之后的路径并不拥挤 | 本机和服务器之间的那一条成员在排队 |
| 只有某一次重连之后延迟不同,服务器 IP 没变 | 外层五元组变了,散列可能换了成员 |
| 路由跟踪的路径和业务延迟对不上 | 探测的散列输入和隧道的五元组不同 |
| 同一条隧道里出现明显乱序 | 某一跳在按包而不是按流分发 |
| 外层是 IPv6,不同网站的延迟彼此独立 | 入口可能按内层流写了不同的流标签 |
核对清单
- 先数这一段有几个外层五元组:只有一个时,中间路由器按这一条流选择成员;
- 把等价多路径和任播分开记:前者换的是下一跳,后者换的是这个 IP 的落点;
- 路由跟踪另算一份散列:探测的端口或 ICMP 和隧道不是同一条流;
- 乱序先对照重放窗口:按包分发会让编号晚到;
- 流标签只出现在外层 IPv6:IPv4 隧道没有这一字段可以用来区分内层流。