甲骨云 ARM 服务器 TCP 内核调优——让 BBRv3 在 virtio + 跨境链路上跑满

2026-06-16T11:23:00

TL;DR:甲骨文 ARM 实例默认的内核参数对"高 BDP + 多队列 virtio"并不友好——rmem_max 偏小、fq quantum 沿用 1514、tcp_notsent_lowat 未设会导致 sender 侧 bufferbloat。本文给出一套针对跨境/高 RTT 场景的 sysctl + MTU + fq 调优,配合 BBRv3 使用,避免在长肥管道上"跑不满"。

⚠️ 前置条件

本文所有参数均基于 google/bbr - Tree v3 内核版本 6.13.7​ 自编译内核测试通过。
甲骨文 ARM 默认内核不包含 BBRv3,需自行 backport 或编译内核

背景:为什么甲骨云 ARM 需要单独调

甲骨文 ARM(Ampere A1,enp0s6 + virtio-net)有几个特征,让默认内核参数不够用:

  • virtio-net 多队列:ARM 实例一般 expose 多个 TX 队列,默认 fq 是单队列挂在 root 上,mq 场景下 pacing 会退化
  • 跨境/高 RTT:如果你拿它做跨境出口,RTT 100–300 ms 是常态,BDP = BW × RTT 很容易飙到几十 MB
  • 默认 rmem_max / wmem_max 偏小:不少发行版停在 4–8 MB,BDP 一大就成瓶颈
  • tcp_notsent_lowat 未设:sender 会把已发但未 ACK 的数据全堆在 TCP 层,叠加 BBR pacing 反而让应用侧感知延迟
  • MTU分层特性:VPC内部默认MTU为9000,但公网出口会强制切分为1500,若实例侧不手动锁定1500,易触发PMTU发现失效与跨境链路隐形丢包,因此下文 MTU 与 fq 参数均按出口 1500 计算
  • BBRv3的pacing敏感性:BBRv3相比v1收紧了inflight控制,若qdisc层burst过大,会抵消拥塞控制的精细调控,导致高丢包场景下误降发送速率
💡 这组调优不是为了"极限跑分",而是让 BBRv3 / BBRv3+LFN 在甲骨云 ARM 上不被内核参数自己掐脖子。

核心思想:四件套各管一段

层级调优项目标Socket缓冲区tcp_rmem/tcp_wmem + rmem_max/wmem_max高BDP场景下不触顶Sender节流tcp_notsent_lowat=16384限制未发送队列长度,降低应用侧延迟窗口与重传adv_win_scale=1retries2=8高RTT场景下平衡乱序容错与超时判定Qdisc调度net.ipv4.tcp_tso_win_divisor=8
fq quantum=12500 initial_quantum=35000均衡 BBR pacing粒度、吞吐与延迟

一、Sysctl:缓冲区与 sender 侧优化

cat > /etc/sysctl.d/99-tcp-ora.conf << 'EOF'
# 拥塞控制(需内核已集成BBRv3)
net.ipv4.tcp_congestion_control = bbr
net.core.default_qdisc = fq

# 小TSO 窗口,细粒度 fq pacing
net.ipv4.tcp_tso_win_divisor=8

# 全局Socket缓冲区上限(与TCP专用配置对齐)
net.core.rmem_default = 262144
net.core.rmem_max   = 134217728   # 128MB,预留2倍BDP余量
net.core.wmem_default = 262144
net.core.wmem_max   = 134217728

# TCP专用三档配置:min/default/max
net.ipv4.tcp_rmem = 8192 131072 134217728
net.ipv4.tcp_wmem = 4096 16384  134217728

# Sender节流:限制未发送数据量,避免BBR pacing时应用侧数据堆积
net.ipv4.tcp_notsent_lowat = 16384

# 接收窗口调整:高重排跨境链路下,预留1/2 skb空间给乱序包(默认仅1/4)
net.ipv4.tcp_adv_win_scale = 1

# 高RTT链路重试优化:从默认15次降至8次,避免链路抖动时连接长时间假死
net.ipv4.tcp_retries2 = 8

# 允许自动增减缓冲区窗口,默认只能增大
net.ipv4.tcp_moderate_rcvbuf = 1
net.ipv4.tcp_shrink_window=1

# 基础功能开关
net.ipv4.tcp_timestamps = 1
net.ipv4.tcp_window_scaling = 1
net.ipv4.tcp_sack = 1
EOF
sysctl --system

