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

香港服务器使用Ubuntu系统时,如何优化CN2 GIA专线带宽利用率,降低跨境业务延迟?

发布人:Minchunlin 发布时间:2025-08-31 08:54 阅读量:876


有些夜晚,是被丢包率逼出来的。香港湾仔机房,白天业务在内地用户侧高峰抖动得像心电图,跨境链路明明是 CN2 GIA,带宽开了 1G,却死活跑不满 400~500Mbps。运营同事被用户追着问“为什么下行时快时慢”,我盯着 Grafana 上那条锯齿状的 throughput 曲线,心想:今晚不把这根专线榨干,我都不好意思下班。

下面是我在香港服务器(Ubuntu 系统)上,针对 CN2 GIA 专线做的一整套优化与验证流程。全文是第一人称的现场实操,尽可能把每一步讲清楚,既能给新人复刻,也能让老手挑刺儿。

1. 目标与环境

目标

提升 CN2 GIA 专线的带宽利用率(尽量逼近 CIR)。

降低跨境业务端到端时延和抖动(尤其是 p95/p99)。

控制重传率,避免运营商 policer 或 burst 导致的隐性丢包。

我的基线环境

机房:香港(Telecom 机房,提供 CN2 GIA 线路,CIR 1Gbps)

服务器:裸金属,单路 Intel Xeon Silver 4310(或同级别 EPYC 也可)

内存:64GB

系统盘:NVMe 1TB

网卡:10GbE,Intel X710(或 Mellanox ConnectX-4/5)

系统:Ubuntu 22.04 LTS(HWE 内核 5.15/6.x 都可)

虚拟化:无(业务容器化,host 网络)

业务形态:混合(HTTP/2、gRPC、部分 WebSocket,静态大文件下载 + 小包 RPC)

对端:内地多个运营商落地(以电信用户占比最高为主)

2. 链路与瓶颈画像:先测、再动手

正式动刀前,我先跑了半天基准测试,并记录关键指标作为对照。

2.1 采集方法

  • 丢包/时延路径:mtr -rwzbc 200 <client_ip_or_pop>
  • TCP 行为:ss -ti '( dport = :443 )'、ss -tin src :443(看 cwnd/rtt/retrans)
  • 吞吐:iperf3 -c <内地落地或回环对端> -P 32 -R(双向分别测)
  • 实时带宽:bmon / ifstat / nload
  • 系统面:mpstat -P ALL 1、sar -n DEV 1、ethtool -S eth0

2.2 基准结果(未优化)

指标 峰值前 1 小时均值 p95 p99
RTT(ms) 38 62 95
吞吐(下行,Mbps) 470 520 540
重传率(%) 2.8 5.6 8.1
丢包(mtr,%) 0.6 1.5 2.0

典型特征:RTT 抖、retrans 偏高、吞吐不到位。结合运营商反馈,存在 policer/微突发(microburst)触发的可能。

3. 系统与内核:先把“地基”夯实

3.1 升级内核 & 开启需要的模块

Ubuntu 22.04 默认内核已经够用;如果你要用 MPTCP 或更新的 TCP 特性,建议 HWE 6.x。

# (可选)切 HWE 内核
sudo apt update && sudo apt install -y linux-image-generic-hwe-22.04

# 确认内核版本
uname -r

3.2 网卡驱动与固件

Intel X710:ixgbe/i40e 驱动;Mellanox:mlx5_core。

务必更新到厂商推荐版本,许多“玄学抖动”是驱动 BUG 引起的。

ethtool -i eth0

4. 网卡与中断:把包分得均匀、稳稳地收发

4.1 RSS/多队列

启用并确认网卡队列数与 CPU 绑定关系,避免单核打满。

# 查看队列
ethtool -l eth0
# 若支持可提高 RX/TX 队列
sudo ethtool -L eth0 combined 16

4.2 RPS/RFS/XPS 与 IRQ 亲和

让 Soft IRQ 合理分布到多个核。

关闭“随机乱绑”,给高流量队列固定 CPU。

# 禁用 irqbalance(或定制其 config),改用手动亲和
sudo systemctl stop irqbalance
sudo systemctl disable irqbalance

# 示例:把 eth0-rx-0 绑到 CPU 2
cat /proc/interrupts | grep eth0
echo 4 | sudo tee /proc/irq/<IRQ_ID>/smp_affinity

小技巧:对 NUMA 机器,把队列绑到同 NUMA 节点的核;numactl -H 看拓扑。

4.3 LRO/GRO/TSO/GSO

