上一篇 下一篇 分享链接 返回 返回顶部

如何在香港服务器的 Linux 上用 MPTCP 绑定 CN2 与 GIA 双线路,稳住跨境访问?

发布人:Minchunlin 发布时间:2025-09-03 11:19 阅读量:715


凌晨 2:17,我在香港机房外的走廊接到客服的电话:深圳的核心客户后台一片超时,跨境访问抖成筛子。我们香港边缘节点上挂着两根线——CT/CN2 和 CMI/GIA。两条都不差,但单走一条就总有那么几分钟的“玄学丢包”。业务侧最要命的不是“慢”,而是不稳。
我盯着交换机上的口灯,心里盘算:把 CN2 和 GIA 绑成一根“更稳”的逻辑通道。ECMP?对端不可控;纯健康检查切换?切得再快也有中断。必须在传输层做聚合和冗余。答案其实就在眼前:Multipath TCP(MPTCP)。

下面是我那晚从拉通、验证到上线的全过程,包含硬件/网络拓扑、内核与工具链、路由与策略、MPTCP 参数、HAProxy 级联、观测与压测、灰度与回滚,以及踩过的坑。

场景与目标

目标:在 HK 边缘节点把 CN2 与 GIA 两条跨境线路同时纳入一条 MPTCP 连接里,让单连接具备多路径容错/切换/汇聚能力,稳住大陆⇄香港的访问。

约束:客户端(浏览器/APP)不支持 MPTCP。所以我们走**“网关↔网关”**的 TCP 代理链路:
CN-GW(大陆侧访问网关) ⇄ HK-EDGE(香港侧边缘) 用 MPTCP 连,前后都接普通 TCP。

策略:成本可控前提下优先 CN2,GIA 作备份(或相反,视你成本/质量偏好);发生丢包/黑洞时能秒级切到健康路径。

拓扑与设备

[ 客户端/办公地(大陆) ] 
        │  普通TCP/HTTPS
        ▼
[ CN-GW: 大陆访问网关 (ECS/IDC) ]
        ║  (这段是跨境难点)
        ▼  MPTCP(多子流: CN2/GIA)
[ HK-EDGE: 香港边缘节点 ] ──► [ 业务/源站 或 继续转发 ]
        ▲
   CN2 / GIA 物理上行(双上联)

关键硬件参数(实配)

角色 型号/参数 说明
HK-EDGE(物理) 2×Intel Xeon Silver / 64GB / 2×NVMe 本文核心节点
NIC1 Intel X710 10GbE(CN2 上联) eth1, 公网 A.A.A.A/30
NIC2 Broadcom 10GbE(GIA 上联) eth2, 公网 B.B.B.B/30
CN-GW(云主机) 4vCPU/8GB 任意国内合规云,普通 TCP 入
系统 CentOS 7.9(EOL,换内核) / Ubuntu 22.04 我们当晚在 CentOS7 上用新内核;也给出 Ubuntu 路径

为何 CentOS 7 也行? CentOS7 的 3.10 内核没 MPTCP,但可装 ELRepo 的新内核(kernel-ml 5.10+),或你用 Ubuntu 22.04(内核 5.15+)原生支持 MPTCP。MPTCP 在 Linux 5.6+ 主线提供,iproute2 提供 ip mptcp 子命令进行路径管理。

步骤总览

  1. 升级内核 & 工具链(让系统具备 MPTCP)
  2. 双 WAN 策略路由(按源地址/出接口走对的网关)
  3. 启用 MPTCP & 设调度器/PM(sysctl)
  4. 声明端点与子流(ip mptcp endpoint/limits)
  5. 代理链路(HAProxy:CN-GW→HK-EDGE 走 MPTCP;两端保留真实客户端 IP)
  6. 观测/压测/灰度/回滚

1. 升级内核与工具链

CentOS 7(实操当晚用的)

# 1) 加 ELRepo
yum install -y https://www.elrepo.org/elrepo-release-7.el7.elrepo.noarch.rpm
# 2) 安装新内核(示例:kernel-ml)
yum --enablerepo=elrepo-kernel install -y kernel-ml
# 3) 设默认启动到新内核
grub2-set-default 0
grub2-mkconfig -o /boot/grub2/grub.cfg
reboot

升级后确认内核 5.10+(或更高)。

uname -r

安装新版 iproute2(至少包含 ip mptcp 子命令)与工具:

yum install -y iproute iperf3 haproxy
# mptcpize / mptcpd 视发行版源可用性:
# 可从发行版包或源码安装(Ubuntu 见下)

Ubuntu 22.04(推荐更省事)

apt update && apt install -y iproute2 mptcpize mptcpd iperf3 haproxy
# mptcpize/mptcpd:Ubuntu 有现成包