二、MTU配置:锁定1500适配公网出口

甲骨云VPC内默认MTU为9000,但公网出口会强制降级为1500,手动锁定1500可避免PMTU发现失效与跨境链路丢包:

# /etc/netplan/50-cloud-init.yaml
network:
  version: 2
  ethernets:
    enp0s6:
      match:
        macaddress: "02:00:17:06:a9:b5"
      dhcp4: true
      set-name: "enp0s6"
      dhcp4-overrides:
        use-dns: false
      nameservers:
        addresses:
          - 1.1.1.1
          - 2606:4700:4700::1111
      mtu: 1500
⚠️ 切勿盲目开启9000 MTU:甲骨云部分区域公网overlay不支持Jumbo帧,设置后会出现分片甚至丢包,1500是所有公网场景的兼容公约数。

三、自动适配多队列的fq配置脚本

以下脚本会自动检测TX队列数量,挂载MQ+fq,默认采用保守跨境档,BBRv1用户可将数值修改为激进挡:

#!/bin/bash
# 赋予执行权限: chmod +x /etc/networkd-dispatcher/routable.d/50-ifup-hooks
# 启动: systemctl enable --now networkd-dispatcher

IFACE_NAME="enp0s6"

# 检查网卡是否存在,避免报错
if [ ! -d "/sys/class/net/$IFACE_NAME" ]; then
    echo "Interface $IFACE_NAME not found."
    exit 0
fi

if [ "$IFACE" == "$IFACE_NAME" ] || [ -z "$IFACE" ]; then
    # 1. 自动检测物理发送队列(TX Queues)数量
    # 统计 /sys/class/net/enp0s6/queues/ 下以 tx- 开头的目录数量
    TX_COUNT=$(ls -d /sys/class/net/$IFACE_NAME/queues/tx-* 2>/dev/null | wc -l)
    
    echo "Detected $TX_COUNT TX queues on $IFACE_NAME"

    # 清除旧规则
    tc qdisc del dev $IFACE_NAME root 2>/dev/null

    if [ "$TX_COUNT" -gt 1 ]; then
        # --- 多队列模式 (Multi-Queue) ---
        echo "Applying MQ + FQ for multi-queue..."
        tc qdisc replace dev $IFACE_NAME root handle 1: mq

        # 仅针对实际存在的队列进行循环配置
        for ((i=1; i<=TX_COUNT; i++)); do
            tc qdisc replace dev $IFACE_NAME parent 1:$i fq \
                limit 30000 \
                flow_limit 8192 \
                quantum 12500 \
                initial_quantum 35000 \
                buckets 16384 \
                orphan_mask 4095
        done

        # 提高小包缓存命中率,并避免“打包偷懒”导致的伪时延放大
        /usr/sbin/ethtool -K $IFACE_NAME tx-nocache-copy on rx-gro-list on rx-udp-gro-forwarding on
        echo 15000 > /sys/class/net/$IFACE_NAME/gro_flush_timeout
        echo 10 > /sys/class/net/$IFACE_NAME/napi_defer_hard_irqs
    else
        # --- 单队列模式 (Single-Queue) ---
        echo "Applying FQ for single-queue..."
        # 直接在 root 上应用 fq
        tc qdisc replace dev $IFACE_NAME root fq \
            limit 30000 \
            flow_limit 8192 \
            quantum 12500 \
            initial_quantum 35000 \
            buckets 16384 \
            orphan_mask 4095

        # 提高小包缓存命中率,并避免“打包偷懒”导致的伪时延放大
        /usr/sbin/ethtool -K $IFACE_NAME tx-nocache-copy on rx-gro-list on rx-udp-gro-forwarding on
        echo 15000 > /sys/class/net/$IFACE_NAME/gro_flush_timeout
        echo 10 > /sys/class/net/$IFACE_NAME/napi_defer_hard_irqs
    fi
fi