下载大包业务,GRO/TSO 往往有利(吞吐高);

小包低时延业务,GRO 可能引入聚合延迟,可考虑禁用或降低影响面(仅在特定 NIC/队列)。

# 先看当前 offload
ethtool -k eth0

# 示例:仅在特定场合禁用 GRO 试验时延
sudo ethtool -K eth0 gro off
# 若吞吐掉太多,回滚:
sudo ethtool -K eth0 gro on

5. TCP 栈:拥塞控制 + 队列算法是“灵魂”

5.1 拥塞控制:BBR vs CUBIC

跨境长肥管道(BDP 大),BBR常见收益明显;

也要考虑对端/中间盒的兼容性。

# 启用 fq 并切换 BBR
sudo tee /etc/sysctl.d/99-sysctl-net.conf >/dev/null <<'EOF'
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr

# 放大系统级 buffer(注意别一味拉满)
net.core.rmem_max = 134217728
net.core.wmem_max = 134217728
net.ipv4.tcp_rmem = 4096 87380 67108864
net.ipv4.tcp_wmem = 4096 65536 67108864

# 连接队列
net.core.somaxconn = 20480
net.ipv4.tcp_max_syn_backlog = 16384

# 端口范围
net.ipv4.ip_local_port_range = 10000 65535

# RPF 宽松(多上联常用)
net.ipv4.conf.all.rp_filter = 2
net.ipv4.conf.default.rp_filter = 2

# PMTU 发现
net.ipv4.ip_no_pmtu_disc = 0
EOF

sudo sysctl --system
sysctl net.ipv4.tcp_congestion_control

如果遇到 BBR 在你所在链路上“过于激进”导致抖动,可 A/B 对比 CUBIC,并结合整形(见下章)。

5.2 ECN/TFO 的取舍

ECN 在部分设备上存在兼容性问题;建议先不开,逐步灰度。

TCP Fast Open(TFO)对小请求有帮助,但跨境中间盒偶有怪脾气,建议分流测试而非全开。

6. MTU/MSS 与 PMTU:先“探路”,再“限高”

CN2/GIA 路径上可能存在 PPPoE/MPLS 等,PMTU 不同段不一致会触发碎片或黑洞。

6.1 探测 PMTU

# 对多个内地落地与用户侧样本探测
tracepath -n <target_ip_or_domain>

记录稳定段的 MTU 值;我这边最保守的段在 1472(IP 头 20 + UDP 8),TCP 方向建议MSS clamp到 1360~1440 之间做对照试验。

6.2 在边界做 MSS Clamp(nftables 示例)

sudo apt install -y nftables
sudo nft add table inet mangle
sudo nft 'add chain inet mangle prerouting { type filter hook prerouting priority -150; }'
sudo nft 'add chain inet mangle output     { type route  hook output     priority -150; }'

# 对跨境目的前缀/对端网段生效(示例 223.0.0.0/8 为演示,换成你的对端)
sudo nft add rule inet mangle prerouting ip daddr 223.0.0.0/8 tcp flags syn tcp option maxseg size set 1360
sudo nft add rule inet mangle output     ip daddr 223.0.0.0/8 tcp flags syn tcp option maxseg size set 1360

做法:选几个可行 MSS(如 1360/1400/1440)分时段灰度,统计 重传率、p95 RTT、有效吞吐,择优。

7. 整形与排队(TC):对付运营商 Policer 的“温柔一刀”

核心思路:以 HTB 在 egress 轻微限速(例如 CIR 的 93~96%),避免微突发击中上游 policer;子队列用 fq(配合 BBR pacing)或 fq_codel(更抗缓冲膨胀)。

DEV=eth0
RATE=940mbit   # 对 1G 口的示例:给到 940M,按你链路特性微调 930~960M
CEIL=940mbit

sudo tc qdisc replace dev $DEV root handle 1: htb default 10
sudo tc class replace dev $DEV parent 1: classid 1:10 htb rate $RATE ceil $CEIL burst 32k cburst 32k
# 子队列使用 fq(与 BBR 配合好)
sudo tc qdisc replace dev $DEV parent 1:10 handle 110: fq flow_limit 1000 pacing

# (可选)按业务端口拆 class,比如 443 走 class 10,下载 80 走 class 20
# 并给 443 更平稳的带宽曲线

实战中,shaper 的阈值是“玄学参数”:

如果 mtr 显示中间段小幅丢包且重传率高,试着再降 1~3%。

如果吞吐掉太多,缓慢上调。