知识点:mptcpize 可以把应用的套接字“转”为 MPTCP,常用于让 iperf3、HAProxy 这类客户端连接强制走 MPTCP。

2. 双 WAN 策略路由(HK-EDGE)

目标:让源自 CN2 IP 的流量一定从 CN2 口出去,源自 GIA IP 的从 GIA 出去,避免错路/回程不一致。

# 假设:
# eth1: CN2,  IP=A.A.A.A/30, GW=A.A.A.1
# eth2: GIA,  IP=B.B.B.B/30, GW=B.B.B.1

# 1) 两个路由表
echo "101 cn2" >> /etc/iproute2/rt_tables
echo "102 gia" >> /etc/iproute2/rt_tables

# 2) 各自表的默认路由
ip route add default via A.A.A.1 dev eth1 table cn2
ip route add default via B.B.B.1 dev eth2 table gia

# 3) 源地址策略(谁的源IP走哪个表)
ip rule add from A.A.A.A/32 table cn2 priority 100
ip rule add from B.B.B.B/32 table gia priority 100

# 4) 主路由保留直连
ip route add A.A.A.0/30 dev eth1
ip route add B.B.B.0/30 dev eth2

这一步不是 MPTCP 特有,而是双上联的必做功课。否则 ip mptcp 指定的源地址也可能被路由到错误的物理口。

3. 启用 MPTCP 与核心参数(HK-EDGE & CN-GW)

/etc/sysctl.d/99-mptcp.conf:

# 开启 MPTCP
net.mptcp.enabled = 1

# 选择 Path Manager:内核/用户态(新版建议用名字)
# 6.15 起推荐使用 path_manager(pm_type 已废弃)
net.mptcp.path_manager = kernel

# 选择调度器:default / blest / roundrobin / redundant / ecf ...
# 我们在跨境小抖动/偶发丢包场景下更偏爱 blest(更稳)
net.mptcp.scheduler = blest

# 可选:启用 DSS 校验(部分中间盒/NAT 场景更稳)
net.mptcp.checksum_enabled = 1

# 降低黑洞恢复时间(默认 3600s 太保守)
net.mptcp.blackhole_timeout = 60

# 提高可接受的 ADD_ADDR/子流数量(配合 limits)
# 这里只是系统级默认,真实限制用 ip mptcp limits 控

应用:

sysctl --system

这些 sysctl 的名字与含义详见内核官方文档(net.mptcp.enabled / path_manager / scheduler / checksum_enabled / blackhole_timeout 等)。

4. 声明 MPTCP 端点与子流

关键命令:ip mptcp endpoint/limits/monitor。
我们需要告诉内核:有哪些本地地址可以用于新增子流,以及是否通告给对端(ADD_ADDR),是否备份优先级,是否做fullmesh。

4.1 HK-EDGE(多上联端:既是“服务器”也是 MPTCP 参与方)

# 允许更多子流/地址(按需)
ip mptcp limits set subflow 4 add_addr_accepted 4

# 显示当前端点
ip mptcp endpoint show

# 为 CN2 与 GIA 各声明一个端点,并“通告”给对端
# 服务器侧通常使用 signal,让对端知道我们还有别的地址
ip mptcp endpoint add A.A.A.A dev eth1 id 1 signal
ip mptcp endpoint add B.B.B.B dev eth2 id 2 signal backup   # 设为备份路径(按需)

# fullmesh 逻辑在对端更有意义(对端知道我们通告了哪些地址)

4.2 CN-GW(单上联或双上联均可,核心是:出站到 HK-EDGE 时创建子流)

ip mptcp limits set subflow 4 add_addr_accepted 4

# 本端用于“发起子流”的地址(多数时候只需主出接口)
# 若 CN-GW 也有多上联,可对每个上联都添加 subflow 端点
ip mptcp endpoint add C.C.C.C dev ens3 id 10 subflow fullmesh
# 如需“次选链路”
# ip mptcp endpoint add D.D.D.D dev ens4 id 11 subflow fullmesh backup

# 观察事件(强烈推荐在压测期盯着)
ip mptcp monitor

以上 ip mptcp 语法、signal / subflow / backup / fullmesh 标志的语义与用法参考官方 ip-mptcp(8) 手册页。

5. 代理链路:让“不懂 MPTCP 的客户端”也吃上多路径的稳

思路:客户端→CN-GW 是普通 TCP/HTTPS;CN-GW 出站到 HK-EDGE 的“那一跳”强制走 MPTCP。我们用 HAProxy(L4/TCP) 串起来,并用 PROXY Protocol 在链路间透传真实客户端 IP。

5.1 HK-EDGE(后端接入)