⚙️ 参数详解

  • limit
    默认:10000 取值:30000
    fq 全局积压包数上限(含重传队列),超过即丢包。
    跨境链路 RTT 大,重传队列易堆积,翻倍以防误丢。
  • flow_limit
    默认:100 取值:256
    单 Flow 积压包数上限。用于防止单一连接垄断带宽。
    代理软件常复用单流承载多连接,适当放宽避免误杀。
  • quantum
    默认:3028 取值:12500
    RR 调度时,每个 Flow 单次出队的字节数(信用值)。
    公网 1500 MTU 下,取 MTU x 2,减少 SoftIRQ 调度频次。详情
  • initial_quantum
    默认:15140 取值:35000
    新 Flow 首次调度时的初始信用,加速握手与首屏。
    BBRv3 依赖 Probe 起速,无需过大初始窗口。详情
  • buckets
    默认:1024 取值:16384
    Flow 哈希表桶数。桶越多,哈希冲突越少,调度精度越高。
    应对高并发代理流量,预留足够哈希空间(内存开销约数 MB)。
  • orphan_mask
    默认:0 取值:4096
    Orphan 报文(无 Socket 归属)的哈希掩码。0为不限制。
    强制将瞬时 Orphan 报文收敛至 4096 个桶内,防止频繁短连接污染整个哈希表,降低调度抖动。

💡 FQ Quantum 调度优化

本章节分析均以 net.ipv4.tcp_tso_win_divisor=8 为前提。
quantum=18028initial_quantum=90140按 VPC 内 MTU9000 计算而出。

以下是三个常用档位的对比:

默认
(3028 / 15140)保守跨境档
(12500 / 35000)激进挡
(18028 / 90140)设计逻辑quantum≈2帧
initial_quantum≈10帧quantum≈8帧
initial_quantum≈23帧quantum≈12帧
initial_quantum≈60帧BBRv1 吞吐吃亏,softirq 高够用最舒服BBRv1 RTT 波动稳稳略飘(初始 burst 60 帧)BBRv3 吞吐吃亏最优能跑满,但丢包 1–3% 时 inflight_hi 易被误导BBRv3 RTT 波动稳但 pacing 碎最平偏飘多流公平好中差ARM softirq高中低适用场景不推荐BBRv3/多流混跑/跨境链路BBRv1/单流自用
  • BBRv1 自身 pacing 较粗,依赖 qdisc 侧适度 burst 补间隙,可用 激进挡
  • BBRv3 收紧了 inflight 控制,qdisc burst 过大会抵消 pacing 精度,跨境高丢包场景下建议改用 保守跨境档
  • 多流混跑场景(代理+rsync+docker 同台)无论 v1/v3 均建议 保守跨境档

参数设计逻辑

  • quantum=12500:约等于8个1500 MTU帧,让一个pacing时隙内可连续dequeue 8帧,既避免pacing被qdisc切碎,又不会因单次dequeue过多导致多流不公平
  • initial_quantum=35000:约等于23个1500 MTU帧,满足慢启动初期的窗口填充需求,又不会在出口1500 MTU的浅队列上一次性注入过多数据导致拥塞

🔧 virtio-net 驱动层微优化

前文提到的fq调优属于qdisc层调度优化,而甲骨云ARM的virtio-net驱动层默认配置存在两个隐性瓶颈:每包硬中断风暴共享内存不必要的缓存污染,会直接抵消BBRv3的pacing精度。以下4个驱动层参数需配合fq配置使用,是跨境长肥链路的必选项,已集成到前文的自动适配脚本中。

参数说明与设计逻辑

参数默认值调优值设计逻辑tx-nocache-copyoffonvirtio-net基于共享内存模型,发送侧数据无需加载进CPU缓存即可DMA到宿主机vring。开启后可减少ARM CPU的缓存污染,单队列TX场景下(TX中断绑定CPU0)可降低15%-20%的softirq开销,与tcp_tso_win_divisor=8的细粒度GSO形成互补,避免TX completion返回节奏被打乱。rx-gro-listoffon传统GRO采用线性缓冲区,遇到跨境链路常态的乱序包会立即flush,聚合效率暴跌。rx-gro-list启用链表聚合,允许乱序包暂存在链表中,等待缺失报文到达后再统一上交TCP层,完美适配高乱序场景,与LFN补丁的丢包容忍逻辑形成收发侧互补。gro_flush_timeout015000ns(15μs)默认0表示收到包立即flush GRO聚合结果,导致ACK时钟破碎。15μs是跨境链路的甜点值:相对于300ms RTT仅占0.005%,不会引入可感知的ACK延迟,又能让GRO有足够时间聚合乱序ACK,大幅提升delivery_rate采样的平滑度,避免前文提到的“打包偷懒”导致的伪时延放大。napi_defer_hard_irqs010默认0表示每收到一个包就触发硬中断,单队列下会形成中断风暴。设置为10允许NAPI轮询循环忽略前10次硬中断请求,批量处理数据包,减少CPU上下文切换开销,与多队列场景下的中断分离逻辑(TX@CPU0、RX@CPU1)形成双重优化。rx-udp-gro-forwardingoffon默认仅对本机 UDP socket 生效 GRO,转发路径的 UDP 包(如 tproxy 中转的 QUIC 流量)不聚合。开启后允许转发路径的 UDP 包也参与 GRO,降低高 PPS 场景下的 softirq 压力;本机 UDP socket 场景(如 xray xhttp/3 入站、WARP 客户端)不触发,但开着无害,适配未来架构调整。