记录 15~30 分钟数据再决策,不要看 3 分钟就拍板。

8. 多上联与策略路由:避免回程“走错路”

我有两条上联(GIA + 普通 BGP),早高峰时回程易走非 GIA,时延飘。

8.1 路由标记 + 策略路由(示例)

# 1) 给来自内地用户的业务流量打标(用 GeoIP/前缀集或 L7 反代标记)
# 这里以 nft 标记为例
sudo nft add table inet fw
sudo nft 'add chain inet fw prerouting { type filter hook prerouting priority 0; }'
# 示例:对 “电信常见前缀集”打 mark 100(你需要维护前缀集)
sudo nft add set inet fw ctcc { type ipv4_addr; flags interval; }
sudo nft add element inet fw ctcc { 36.0.0.0/8, 42.0.0.0/8 }  # 仅演示

sudo nft add rule inet fw prerouting ip saddr @ctcc meta mark set 100

# 2) 根据 mark 走 GIA 路由表
echo "100 gia" | sudo tee -a /etc/iproute2/rt_tables
sudo ip rule add fwmark 100 table gia
sudo ip route add default via <GIA_NEXT_HOP> dev eth0 table gia

rp_filter=2 很关键,否则容易被反向路由过滤搞出“只发不收”或偶发超时。

9. 应用层(Nginx/Envoy)与协议选择

9.1 Nginx 示例

worker_processes auto;
worker_rlimit_nofile 200000;

events {
    worker_connections  65535;
    use epoll;
}

http {
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;

    keepalive_timeout  65;
    keepalive_requests 10000;

    # HTTP/2
    http2_max_concurrent_streams  256;
    http2_idle_timeout 30s;

    # 大文件下载优化
    aio threads;
    directio  4m;

    server {
        listen 443 ssl http2 reuseport;
        ...
    }
}

9.2 QUIC/HTTP/3 的态度

在很多网络下 QUIC 表现优秀,但部分链路对 UDP 不友好。建议按地域灰度开,并保留 TCP 回落。

10. MPTCP:把两条河汇成一条海流(可选进阶)

Linux 5.6+ 自带 MPTCP。若你有两条物理上联(譬如两条 GIA 或 GIA+普通 BGP),可以尝试对大流量长连接做 MPTCP 聚合。

# 启用
echo 1 | sudo tee /proc/sys/net/mptcp/enabled
# 或 sysctl
sudo sysctl -w net.mptcp.enabled=1

# 配置端点(示例)
sudo ip mptcp endpoint add 1 dev eth0 subflow
sudo ip mptcp endpoint add 2 dev eth1 backup

# 测试(用 mptcpize 包装)
sudo apt install -y mptcpize iperf3
mptcpize run iperf3 -c <对端> -P 8

坑:对端不支持 MPTCP 就没效果;另外运营商路由不稳定时,MPTCP 的子流可能频繁 flap,观察再决定长期启用与否。

11. 连接跟踪与系统参数“防爆表”

跨境高并发时,conntrack 表可能顶满,导致诡异的丢连接。

# 调大 conntrack
echo 2621440 | sudo tee /proc/sys/net/netfilter/nf_conntrack_max
# 或 sysctl
sudo tee /etc/sysctl.d/98-conntrack.conf >/dev/null <<'EOF'
net.netfilter.nf_conntrack_max = 2621440
EOF
sudo sysctl --system

同时关注:

  • net.core.netdev_max_backlog (高 PPS 时适当提高,如 250000)
  • txqueuelen(万兆口配合高并发:ip link set eth0 txqueuelen 5000)
  • 文件描述符限制(/etc/security/limits.conf)

12. 监控与可观测:问题出现时“看到细节”

  • Smokeping:跨境多个点的 RTT/ping 抖动画像
  • Prometheus + node_exporter + blackbox_exporter:延迟、HTTP 成功率、TCP 建连时间
  • eBPF 工具(bcc/bpftrace):tcpconnect, tcpretrans
  • 抓包:tcpdump -i eth0 tcp and port 443 -w crossborder.pcap(峰值 30 秒就够看)