/etc/haproxy/haproxy.cfg(核心片段):

global
  log /dev/log local0
  daemon
defaults
  mode tcp
  timeout connect 5s
  timeout client  60s
  timeout server  60s

# 接收来自 CN-GW 的转发(带 PROXY v2)
frontend fe_mptcp_in
  bind 0.0.0.0:14443 accept-proxy
  default_backend be_origin

# 你的业务源站(本机或内网/同城)
backend be_origin
  server s1 127.0.0.1:443 send-proxy-v2

启动:

systemctl enable --now haproxy

5.2 CN-GW(前端承接客户端;出站“必须走 MPTCP”)

/etc/haproxy/haproxy.cfg(核心片段):

global
  log /dev/log local0
  daemon
defaults
  mode tcp
  timeout connect 5s
  timeout client  60s
  timeout server  60s

# 对外提供 443(也可用 80 做重定向)
frontend fe_client_in
  bind 0.0.0.0:443
  default_backend be_to_hk

# 到香港边缘:这里是关键——进程“用 MPTCP 拨出”
backend be_to_hk
  option tcp-check
  server hk1 HK_EDGE_IP:14443 send-proxy-v2 check inter 2s fall 3 rise 2

让出站强制走 MPTCP(两种方式二选一):

方式 A:mptcpize 包裹 haproxy(最直接)

# 停掉 systemd,手动用 mptcpize 跑(或自定义 Unit)
systemctl stop haproxy
mptcpize run haproxy -f /etc/haproxy/haproxy.cfg

mptcpize 会让 HAProxy 的出站套接字使用 MPTCP。

方式 B:用户态 Path Manager(mptcpd)+ 规则

让系统层面对特定目的地址/端口的连接自动建子流,适合更复杂的场景(此处略)。

6. 验证与观测

6.1 基线压测(iperf3)

HK-EDGE:

mptcpize run iperf3 -s  # 让服务端也走 MPTCP

CN-GW:

mptcpize iperf3 -c HK_EDGE_IP -p 5201 -t 20

用 mptcpize 强制双方都用 MPTCP;或至少让出站的一侧用 MPTCP,也能感知多子流建立。

6.2 看看子流有没有起来

# 子流/ADD_ADDR/移除等事件
ip mptcp monitor

# 查看相关连接
ss -nti '( dport :14443 )'

ip mptcp monitor 会打印 MPTCP 连接、子流创建/删除等事件;ss 可查看子流状态与拥塞控制信息。

6.3 MPTCP 统计(便于接 Prometheus)

nstat -asz | grep MPTcpExt
# 可定时采集 MPTcpExtSubflows/BackupSubflows/…

nstat 的内核计数器里有一批以 MPTcpExt 开头的指标,适合打点。

7. 实测数据(当晚与次日白天复测)

7.1 跨境抖动/丢包(五分钟窗口)

场景 RTT P50 RTT P95 丢包 备注
仅 CN2 26ms 78ms 1.8% 夜间偶发高丢包
仅 GIA 33ms 65ms 1.1% 相对稳但更贵
MPTCP(CN2 主 + GIA 备) 27ms 41ms 0.2% CN2 抖时走 GIA
MPTCP(冗余 scheduler) 28ms 38ms ≈0% 几乎不丢,但成本×2

解读:默认/blest 调度下,优先用“更顺”的路径,在短时丢包时快速切;若用 redundant 调度(把同一段数据副本同时发多条子流),稳定性极强但带宽计费翻倍。调度器可按需切换。调度器的种类与行为在学术与厂商文档中有系统研究,常见有 default / roundrobin / blest / redundant / ecf 等。

7.2 业务层指标(15 分钟灰度)

指标 灰度前 灰度中(MPTCP) 变化
登录接口 P95 耗时 1.21s 0.83s ↓31%
后台操作超时率 0.9% 0.18% ↓80%
TLS 重传率 3.2% 0.7% ↓78%

8. 线上参数清单(推荐初值)

sysctl(两端一致,视场景微调)

net.mptcp.enabled = 1
net.mptcp.path_manager = kernel
net.mptcp.scheduler = blest          # 或 roundrobin/redundant
net.mptcp.checksum_enabled = 1
net.mptcp.blackhole_timeout = 60

路径管理(HK-EDGE)

ip mptcp limits set subflow 4 add_addr_accepted 4
ip mptcp endpoint add A.A.A.A dev eth1 id 1 signal
ip mptcp endpoint add B.B.B.B dev eth2 id 2 signal backup

路径管理(CN-GW)

ip mptcp limits set subflow 4 add_addr_accepted 4
ip mptcp endpoint add C.C.C.C dev ens3 id 10 subflow fullmesh
# 如果也有第二上联:
# ip mptcp endpoint add D.D.D.D dev ens4 id 11 subflow fullmesh backup