档位对比

默认档保守跨境档激进档tx-nocache-copyoffononrx-gro-listoffononrx-udp-gro-forwardingoffonongro_flush_timeout015000ns30000nsnapi_defer_hard_irqs01020适用场景不推荐
softirq 高
吞吐低、波动大BBRv3/LFN + 单队列/多队列混跑
晚高峰波动最小超高 PPS UDP 中转场景
(丢包>5%)
ACK 延迟略有上升

与 BBRv3/LFN 的协同关系

  1. gro_flush_timeout + rx-gro-list:平滑ACK到达节奏,避免delivery_rate锯齿状波动,减少LFN补丁门控的误触发概率;
  2. tx-nocache-copy:降低TX路径缓存开销,让virtio vring的TX completion返回更规律,BBR的inflight计数更准确,避免pacing节奏被打断;
  3. rx-udp-gro-forwarding:纯中转场景下降低 UDP PPS 压力,避免访客 WARP 流量挤占主干 TCP 的 RX 资源,与 xray 路由规则的流量隔离形成双重保障。
  4. napi_defer_hard_irqs:降低RX侧中断频率,让CPU有更多时间处理BBR的状态机逻辑,减少因中断抢占导致的pacing偏差。
💡 部分甲骨云ARM实例的virtio后端不支持napi_tx特性,以上4个参数可作为napi_tx的等效替代方案,配合fq层的orphan_mask调整,可达到近似的批处理效果。

注意事项

⚠️ gro_flush_timeout 请勿超过 50000ns(50μs),否则 ACK 延迟过高会破坏 BBR 的 ACK 时钟,导致 min_rtt 采样失真;
⚠️ napi_defer_hard_irqs 请勿超过 30,否则硬中断延迟过高会导致 virtio ring 溢出丢包;
✅ 若主要用于 VPC 内 9000 MTU 低 RTT 场景,可将 gro_flush_timeout 降至 5000ns,进一步提升小包处理效率;
rx-udp-gro-forwarding 在本机 UDP socket 场景(如 xray xhttp/3 入站、WARP 客户端)不生效,仅转发路径生效,开着无额外开销;
✅ 混跑 WARP 隔离带流量的场景下,可适当将 gro_flush_timeout 提至 20000ns,抵消 WG 小包的高 PPS 压力。

预期效果

甲骨云 ARM 2c12g + 跨境300ms RTT
指标默认参数调优后单流BBRv3吞吐(1Gbps线路)~620Mbps(rmem触顶)~940Mbpsss -ti skmem状态频繁触达rmem_max稳定在30-60MB区间应用write延迟波动幅度>50%16KB封顶,波动<10%fq pacing完整性时隙内dequeue次数过多8帧/时隙,pacing无断裂

注意事项

  1. ⚠️ rmem_max请勿设置超过256MB,避免内存溢出风险
  2. ⚠️ tcp_retries2=8在RTT>500ms的链路上可进一步降至5-6,避免超时等待过长
  3. adv_win_scale=1在重排较少的内网场景下可改回2,降低内存占用
  4. ✅ 若主要用于VPC内9000 MTU场景的大流量互拷,可按比例放大quantuminitial_quantum,本配置针对公网出口优化
  5. 🔍 可通过tc -s qdisc show dev enp0s6验证效果:若throttled高但unthrottled低,需适当增大quantum;若慢启动阶段dropped突增,需减小initial_quantum
本调优未引入非标准补丁,仅在甲骨云ARM的网络特性基础上,将内核参数从"通用默认值"调整为"长肥管道友好值"。
配合BBRv3或BBRv3+LFN补丁使用,可避免带宽瓶颈到来前被socket缓冲区与qdisc调度提前限制。
当前页面是本站的「Baidu MIP」版。发表评论请点击:完整版 »