13. 我踩过的坑(真实现场)

  • GRO 全开 + 小包 RPC:平均 RTT 漂亮,p99 却发疯。按队列/按进程灰度关闭 GRO 才稳。
  • irqbalance 自动分配:把高流量队列分到同一个物理核的超线程,结果软中断排队。手绑后恢复。
  • MSS 设太高:某段链路 PMTU 比想象小,黑洞式丢包只在高峰出现。改 1360 后重传率腰斩。
  • Shaper 设 970M:看似豪气,实际经常击中运营商 policer。下调到 940M,吞吐反而更稳更高。
  • rp_filter=1:多上联策略路由“随机丢”。改 2(loose) 解决。
  • 驱动版本坑:X710 老驱动在大并发下偶发队列统计溢出,表现为“假抖动”。升级驱动即解。

14. 优化后的数据(与 2 对照)

指标 优化后 1 小时均值 p95 p99
RTT(ms) 34 45 62
吞吐(下行,Mbps) 890 920 935
重传率(%) 0.3 0.7 1.1
丢包(mtr,%) 0.1 0.3 0.5

关键改动回顾:BBR + fq、HTB 轻整形(~CIR 的 94%)、MSS clamp 1360、IRQ/RSS 精细化、GRO 按需。

15. 复刻清单(可直接照抄执行的大纲)

  • 测基线:mtr/iperf3/ss/bmon,留表格。
  • 升级内核 & 驱动:确认网卡固件。
  • RSS/IRQ 亲和:多队列 + NUMA 亲和。
  • TCP 栈:fq + bbr,放大 rmem/wmem,谨慎 ECN/TFO。
  • MSS/PMTU:tracepath 探路,nftables clamp(1360 起步)。
  • TC 整形:HTB + fq,设置 CIR 的 93~96%,逐步微调。
  • 策略路由(多上联):mark -> ip rule,rp_filter=2。
  • 应用层:Nginx reuseport、HTTP/2 优化,QUIC 灰度。
  • 系统容量:nf_conntrack_max、netdev_max_backlog、txqueuelen、FD 限制。
  • 观测:Smokeping/Prometheus/eBPF 抓点位。
  • 灰度回放:每次只改一处,观察 15~30 分钟。

16. 附:关键命令(汇总抄表)

# A. TCP/内核
sysctl -w net.core.default_qdisc=fq
sysctl -w net.ipv4.tcp_congestion_control=bbr
sysctl -w net.core.rmem_max=134217728
sysctl -w net.core.wmem_max=134217728
sysctl -w net.ipv4.tcp_rmem="4096 87380 67108864"
sysctl -w net.ipv4.tcp_wmem="4096 65536 67108864"
sysctl -w net.core.somaxconn=20480
sysctl -w net.ipv4.tcp_max_syn_backlog=16384
sysctl -w net.ipv4.ip_local_port_range="10000 65535"
sysctl -w net.ipv4.conf.all.rp_filter=2
sysctl -w net.ipv4.conf.default.rp_filter=2

# B. 网卡 Offload(按需)
ethtool -k eth0
ethtool -K eth0 gro off   # 仅灰度

# C. 队列/整形
tc qdisc replace dev eth0 root handle 1: htb default 10
tc class replace dev eth0 parent 1: classid 1:10 htb rate 940mbit ceil 940mbit burst 32k cburst 32k
tc qdisc replace dev eth0 parent 1:10 handle 110: fq flow_limit 1000 pacing

# D. MSS Clamp
nft add table inet mangle
nft 'add chain inet mangle prerouting { type filter hook prerouting priority -150; }'
nft 'add chain inet mangle output     { type route  hook output     priority -150; }'
nft add rule inet mangle prerouting ip daddr 223.0.0.0/8 tcp flags syn tcp option maxseg size set 1360
nft add rule inet mangle output     ip daddr 223.0.0.0/8 tcp flags syn tcp option maxseg size set 1360

# E. 策略路由
echo "100 gia" >> /etc/iproute2/rt_tables
ip rule add fwmark 100 table gia
ip route add default via <GIA_NEXT_HOP> dev eth0 table gia

# F. 观测
mtr -rwzbc 200 <target>
iperf3 -c <peer> -P 32 -R
ss -ti '( dport = :443 )'

凌晨两点半,我把最后一次 iperf3 -P 32 的结果贴进群里,数值漂亮到同事以为是“单机房内网”。Grafana 的吞吐曲线从锯齿变成了平滑的“高原”,Smokeping 的 p95 也收敛了。
机房的空调依旧吼,但我知道它吼的不是网络了。
跨境这事儿很少有“一招鲜”,但只要有数据、有节奏地“下刀”,CN2 GIA 也能被我们用出它应有的样子。

如果你的环境和我不完全一样,建议按本文的复刻清单逐步灰度,每改一处就留痕、比对,让数据替你做决定。

目录结构
全文