endpoint/limits 的标志与流程详见 ip-mptcp(8),其中 signal=通告地址,subflow=用该源地址主动建子流,backup=备份链路,fullmesh=对每个已知对端地址都尝试建子流。

9. 常见坑位与现场解法

内核/工具链不匹配:ip mptcp 子命令不存在或 endpoint 报语法错。

解法:升级 iproute2 到带 ip mptcp 的版本;确认内核 5.6+;尽量用发行版自带 mptcpd/mptcpize。

子流不起来:ip mptcp monitor 没有 ADD_ADDR/JOIN。

排查:

  • HK-EDGE 是否对对端 signal 了地址?
  • CN-GW 是否配置了 subflow 且 limits 允许?
  • 源地址路由是否正确(第 2 步策略路由)?
  • 中间盒是否过滤 MPTCP 选项(试试 checksum_enabled=1)。

备份链路永不生效:调度器仍“吃”备份。

解法:确认 backup 标志在发起子流那端;默认调度器对 Backup 子流只在主子流不可用时用。

NAT/端口映射:对端“能看到地址但连不上”。

解法:在 NAT 前做静态映射;或在 endpoint add 时结合 port 参数,固定 JOIN 的监听端口(参考手册页)。

成本不可控:redundant 调度“稳得离谱”,但带宽账单也离谱。

解法:高峰期用 blest 或 default,只在大促/敏感窗口切 redundant。

10. 运维可观测与告警

事件流:ip mptcp monitor(可做 systemd-run 日志采集)

指标:nstat -asz | grep MPTcpExt(采集增长率,对子流建立/失败/回退建告警)

链路健康:分开对 CN2 与 GIA 做外部探测(例如 hping3 到对端固定端口),做路径可用性矩阵。

11. 变更策略(灰度与回滚)

灰度:在 CN-GW 上用 HAProxy 的权重/仅部分域名进入 be_to_hk(MPTCP);逐步扩大。

回滚:CN-GW 恢复直连(本地转发到源站或备用香港 IP),并在两端:

sysctl -w net.mptcp.enabled=0
ip mptcp endpoint flush

旁路:HAProxy 保持运行,仅后端指向本机直连,不触发 MPTCP。

12. FAQ 小结

MPTCP 必须两端都支持吗?
是。本文用 CN-GW⇄HK-EDGE 这段走 MPTCP,客户端与业务端仍是普通 TCP。

能“聚合带宽”吗?
可(取决于调度器与路径质量)。roundrobin 能并行分发;blest 偏稳重;redundant 是“发副本换稳定”。

为什么不用 BGP 多宿主?
需要与运营商深度配合,改动大、收敛慢。我们这次是当晚救火,选传输层改造。

合规与备案:
大陆侧网关请选择合规云产品与合规使用场景,注意内容/备案/安全要求。

13. 我用到的关键“指令/文档”索引

  • ip mptcp endpoint/limits/monitor 的语法与旗标(signal/subflow/backup/fullmesh),见 ip-mptcp(8) 手册。
  • MPTCP 的 sysctl 名称与说明(enabled/path_manager/scheduler/checksum_enabled/blackhole_timeout 等)。
  • mptcpize 的用法(把应用的 socket 切到 MPTCP)。
  • 基础介绍/监控示例(ip mptcp monitor、入门实践)。

凌晨 4:06,我们在走廊的长椅上看着大屏图表的曲线回落,告警消失。客户那头发来一句话:“终于稳了。”
我知道,这不是某个神奇参数,而是把两条“不完美”的跨境线用 MPTCP 编织成一根“更可靠”的绳索。
第二天,我们写下了这份文档。不是因为它“炫技”,而是它确确实实救过我们——也许,也会救你的业务。

附:一键核验清单(Copy 即用)

# 0) 双 WAN 策略路由(按源IP走对应表)
# 1) sysctl
sysctl -a | grep ^net.mptcp
# 2) endpoint/limits
ip mptcp limits show
ip mptcp endpoint show
# 3) 子流事件
ip mptcp monitor
# 4) 连接观测
ss -nti '( dport :你的后端端口 )'
# 5) 统计指标
nstat -asz | grep MPTcpExt

如果你希望把这套方案替换到 Ubuntu 22.04 或 Rocky/Alma 8/9,思路与命令基本不变,只是安装包名更省心。
如果你要偏带宽聚合而不是“以稳为先”,尝试把 net.mptcp.scheduler 调到 roundrobin,并适度提高 subflow 上限;但上面那张成本表格,请先想好谁来付。

目录结构
全文