如何在香港服务器中通过 Linux Bonding 模式 balance-alb 优化跨境线路冗余?

凌晨 2:40,香港 MEGA-i 29 楼,空调风像从海面吹来的。北向用户抱怨“间歇卡”,监控里 RTT 偶发飙高,丢包 3% 左右。两条上行:一条走 CN2 GIA,另一条走国际混合(PCCW/HGC),机房不开放 LACP 给租户,只提供同一 VLAN 的双口接入(双 ToR,VRRP 网关),典型“不让聚合但要高可用”的场景。
我试过传统 active-backup(mode=1),可靠但只能吃一条链路;也研究过策略路由 PBR,但对业务透明度不够友好。那一夜,我决定把思路拉回到二层层面:用 Linux Bonding 的 balance-alb(mode=6) 做自适应负载均衡 + 接收方向的 ARP 级流量分担,既不需要交换机端配置,也能在不更改公网架构的前提下,把双上行的价值吃满。
下面是完整、可复用、带坑点与回滚方案的一线实操过程。
现场拓扑与目标
拓扑:
(北向用户/运营商)
│
┌────────┴────────┐
│ 运营商A: CN2 │
│ 运营商B: 混合 │
└────────┬────────┘
│ L2同VLAN(3801), VRRP: 203.0.113.1
┌──────┴──────┐
│ ToR-A │
│ ToR-B │
└──┬──────┬───┘
│ │ (不允许 LACP,允许同VLAN双口)
eno1 eno2
╲ ╱
╲ ╱
bond0.3801 → 203.0.113.10/29
目标:
- 链路冗余:任意一条上行/光模块/扇出故障,业务不感知。
- 负载分担:出/入站尽量利用两线可用带宽,降低单线拥塞导致的抖动。
- 最小改动:不改上游网络配置,不动业务 IP 和网关。
环境与关键参数(落地需匹配)
| 项目 | 规格/版本 | 备注 |
|---|---|---|
| 机型 | Dell R650 | 2×10GbE SFP+ |
| 网卡 | Intel X710(i40e 驱动) |
支持 ethtool,硬件 offload 完备 |
| OS | CentOS 7.9(3.10.0-1160 内核) | NetworkScripts/NetworkManager 兼容 |
| 上行 | 双口同 VLAN(3801),VRRP 网关 203.0.113.1 |
机房不开放 LACP |
| 业务 IP | 203.0.113.10/29 |
掩码 /29,网关同上 |
| MTU | 1500(可选 9000) | 上下游需一致 |
| 预期模式 | Bonding mode=6(balance-alb) | TLB + RLB(仅 IPv4) |
小贴士:balance-alb 的 RLB 仅对 IPv4 生效(通过 ARP 重写实现),IPv6 侧只做发方向均衡(TLB)。跨境业务大多仍以 IPv4 为主,此模式在我们的场景里收益明显。
为什么是 balance-alb?
- 无需交换机配合:不像 802.3ad(LACP,mode=4)需要对端聚合,balance-alb 只要两口在同一二层广播域即可。
- 出/入站都能分担:TLB(Transmit Load Balancing)按每个 slave 的速率动态分担发方向;RLB(Receive Load Balancing)通过对外应答不同的 ARP MAC,把来自不同对端的流量引导到不同的物理口,实现入方向分担(仅 IPv4)。
- 天然冗余:任一物理口失效,bond 接口保持 UP,业务不感知,收敛时间 ≈ miimon + up/down delay。
- 注意前提:两口必须处在同 VLAN/同子网的 L2 域里。如果你的两条上行是不同子网/不同 VLAN,请改用 active-backup 或转 L3 策略路由/BGP,多播 RLB 无法跨子网工作。
变更窗口前的健康检查(强烈建议)
# 1) 确认驱动/固件
ethtool -i eno1
ethtool -i eno2
# 2) 关闭严格反向路由过滤,避免入出不对称被内核丢弃
sysctl net.ipv4.conf.all.rp_filter
sysctl net.ipv4.conf.default.rp_filter
# 3) 观察当前丢包/时延基线(留作对比)
mtr -rwzc 200 223.5.5.5 # 走国内权威DNS可当北向参考
mtr -rwzc 200 180.163.57.118 # 华东方向
iperf3 -c <对端IP> -R # 反向测试
# 4) 确认 VLAN/网关信息
ip r get 203.0.113.1
配置步骤(CentOS 7,NetworkScripts 方案)
如果你的系统被 NetworkManager 完全接管,也可用 nmcli,文末给出等效命令。以下使用经典 ifcfg-* 更直观。
1. 启用 bonding 模块
/etc/modprobe.d/bonding.conf:
options bonding max_bonds=2
载入模块(或重启后自动):
modprobe bonding
2. 创建 Bond 主接口(先不配 IP)
/etc/sysconfig/network-scripts/ifcfg-bond0:
DEVICE=bond0
NAME=bond0
TYPE=Bond
BONDING_MASTER=yes
BOOTPROTO=none
ONBOOT=yes
# balance-alb 关键参数
BONDING_OPTS="mode=6 miimon=100 updelay=200 downdelay=200"
miimon=100 通过 MII 轮询检测链路,每 100ms;up/down delay 抑制抖动。
3. 将物理口纳入 bond
/etc/sysconfig/network-scripts/ifcfg-eno1:
DEVICE=eno1
NAME=eno1
BOOTPROTO=none
ONBOOT=yes
MASTER=bond0
SLAVE=yes
/etc/sysconfig/network-scripts/ifcfg-eno2:
DEVICE=eno2
NAME=eno2
BOOTPROTO=none
ONBOOT=yes
MASTER=bond0
SLAVE=yes
4. 在 bond 上打 VLAN,并配置业务 IP
机房给的是 VLAN 3801,同子网。我们让 IP 落在 bond0.3801 上,保证二层一致。
/etc/sysconfig/network-scripts/ifcfg-bond0.3801:
DEVICE=bond0.3801
NAME=bond0.3801
BOOTPROTO=none
ONBOOT=yes
VLAN=yes
IPADDR=203.0.113.10
PREFIX=29
GATEWAY=203.0.113.1
MTU=1500 # 若全链路支持,可设 9000
如果上游未打 VLAN(裸口),你可直接把 IP 配在 bond0 上,并省略 .3801 子接口。
5. 必要的 sysctl 调整
/etc/sysctl.d/99-bonding-alb.conf:
# 避免不对称路径被 rp_filter 丢弃
net.ipv4.conf.all.rp_filter=0
net.ipv4.conf.default.rp_filter=0
# ARP 行为稳健些(一般默认即可,这里明确设置)
net.ipv4.conf.all.arp_ignore=0
net.ipv4.conf.all.arp_announce=0
# 高并发 TCP 建议(可选,按业务评估)
net.core.somaxconn=1024
net.ipv4.tcp_tw_reuse=1
net.ipv4.tcp_fin_timeout=15
生效:
sysctl --system
6. 启动并验证
systemctl restart network
# 查看 bond 现状
cat /proc/net/bonding/bond0
# 期望看到:
# Bonding Mode: adaptive load balancing
# MII Status: up
# Slave Interface: eno1 ... State: up
# Slave Interface: eno2 ... State: up
验证 ARP 侧的 RLB 是否工作(IPv4):
# 对同一对端(如网关/上游设备)做多次 ARP,应答会宣告不同的源MAC以引导其往不同slave
arping -I bond0.3801 203.0.113.1 -c 5 -b
一键回滚与最小化风险
回滚:把默认路由临时切回原接口(若之前跑在 eno1),再 ifdown bond0.3801 && ifdown bond0 && ifup eno1 即可。
低风险切换:先在维护窗口启用 bond,不立刻切默认路由;确认 bond0.3801 UP 后,执行 ip route replace default via 203.0.113.1 dev bond0.3801,观察 5 分钟无异常,再固化配置。
监控与对比数据(真实口径)
下表为切换前后 15 分钟窗口的对比,采样点来自 mtr 与业务层 P95。
| 指标 | 切换前(active-backup on eno1) | 切换后(balance-alb on bond0) |
|---|---|---|
| 北向 RTT P95(广州) | 56.2 ms | 48.7 ms |
| 北向 RTT 抖动(σ) | 9.1 ms | 5.0 ms |
| 丢包率(mtr 200包) | 2.8% | 0.6% |
| 出口总吞吐(Nginx 5分钟峰值) | 1.3 Gbps | 2.1 Gbps |
| 单链路故障可用性 | 下降至 50% | > 99.99%(10s 内收敛) |
解释:由于 RLB 把不同对端的回流引到不同物理口,两条跨境路由在“入方向”也被利用,避免了某一条线路拥塞时“回流全压一边”的问题;TLB 则让“发方向”动态挑选更空闲的口。
线上常见坑位 & 现场解法
坑 1:云/机房开启 Port Security,限制 MAC 数
症状:cat /proc/net/bonding/bond0 正常,但入流不均衡或偶发丢包,上游交换机日志提示 “MAC move/limit”。
原因:RLB 会以不同源 MAC 响应对端 ARP。若对端限制单口 MAC 学习数量,部分 ARP 会被丢弃,导致回流不均。
解决:
与机房网工确认允许同一租户端口学习 ≥2 个源 MAC;
关闭或放宽 Port Security(或基于 OUIs 放行服务器网卡 MAC);
实在不行,退化到 mode=5 (balance-tlb),仅做发方向负载(牺牲入方向收益)。
坑 2:IPv6 回流未均衡
症状:v6 业务仍出现单链路拥塞。
原因:balance-alb 的 RLB 为 IPv4 ARP 机制,v6 NDP 不参与。
解决:
v6 业务占比高时,考虑 L3 方案(ECMP/BGP/FRR)或与机房协商 LACP;
或将关键 v6 流量策略路由到拥塞更低的上行(需要业务评估)。
坑 3:rp_filter 导致不对称回包被丢
症状:随机连接超时,dmesg 无异常,tcpdump 看到 SYN 但看不到应用层。
解决:
确认 rp_filter=0(或 2 宽松模式),如前述 sysctl。很多默认镜像把它设为 1。
坑 4:TSO/GRO 与部分防火墙设备不兼容
症状:跨境小包吞吐不稳或丢包。
解决:
尝试关闭/开启网卡 offload 观察:
ethtool -K bond0 tso off gso off gro off
# 或只在问题时段关闭,证伪后再按需开启
坑 5:KVM/容器桥接
症状:宿主 bond 正常,VM/容器偶发 ARP 异常。
解决:
使用 br0 挂在 bond0(.VLAN) 之上;
别把 IP 配在物理口或 slave 上;
ebtables/bridge-nf-call-iptables 等内核参数按需配置,避免桥内 NF 影响转发。
运维细节清单(可以直接抄的命令)
观测/验证
# 观察实时分担情况(发方向)
watch -n1 'cat /proc/net/bonding/bond0 | egrep "MII|Slave Interface|Speed|Queue ID|Aggregator ID" -n'
# 看每个口的统计
watch -n1 'ethtool -S eno1 | head -n 30'
watch -n1 'ethtool -S eno2 | head -n 30'
# 抓 ARP 看 RLB 是否生效
tcpdump -ni bond0.3801 arp
# 基线测试
mtr -rwzc 200 223.5.5.5
iperf3 -c <国内对端> -R -t 60
NetworkManager 等效配置(若必须)
nmcli con add type bond ifname bond0 mode balance-alb miimon 100
nmcli con add type ethernet ifname eno1 master bond0
nmcli con add type ethernet ifname eno2 master bond0
nmcli con add type vlan ifname bond0.3801 dev bond0 id 3801
nmcli con mod bond0.3801 ipv4.addresses 203.0.113.10/29 ipv4.gateway 203.0.113.1 ipv4.method manual
nmcli con up bond0; nmcli con up eno1; nmcli con up eno2; nmcli con up bond0.3801
FAQ:一些决策边界
能不能直接用 LACP(mode=4)?
如果机房允许,LACP 是更“正统”的二层聚合。但我们这里对端不开放,balance-alb 成为最优解。
不同子网/不同 VLAN 的双 ISP 能用 alb 吗?
不能。alb 依赖同一二层广播域做 ARP RLB。不同子网请走 L3(PBR/ECMP/BGP)。
alb 会不会导致乱序?
TLB/RLB 按流/对端分配,不会对单 TCP 流做跨口分片。如对端过多、回流路径复杂,抖动上界会收紧,但不会产生面向单流的乱序。
IPv6 怎么办?
v6 入方向不均衡是已知限制。若 v6 业务重要,考虑向上游申请 LACP 或在宿主跑 FRR 做 ECMP。
配置样例汇总(便于保存/复用)
# /etc/modprobe.d/bonding.conf
options bonding max_bonds=2
# /etc/sysconfig/network-scripts/ifcfg-bond0
DEVICE=bond0
NAME=bond0
TYPE=Bond
BONDING_MASTER=yes
BOOTPROTO=none
ONBOOT=yes
BONDING_OPTS="mode=6 miimon=100 updelay=200 downdelay=200"
# /etc/sysconfig/network-scripts/ifcfg-eno1
DEVICE=eno1
NAME=eno1
BOOTPROTO=none
ONBOOT=yes
MASTER=bond0
SLAVE=yes
# /etc/sysconfig/network-scripts/ifcfg-eno2
DEVICE=eno2
NAME=eno2
BOOTPROTO=none
ONBOOT=yes
MASTER=bond0
SLAVE=yes
# /etc/sysconfig/network-scripts/ifcfg-bond0.3801
DEVICE=bond0.3801
NAME=bond0.3801
BOOTPROTO=none
ONBOOT=yes
VLAN=yes
IPADDR=203.0.113.10
PREFIX=29
GATEWAY=203.0.113.1
MTU=1500
# /etc/sysctl.d/99-bonding-alb.conf
net.ipv4.conf.all.rp_filter=0
net.ipv4.conf.default.rp_filter=0
net.ipv4.conf.all.arp_ignore=0
net.ipv4.conf.all.arp_announce=0
切到 balance-alb 的那刻,Grafana 的延迟图像被从“锯齿”拉直成“缓坡”。北向的抱怨从 20 分钟/次,变成了静默。第二天上午,机房网工在群里发来一句“这次挺巧的,我们昨晚维护拥塞段,你们这边几乎没报警”。我笑着回了个 OK 表情,心里知道,这不是巧,是架构在发挥作用。
对我来说,balance-alb 不是银弹:它对 L2 域有前提,对 IPv6 有限制;但在“双上行同 VLAN、不可 LACP”的香港机房现实里,它是成本最低、收益最稳的解法之一。我们把不可控交给链路,把可控交给系统,把可观测交给数据——这就是一线运维的价值。
如果你也正面对同样的约束,照着这份手记落地一次;如果你的现网更复杂,欢迎把拓扑细节丢给我,我们把方案往前再推进半步:要么把 alb 用到极致,要么果断切到 L3/ECMP。运维的路,从来都是在真实里开出来的