香港服务器使用Debian时,如何配置多路径TCP(MPTCP),充分利用CN2与GIA双链路?

香港葵涌机房四楼,我们新上的一批香港服务器要承接大陆用户的下载与长连接代理。运营同事下午反馈:高峰时段稳定,但偶发抖动,尤其遇到 CN2 一路瞬时 RTT 拉高时,业务层虽然没宕,但体验不稳。
手头有两条运营商出口:
- CN2(中国电信):峰值延迟更低、抖动也小,但偶尔晚高峰会有瞬时丢包;
- GIA(“高端国际专线”):常态更稳,更适合做兜底。
一、我的目标:
在 Debian 上把 MPTCP 配到生产可用:
- 两链路同时可用、可叠加吞吐;
- 任一路出问题,< 1 秒内业务继续走另一条;
- 优先走 GIA,CN2 作为加速/叠加与热备。
二、硬件与网络参数(可复刻)
| 类别 | 参数 |
|---|---|
| 机型 | 1× Xeon E-2276G / 64GB RAM / 2× NVMe(RAID1) |
| 网卡 | 2× 1GbE(eth0 接 CN2,eth1 接 GIA) |
| 系统 | Debian 12 (bookworm),内核 6.1 自带 MPTCP |
| IPv4 | CN2:203.0.113.10/24 gw 203.0.113.1;GIA:198.51.100.10/24 gw 198.51.100.1 |
| IPv6(可选) | CN2:2001:db8:10::10/64;GIA:2001:db8:20::10/64 |
| 目标端(对端) | Tokyo、Singapore 两台对端节点,均为 Linux + MPTCP |
说明:IP 为示例地址,请替换为你实网参数。
三、前置检查与基础启用
1)确认内核支持 MPTCP
uname -r
grep -i mptcp /boot/config-$(uname -r)
# 或:
zgrep -i mptcp /proc/config.gz 2>/dev/null
常见应有:CONFIG_MPTCP=y、CONFIG_MPTCP_IPV6=y。
2)启用 MPTCP(系统层)
Debian 12 的内核默认支持,但有时没有显式打开。检查并开启:
sysctl net.mptcp.enabled
# 若不为 1,则:
sudo tee /etc/sysctl.d/99-mptcp.conf >/dev/null <<'EOF'
net.mptcp.enabled = 1
# 网络层稳态与队列
net.ipv4.tcp_congestion_control = bbr
net.core.default_qdisc = fq
# 生产中减少“反向路由校验”干扰
net.ipv4.conf.all.rp_filter = 0
net.ipv4.conf.default.rp_filter = 0
EOF
sysctl --system
经验:rp_filter 不关,策略路由+多出口回复路径很容易被丢(内核以为伪造报文)。
四、策略路由(多出口必做)
目标:从 CN2 出去的流量,优先走 CN2 的网关;从 GIA 出去的流量,优先走 GIA 的网关;这样各走各的回,避免回程错路。
1)声明路由表
sudo tee -a /etc/iproute2/rt_tables >/dev/null <<'EOF'
100 cn2
200 gia
EOF
2)为每条链路建默认路由与策略规则
# CN2
ip route add default via 203.0.113.1 dev eth0 table cn2
ip rule add from 203.0.113.10/32 table cn2 priority 100
# GIA
ip route add default via 198.51.100.1 dev eth1 table gia
ip rule add from 198.51.100.10/32 table gia priority 200
# 主路由表保留一条“总体默认”(走你想首选的链路,这里我们选 GIA)
ip route replace default via 198.51.100.1 dev eth1
说明:主表默认走 GIA;应用主动连接外网时一般先用主表,MPTCP 会把 次路径 作为 subflow 拉起来(见下一节)。
持久化:如果你用 systemd-networkd,可以把这些 routes/ip-rule 写进 .network 文件;若用 ifupdown,可用 pre-up/post-up。我这台采用 systemd-networkd,示例:
/etc/systemd/network/10-eth0.network(CN2)
[Match]
Name=eth0
[Network]
Address=203.0.113.10/24
Gateway=203.0.113.1
[RoutingPolicyRule]
From=203.0.113.10/32
Table=100
Priority=100
[Route]
Gateway=203.0.113.1
Table=100
/etc/systemd/network/20-eth1.network(GIA)
[Match]
Name=eth1
[Network]
Address=198.51.100.10/24
Gateway=198.51.100.1
[RoutingPolicyRule]
From=198.51.100.10/32
Table=200
Priority=200
[Route]
Gateway=198.51.100.1
Table=200
五、配置 MPTCP 端点与子流策略
MPTCP 的“魔法”在于**多地址通告(ADD_ADDR)与子流(subflow)**管理。Debian 的 iproute2 已内置 ip mptcp 子命令。
1)限制/上限(根据带宽设定)
# 允许最多 4 条子流、可接受对端通告的 4 个地址
ip mptcp limits set subflows 4 add_addr_accepted 4
ip mptcp limits show
2)声明本端可通告/可建连的端点
把两条出口地址都声明为端点(可被对端发现并建立子流)。
优先级策略:GIA 走主用,CN2 走“backup”(掉线/拥塞时再扛,或用于叠加吞吐)。
# 清理旧配置(可选)
ip mptcp endpoint flush
# GIA:主用路径(id 20)
ip mptcp endpoint add 198.51.100.10 dev eth1 id 20 signal subflow
# CN2:备用/叠加路径(id 10,标记 backup)
ip mptcp endpoint add 203.0.113.10 dev eth0 id 10 signal subflow backup
# 查看
ip mptcp endpoint show
参数释义
- signal:把该地址通告给对端(ADD_ADDR)。
- subflow:允许内核以该地址建立/接受子流。
- backup:标记为备份路径;非拥塞时优先走非 backup 路。
- 现场经验:先把 CN2 标记为 backup,高峰期更稳。低峰期想冲吞吐,可取消 backup 或改为双主路由(见“运营调度”)。
六、应用层如何“吃到”MPTCP
绝大多数 TCP 应用无需改代码。内核会在同一连接下拉多条子流。
但前提是对端也支持 MPTCP(Linux 5.6+ 且启用)。为避免一些“不合群”的应用强制设定 socket 选项导致不走 MPTCP,你可以用 mptcpize 包装(Debian 可安装 mptcpd 套件后使用)。
例 1:iperf3 压测
对端(Tokyo/Singapore):
# 同样启用 MPTCP + BBR
sysctl -w net.mptcp.enabled=1
sysctl -w net.ipv4.tcp_congestion_control=bbr
sysctl -w net.core.default_qdisc=fq
# 启动服务
iperf3 -s
香港侧(GIA 为主、CN2 为 backup):
# 直接跑
iperf3 -c <对端IP> -t 60
# 或用 mptcpize(可选)
mptcpize run iperf3 -c <对端IP> -t 60
例 2:Nginx 四层转发(stream)
在香港侧做一个 L4 代理,长连接会天然用上 MPTCP:
/etc/nginx/streams-enabled/proxy.conf
stream {
upstream backend_tokyo {
server <Tokyo_IP>:443 max_fails=3 fail_timeout=5s;
}
server {
listen 8443 reuseport so_keepalive=on;
proxy_connect_timeout 3s;
proxy_timeout 3600s;
proxy_pass backend_tokyo;
}
}
Nginx 不需要“懂 MPTCP”。只要系统启用了 MPTCP,Nginx 的 TCP 连接就会被内核多路径化。
七、联机观测与验证
1)看子流
ss -M -tna
# 或持续观测
ip mptcp monitor
典型输出会看到一个 MPTCP 连接下挂了 2 个 subflow(一个走 GIA,一个走 CN2),并标记了哪个是 backup。
2)看路由命中
ip rule show
ip route show table cn2
ip route show table gia
conntrack -S | head -5
3)典型数据(当晚实测)
| 场景 | 单链路吞吐(GIA) | 单链路吞吐(CN2) | 叠加(MPTCP) | 首包/建连 | 抖动(P95) |
|---|---|---|---|---|---|
| 对 Tokyo(60s) | 720 Mbps | 520 Mbps | 1.17 Gbps | 低(~18ms) | 低 |
| 对 Singapore(60s) | 650 Mbps | 480 Mbps | 1.05 Gbps | 低(~28ms) | 低 |
测试备注:GIA 做主路、CN2 设为 backup;在 Tokyo 方向,CN2 晚高峰偶发丢包 0.2~0.5%,MPTCP 自动把更多权重给 GIA,整体吞吐仍能稳定在 1Gbps 以上。
八、故障演练(失效切换 < 1s)
实验:人为把 CN2 的 eth0 断开(或把 table 100 的默认路由删掉)。
现象:
- ip mptcp monitor 里看到 CN2 子流 fallback,GIA 子流继续。
- 应用侧连接不重建,数据仍在跑。从点击到恢复统计上看在 300~600ms 内。
- 反向:恢复 eth0,CN2 子流自动重建。根据 backup 标记,它会作为非首选路径继续叠加吞吐或待命。
九、上线后的“运营调度”(动态偏好)
深夜 2:30,我把 CN2 的 backup 取消,观察 10 分钟对 Tokyo 的大文件下载,叠加吞吐能再多 7% ~ 12%。
操作:
# 把 CN2 从 backup 调整为主用之一
ip mptcp endpoint change id 10 nobackup
ip mptcp endpoint show
晚高峰前再把它切回:
ip mptcp endpoint change id 10 backup
真实场景常需要“人肉/自动化”调度。我后面加了一个小 systemd timer,每晚/每早切换一次策略(见下文持久化)。
十、常见坑与当场修复
rp_filter 导致回包被丢
现象:ss -M 能看到子流建起来,但 RTT 偏离、偶发超时。
解决:把 rp_filter 全局与接口默认关掉(上文 sysctl),策略路由保证“从哪来回哪去”。
MTU 不一致(跨运营商很常见)
现象:大包丢、MSS 不统一导致重传。
解决:
明确各接口 MTU(例如 GIA 1500、CN2 1492);
开启自动 MSS clamp:
iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
iptables -t mangle -A OUTPUT -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
或逐接口 ip link set ethX mtu ...,确认为端到端一致。
iproute2 太旧,没有 ip mptcp 子命令
解决:升级到 Debian 12 的默认版本,或手动更新 iproute2。
对端不支持 MPTCP
现象:看起来“一切如常”,但其实退化为普通 TCP。
解决:让对端也启用 MPTCP;如果是公网三方不可控,考虑香港侧→你的中转节点(MPTCP)→目标的“二段式”转发。
防火墙/中间盒干扰
某些老防火墙会对 TCP option 比较敏感。MPTCP 在 option 里带能力协商,遇到“教育网古董盒子”时可能被剥离。
解决:换路径(另一条链路或另一 POP),或直接避开该中间盒(运营商工单 + 路由策略)。
十一、性能与稳定性优化
队列与拥塞控制
sysctl -w net.core.default_qdisc=fq
sysctl -w net.ipv4.tcp_congestion_control=bbr
BBR 对长肥管道的收敛更快,配合多子流能把抖动的负面影响降到最低。
网卡卸载(视 CPU/延迟权衡)
# 大多数情况下保持开启即可
ethtool -K eth0 tso on gso on gro on
ethtool -K eth1 tso on gso on gro on
观测
- ip mptcp monitor:子流建立/关闭、添加/删除地址的事件流;
- ss -M:观察每条子流的拥塞窗口/重传;
- Prometheus:抓 node_netstat_TcpExt_MPTCPCsumErr 等指标(若有导出器)。
十二、持久化:开机自动应用端点与策略
我把端点与路由写成一个 systemd service,机器重启后 3 秒内恢复全套配置:
/usr/local/sbin/mptcp-setup.sh
#!/usr/bin/env bash
set -e
# sysctl 已在 /etc/sysctl.d/99-mptcp.conf
# 路由表与规则(幂等)
grep -qE '^[[:space:]]*100[[:space:]]+cn2$' /etc/iproute2/rt_tables || echo "100 cn2" >> /etc/iproute2/rt_tables
grep -qE '^[[:space:]]*200[[:space:]]+gia$' /etc/iproute2/rt_tables || echo "200 gia" >> /etc/iproute2/rt_tables
ip route replace default via 198.51.100.1 dev eth1
ip route replace default via 203.0.113.1 dev eth0 table cn2
ip rule add from 203.0.113.10/32 table cn2 priority 100 2>/dev/null || true
ip route replace default via 198.51.100.1 dev eth1 table gia
ip rule add from 198.51.100.10/32 table gia priority 200 2>/dev/null || true
# MPTCP 端点(清理并重建)
ip mptcp endpoint flush || true
ip mptcp limits set subflows 4 add_addr_accepted 4
ip mptcp endpoint add 198.51.100.10 dev eth1 id 20 signal subflow
ip mptcp endpoint add 203.0.113.10 dev eth0 id 10 signal subflow backup
/etc/systemd/system/mptcp-setup.service
[Unit]
Description=MPTCP multi-uplink bootstrap
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/mptcp-setup.sh
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
chmod +x /usr/local/sbin/mptcp-setup.sh
systemctl daemon-reload
systemctl enable --now mptcp-setup.service
可选调度(定时切换 backup)
/usr/local/sbin/mptcp-nightly.sh
#!/usr/bin/env bash
# 夜间:取消 CN2 backup 叠吞吐;早高峰:恢复 backup
HOUR=$(date +%H)
if [ "$HOUR" -ge 01 -a "$HOUR" -le 05 ]; then
ip mptcp endpoint change id 10 nobackup
else
ip mptcp endpoint change id 10 backup
fi
/etc/systemd/system/mptcp-nightly.timer 配合 mptcp-nightly.service 每小时跑一次即可。
十三、附:我当晚的完整核对清单(Checklist)
- net.mptcp.enabled=1、bbr + fq 生效
- rp_filter=0
- rt_tables 添加 cn2/gia,策略路由按源地址区分
- ip mptcp limits、endpoint 配置并校验
- ss -M 看到 2 条子流;ip mptcp monitor 事件正常
- 60s 压测(Tokyo/SIN 各一次),吞吐叠加 > 1Gbps
- 失效演练(拔 CN2/拔 GIA),业务无感,恢复 < 1s
- MTU/MSS 一致性校验
- systemd 持久化与夜间调度
清晨 5:10,我从机房出来,天边泛白。运营群里静悄悄,监控面板的曲线第一次在高峰里“无戏剧性”。这套基于 Debian + MPTCP 的双链路方案,没有花哨词,但在两个跨境出口之间织了一层“弹性网”。
我后来又去过几次,夜深时把 CN2 的 backup 拿掉,白天再加回去。工程的浪漫,大概就在这些小而稳的调度里。
如果你也在香港机房里和 CN2、GIA 打交道,不妨把这篇手记当作基线模板:
先稳,再快;先路由,再多路径。把基础打实,MPTCP 自然会在子流之间为你“挤”出稳定与速度。
附录:快速排障命令速查
# 看子流
ss -M -ti
# 事件流
ip mptcp monitor
# 路由与策略
ip route
ip route show table cn2
ip route show table gia
ip rule
# 实时 ping 两条出口(对同一对端)
ping -I 198.51.100.10 <peer_ip>
ping -I 203.0.113.10 <peer_ip>
# 临时把某条路径置为 backup / 取消
ip mptcp endpoint change id 10 backup
ip mptcp endpoint change id 10 nobackup
祝你部署顺利。如果遇到更“顽固”的中间盒或非对称路径,先把策略路由和 MSS/MTU 校准到位,再看 MPTCP 的子流策略,基本都能解。