两块网卡绑成一个逻辑口,一根线断了业务不中断——这件事听起来理所当然,但我在虚拟化平台上见过太多"看起来成功了"的案例:/proc/net/bonding/bond0里两个 slave 都乖乖列着,状态up,可一旦真的把其中一块网卡断开,SSH 立刻掉线,ping 断十几秒甚至干脆不通。问题往往不在 CentOS 这一侧,而在 VMware 的端口组安全策略、在交换机有没有配合做聚合、在 mode 选错了场景。这篇内容就围绕在 VMware 虚拟机里跑 CentOS,用 bonding 技术把两块虚拟网卡绑定成一个逻辑网卡这件具体的事,把选型逻辑、两侧配置、验证手段和踩坑链路一次讲透。适合手上已经有 CentOS 虚机、想给关键业务做链路冗余或带宽聚合的运维和开发同学,也适合刚接触 Linux 网络、想把 bonding 真正搞明白而不是复制粘贴命令的人。下面所有命令和参数我都按实际能跑通的顺序给,遇到"这条命令为什么这么写"的地方也会解释清楚。
1. 先搞清楚虚拟机里的 bonding 到底在绑什么
1.1 被绑定的不是网线,是内核里的一条虚拟链路
很多人对 bonding 的第一印象是"两块物理网卡绑在一起",这个理解在物理机上没错,但搬到 VMware 里就必须修正。虚拟机里根本不存在"网线"这个东西,你的ens33、ens34本质上是虚拟网卡(VMXNET3 或 E1000e),它们各自挂到 VMware 虚拟交换机的一个端口组上,虚拟交换机再通过物理网卡(上行链路)把流量送出去。所以虚拟机内做 bonding,绑的是内核网络栈里的两条虚拟链路,而这两条虚拟链路在上游可能是同一条物理上行、也可能是两条不同的物理上行,这直接决定了你的冗余到底有没有意义。
这就带来第一个必须想清楚的问题:你的两块虚拟网卡,是不是落在不同的上行链路上?如果宿主机的虚拟交换机只配了一块物理网卡,或者两块虚拟网卡都接在同一个端口组、走同一条上行,那么无论你在 CentOS 里怎么绑,最终都是"两根虚拟线接到同一根物理线上"。物理线断了,两边一起断,bonding 一点用没有。我在实际环境里排查过一次"bond 配了但还是断网"的事故,最后发现虚拟交换机就一个上行口,虚拟机加的那第二块网卡纯属心理安慰。
真正有冗余价值的做法是:两块虚拟网卡接到不同的端口组,而这两个端口组又分别绑定到宿主机的不同物理上行(不同的物理网卡或不同的堆叠成员)。这样从虚拟机网卡到虚拟交换机到物理交换机的整条路径才是双份的。带宽聚合同理,只有当上游确实有多条可用链路时,mode 4 或 mode 0 才可能真的把吞吐提上去,否则你看到的只是单条链路的速度。
1.2 虚拟机做 bonding 和物理机的三个关键差异
第一,MAC 地址行为不同。物理机的两块网卡各有固化 MAC,bonding 之后 bond0 通常沿用第一个加入的 slave 的 MAC。虚拟机虽然也有 MAC,但 VMware 默认的端口组安全策略里"MAC 地址更改"是拒绝的,意味着虚拟机发出的帧如果源 MAC 不是分配给它的那个,虚拟交换机会直接丢弃。bond 切换时 MAC 变化、或者你用fail_over_mac让 bond 保持固定 MAC,都可能撞上这条策略。这是虚拟机环境独有的一道坎,物理机上根本不存在。
第二,链路状态的可信度不同。物理机的网卡 down 掉,驱动能报出 link down。虚拟机的虚拟网卡"链路"状态,取决于虚拟交换机端口的状态,中间隔着 hypervisor 一层。所以单纯依赖miimon(基于 MII 状态检测)在虚拟机里未必能准确反映上游真实故障,有时候虚拟网卡一直是 up,但上游物理链路已经没了。这时候arp_interval+arp_ip_target这套基于对端可达性的检测会更有意义。
第三,混杂模式与伪传输。典型的 mode 0、mode 2 这类需要交换机侧做静态聚合的模式,在虚拟机上如果端口组没开"混杂模式",往往会出现只有一块网卡在收包的怪现象。而 mode 1 主备模式基本不受影响,这也是它在虚拟化实验环境里最省心的原因。
1.3 什么情况下你压根不该做 bonding
我见过不少环境,为了"高可用"三个字就上 bonding,结果配置复杂度飙升、收益为零。以下几种情况先别急着动手:如果业务本身跑在容器编排层、由上层做多副本和负载均衡,单机双网卡冗余的价值就很有限;如果这是一台纯内网测试机、中断几分钟完全无感,bonding 只会给后续排障增加一层不确定性;如果你真正想解决的是"网络带宽不够",那更应该先看是不是单条链路的物理瓶颈、是不是队列或中断绑核没做好,bonding 在虚拟机里提高吞吐的效果远没有想象中那么立竿见影。
还有一个容易被忽略的点:bonding 在高可用上的承诺是"链路级"的,它不解决交换机整机故障、不解决 IP 冲突、不解决上层应用连接不重连的问题。TCP 连接在切换瞬间照样会卡住,长连接照样可能超时。所以如果你的应用对连接中断零容忍,bonding 只是其中一层,别把它当成万能药。
2. 七种 mode 的取舍逻辑,别拿生产环境试错
2.1 一张表把模式、交换机依赖、适用性摆清楚
bonding 内核模块提供七种模式,每种的报文分发策略和对外部设备的要求都不一样。我把它们放在一起对照,方便你按环境直接对号入座。需要提醒的是,"交换机侧要配置"这一列决定了你在虚拟化环境中的可行性——如果虚拟机没法让上游交换机配合,那这些模式基本可以直接排除。
| mode | 名称 | 交换机侧要求 | 虚拟机环境可行度 | 典型场景 |
|---|---|---|---|---|
| 0 | balance-rr | 需静态链路聚合 | 低(需混杂模式,易乱序) | 实验验证、特定大包传输 |
| 1 | active-backup | 无需配置 | 高(最推荐) | 关键业务链路冗余 |
| 2 | balance-xor | 需静态聚合 | 低 | 需要哈希分发且能配交换机 |
| 3 | broadcast | 无需配置 | 很低 | 极特殊容错场景 |
| 4 | 802.3ad (LACP) | 需 LACP 动态协商 | 中(取决于上游) | 生产带宽聚合主流方案 |
| 5 | balance-tlb | 无需配置 | 中(依赖驱动) | 发送侧均衡,接收不均衡 |
| 6 | balance-alb | 无需配置 | 低(依赖 ARP 协商,IPv6 有坑) | 双向均衡但兼容性差 |
模式选择的本质是一个二选一:上游能不能配合你做聚合。能配合,优先考虑 4;不能配合,老老实实选 1。至于 0、2、5、6 这些,在虚拟化环境的收益和风险比并不划算。
2.2 为什么生产环境偏爱 mode 4,实验环境却更适合 mode 1
mode 4(802.3ad)是唯一一个走标准 LACP 协议动态协商的模式。它的好处是链路状态由协议维护,两端都知道对方有几条可用链路,出现单条链路故障时收敛快、不会有"一端以为是聚合、另一端没配"的错配惨案。更重要的是,它是有规范的,不同厂商设备之间互通性最好。
但 mode 4 的前提是上游必须配 LACP。在 VMware 环境里,这意味着宿主机的虚拟交换机上行要接到一台配置了链路聚合的物理交换机端口上(通常是把连接该宿主机上行的多个物理端口做成一个聚合组)。这件事在有些环境里根本做不到:宿主机和交换机之间的连接往往是共享的、由网络团队统一管理,你申请一条虚拟机级别的聚合,别人只会回你一句"我们这不做"。这种情况下强行在虚机内配 mode 4,结果就是bond0一直处于down或只激活一个 slave 的状态,因为 LACP 协商根本没成功。
mode 1(active-backup)没有这些包袱。两块网卡一主一备,只有主网卡收发,备网卡待命。交换机侧完全不需要任何配置,插上就能用。切换时延由miimon和updelay/downdelay控制,实测在虚机环境里 100ms 检测间隔配合 200ms 的updelay,切换基本控制在 1 秒以内。代价是不增加带宽——但说实话,虚拟机做链路聚合的带宽收益本来就要打问号,主备模式的确定性反而更值钱。
我的建议很直白:先按 mode 1 把链路冗余做扎实,等确认上游确实支持 LACP 并且有带宽需求,再切到 mode 4。切换的成本不高,改一下BONDING_OPTS重启网络即可,但前期方向搞错会白折腾很久。
2.3 xmit_hash_policy 和 lacp_rate 这两个参数不能拍脑袋填
用 mode 4 或 mode 2 的时候,xmit_hash_policy决定了一个报文该从哪条 slave 发出去。默认值layer2只按源/目的 MAC 做哈希,问题在于:如果流量都经过同一个网关出去,目的 MAC 永远是网关那一张网卡,源 MAC 永远是 bond0,哈希结果恒定,所有流量都走同一条 slave,聚合形同虚设。这是很多人配完 mode 4 却发现带宽没提升的根本原因。
layer3+4会用源/目的 IP 加源/目的端口做哈希,流量分布明显改善。但要注意它的边界:内核文档里明确提过,分片的 TCP/UDP 报文可能无法按端口信息正确哈希,另外同一对 IP 加同一对端口的单条连接仍然只走一条链路——也就是说单个大文件传输不会变快,只有并发多连接才会。如果你的业务是单连接大流量(比如一次大备份),配了layer3+4也不会有带宽叠加的效果,这点心理预期要先建立。
lacp_rate控制 LACP 报文发送频率,默认slow(30 秒一次),fast是 1 秒一次。链路频繁抖动或者需要快速感知的场景用fast,代价是多一点点协议报文开销。生产环境我一般给fast,因为在虚拟化环境里链路状态的感知本来就慢半拍,协议层快一点总没坏处。
还有个fail_over_mac,在 mode 1/5/6 下才有意义。默认值none表示切换时 bond0 的 MAC 会跟着变成新 slave 的 MAC,对端设备的 ARP 表需要重新学习;设成active则 bond0 始终保持同一个 MAC,切换时发送免费 ARP 通知对端。虚拟机环境下如果端口组"MAC 地址更改"策略是拒绝的,那none模式切换很可能失败,这时候必须用active。这条我吃过亏,后面排障章节会详细说。
3. VMware 这一侧的地基没打好,CentOS 里怎么配都白搭
3.1 虚拟网络编辑器里那三个安全策略,一定要看一眼
在 VMware 的虚拟网络编辑器(或者 ESXi 的端口组设置)里,每个端口组都有一组"安全"策略,默认三项全是拒绝:混杂模式、MAC 地址更改、伪传输。日常单网卡虚机用着毫无问题,一旦涉及 bonding 就会撞墙。
- MAC 地址更改:bond 切换时如果 bond0 的 MAC 变了(
fail_over_mac=none的情况),新 MAC 的帧会被虚拟交换机丢弃。做 mode 1 主备,这一项建议改成"接受",或者干脆在 CentOS 侧配fail_over_mac=active绕开。 - 伪传输:允许虚拟机发送源 MAC 与其分配 MAC 不一致的帧。大多数 bonding 场景不需要打开,除非你在做非常规的 MAC 伪装。默认拒绝保持即可,安全性更好。
- 混杂模式:接收所有经过该端口组的帧,而不只是发给自己的。做 mode 0、mode 2、mode 4 这类多网卡并行的模式,某些实现下需要打开才能正常收包。如果发现只配了一块网卡在收流量,或者抓包时行为诡异,先来查这一项。
3.2 两块虚拟网卡接同一个端口组还是不同端口组
这是一个实际操作中分歧很大的点,得看你的目的。
如果目的是链路冗余,两块虚拟网卡应该接到不同的端口组,且这两个端口组分别落到宿主机的不同物理上行上。这样才可能覆盖"某块物理网卡坏掉"这样的故障。如果两块都接同一个端口组,虽然虚拟交换机内部可能做了一些负载分发,但上游一旦是单条链路,冗余就无从谈起。
如果目的是容易做实验、验证 bonding 本身,把两块网卡接同一个端口组也完全可以,mode 1 在这个场景下照样能正常切换,只是它验证的是"虚拟网卡被禁用"这类逻辑故障,验证不了物理链路故障。
还有个物理限制要记住:单台虚拟机可添加的网卡数量是有上限的(常见的桌面虚拟化产品一般最多十块),而且不同类型的虚拟网卡(E1000e、VMXNET3)在驱动层面的行为也有差别。VMXNET3 性能好、支持多队列,是首选;E1000e 兼容性好但在某些老内核上做 bond 时表现更"迟钝"。我在同一台虚机上对比过,切换检测的灵敏度差异能到几百毫秒级别,量不大但值得知道。
3.3 上游交换机如果真的配了聚合,要让两边参数对得上
如果你的环境里上游确实为这台宿主机配置了链路聚合,那么恭喜你,可以走 mode 4 路线。但必须确认几件事:聚合组的模式是不是 LACP 主动/被动(对应 CentOS 侧的802.3ad);聚合组的端口成员和虚拟交换机上行口的对应关系是否一致;以及交换机侧有没有开启快速收敛(有些设备默认收敛时间较长,会拖慢 bond 的建立)。
一个常见的错配是:交换机侧做了静态聚合(不跑 LACP),而 CentOS 侧配了 mode 4。这种组合下 CentOS 会一直等 LACP 报文,等不到就不激活链路,bond0处于降级状态。反过来,交换机跑了 LACP 而 CentOS 侧是 mode 1,则交换机那边会认为成员端口在"半吊子"状态,可能出现端口被挂起。这类错配排查起来非常磨人,因为两端的管理员视角完全不同,所以动手前一定要把两边的模式口头确认一遍,或者对着配置截图核对。
4. CentOS 侧的完整落地流程:从认卡到验证
4.1 先把网卡认准,别把 ens33 和 ens34 搞混
动手第一件事是确认两块待绑定的网卡名字和驱动。执行ip link show或者nmcli device status能看到当前所有网络设备。这里有个坑:虚拟机的网卡命名可能因为克隆、硬件变更而顺序漂移,昨天是ens33、ens34,今天可能变成ens37、ens38。所以不要凭记忆写配置文件,一定要现场查。
顺便看一眼驱动的 offload 特性,用ethtool -k ens33 | grep -E "tx-checksum|sg"大致确认一下。bonding 对某些网卡的发送校验和卸载有要求,如果后面发现 mode 5/6 工作不正常,可以尝试用ethtool -K ens33 tx off关掉试试——这属于偏门但实测有效的调试手段。
还有一个必须做的操作:给两块网卡各分配一个临时 IP(或者干脆不分配,只确认状态UP),然后分别 ping 一下网关,确认两块卡本身都是通的。这一步的意义在于把问题分层——如果单卡就不通,问题在虚拟网络配置,跟 bonding 没关系,别把两件事混在一起查。
4.2 用 nmcli 建 bond 的完整命令序列
在 CentOS 7 及以上、尤其是 CentOS 8/Stream 之后,NetworkManager 是默认的网络管理栈,nmcli是最稳的路子。下面这套命令我按顺序给,mode 1 为例:
# 1. 确认两条以太网连接已存在且没有乱配 IP nmcli device status # 2. 创建 bond 连接,指定 mode、检测间隔和主网卡 nmcli connection add type bond ifname bond0 con-name bond0 \ bond.options "mode=active-backup,miimon=100,primary=ens33,fail_over_mac=active" # 3. 配置 IP(示例用静态,DHCP 就把 ipv4.method 改成 auto) nmcli connection modify bond0 ipv4.method manual \ ipv4.addresses 10.10.20.15/24 ipv4.gateway 10.10.20.1 \ ipv4.dns "10.10.20.1" # 4. 把两块网卡挂成 slave nmcli connection add type ethernet ifname ens33 con-name bond0-slave-1 master bond0 nmcli connection add type ethernet ifname ens34 con-name bond0-slave-2 master bond0 # 5. 起 bond nmcli connection up bond0关键在第二条命令里的bond.options。mode=active-backup是模式,miimon=100是链路检测间隔(单位毫秒,100 表示每 100ms 检查一次),primary=ens33指定首选主网卡,fail_over_mac=active让 bond0 始终保持固定 MAC,规避虚拟交换机 MAC 策略的限制。
如果你走 mode 4 路线,选项换成这样:
nmcli connection add type bond ifname bond0 con-name bond0 \ bond.options "mode=802.3ad,miimon=100,lacp_rate=fast,xmit_hash_policy=layer3+4"注意mode的取值在 nmcli 里是字符串形式,写802.3ad或者4都行,但别写成lacp之类的别名,NetworkManager 不认。
有一个容易忽略的细节:创建 slave 连接之后,NetworkManager 默认会给它们加上connection.autoconnect yes,系统重启时会自动拉起,这是好事。但如果你的环境里同时开着老的network服务和 NetworkManager,可能出现两边抢着管网卡的情况。检查systemctl status network和systemctl status NetworkManager,只留一个在跑,这个坑我踩过不止一次。
4.3 传统 ifcfg 脚本写法,老系统或特殊环境下仍然管用
有些环境里 NetworkManager 被停用了,或者需要和其他配置管理系统配合,这时候就得回到/etc/sysconfig/network-scripts/下的 ifcfg 文件。写法如下:
# /etc/sysconfig/network-scripts/ifcfg-bond0 DEVICE=bond0 NAME=bond0 TYPE=Bond BONDING_MASTER=yes BOOTPROTO=none ONBOOT=yes IPADDR=10.10.20.15 PREFIX=24 GATEWAY=10.10.20.1 DNS1=10.10.20.1 BONDING_OPTS="mode=1 miimon=100 primary=ens33 fail_over_mac=active" NM_CONTROLLED=no两块 slave 的配置文件:
# /etc/sysconfig/network-scripts/ifcfg-ens33 DEVICE=ens33 NAME=ens33 TYPE=Ethernet BOOTPROTO=none ONBOOT=yes MASTER=bond0 SLAVE=yes NM_CONTROLLED=noens34的文件除了设备名完全一样。注意 slave 的 ifcfg 里不要配 IPADDR,配了也不会生效,反而在排障时制造困惑。另外NM_CONTROLLED=no这一行很重要,不加的话 NetworkManager 可能仍然尝试接管,导致行为不可预期。
改完之后执行systemctl restart network(CentOS 7)或者nmcli connection reload && nmcli connection up bond0。CentOS 8 之后network服务已经默认不可用了,还是走 nmcli 更稳。
4.4 怎么验证"真的绑上了",而不是只看表面
配完之后最直接的证据在/proc/net/bonding/bond0。这个文件里的信息密度很高,值得逐段读:
cat /proc/net/bonding/bond0需要重点确认几个地方:Bonding Mode是不是你设的那个;Currently Active Slave指向哪块网卡;MII Status在 bond 层面和每个 slave 层面是否都是up;Slave Interface列表里是不是两条都在。如果Currently Active Slave是空的,或者某条 slave 的MII Status是down,说明绑定没生效。
再配合ip addr show bond0确认 IP 和 MAC,ip route确认默认路由指向 bond0,最后从外部 ping 一下这台机器,双向都能通才算完事。别忘了ping -I bond0指定源接口测试一下出口方向。
还有一步强烈建议做:主动触发一次切换。用nmcli device disconnect ens33把主网卡断开,然后持续 ping,观察中断时长和恢复情况,再用cat /proc/net/bonding/bond0看Currently Active Slave是否切到了ens34。测完记得把ens33连回来。没做过这一步的 bonding 配置,我从来不敢签字上线。
5. 排障实录:bond 起来了但不通,问题往往在哪
5.1 bond0 状态正常,但只有一块 slave 在收流量
这个现象最典型的表现是:/proc/net/bonding/bond0里两个 slave 都是up,但用ip -s link show看收发包计数,一块狂涨一块几乎为零。在 mode 0/2/4 下出现这种情况,先查虚拟交换机端口组的混杂模式是否开启。虚拟交换机默认只把目标 MAC 匹配的帧转发给虚机,如果你的 bond 在用多个 MAC(或者对端还没学到),另一个 slave 就收不到东西。
第二个可能是xmit_hash_policy选得不对,导致哈希结果恒定。比如全部流量都是去同一个网关、走同一个连接,layer2策略下必然只有一条链路被使用。这不是故障,是负载均衡策略的固有局限,改用layer3+4并确保有并发多连接才能看到效果。
第三个可能是上游交换机侧没做聚合,而你却用了 mode 0 或 2。此时两块网卡的帧从不同物理口出去,对端交换机看到同一个 MAC 在两个端口来回出现,MAC 地址表不停抖动,严重时还会引发环路告警。这种配置错配在交换机日志里会留下痕迹,如果条件允许,找网络侧同事看一下端口日志能省下大量时间。
5.2 断开主网卡后网络卡死十几秒,SSH 直接超时
这种情况多见于 mode 1,而且往往和三个参数有关。第一个是miimon设得太大,比如有人图省事写miimon=1000,那就意味着最坏情况下要一秒才检测到故障,加上切换和 ARP 重新学习,十几秒的卡顿完全解释得通。改回miimon=100是最基本的。
第二个是downdelay和updelay的设置。有时候链路只是瞬断(比如交换机在做端口协商、或者上游在做链路切换),你真的不希望立刻切走再切回来,来回抖动的代价比不切还大。这时候设downdelay=500让 bond 等半秒再认定故障,效果反而更好。但反过来,updelay设太大(比如 30000)会让备卡恢复后很久才被启用,看起来像"卡住了"。
第三个是我踩过最深的一个坑:fail_over_mac用了默认的none,而虚拟交换机的"MAC 地址更改"策略是拒绝。结果就是 bond0 的 MAC 从ens33的变成了ens34的,新 MAC 的帧被虚拟交换机丢掉,切换完成后网络彻底不通,比不切还惨。解决办法二选一:在 CentOS 侧加fail_over_mac=active,或者在 VMware 端口组把"MAC 地址更改"改成接受。前者更稳妥,因为它不依赖宿主机层面的配置变更,迁移到别的环境也能用。
顺带一提 ARP 监控。如果虚机所在网络存在"链路物理上还在、但上游已经断了"的情况(虚拟网络里这种情况比物理机多),miimon是检测不到的,因为虚拟网卡的 MII 状态一直是 up。这时可以加arp_interval=200 arp_ip_target=10.10.20.1,让 bond 通过 ARP 请求实际探测对端可达性。注意arp_ip_target必须是对端真实会响应 ARP 的地址(通常是网关),填一个不存在或者不响应 ARP 的地址,会导致 bond 误判所有链路都故障。
5.3 系统克隆之后 bond 配好了却互相打架
虚拟机克隆是虚拟化环境的高频操作,也是最容易埋雷的地方。克隆出来的两台机器,MAC 地址如果不重新生成,会出现两个不同的虚机用同一个 MAC 发帧的情况,表现是网络时通时不通、ARP 表混乱。bonding 会让这个问题更明显,因为切换过程中本来就有 MAC 变更动作,再叠加上 MAC 冲突,现象会非常迷惑。
判断方法很简单:ip link show bond0和ip link show ens33看 MAC,跟虚拟化平台上给这台虚机分配的 MAC 逐一比对。对不上就是有问题。修复方式是在虚拟化平台重新生成 MAC,然后进 CentOS 把 bond 和 slave 的连接重建一遍,别指望改个配置文件就能好。
还有一类克隆后的遗留问题:老的ifcfg-ens33文件里残留了MASTER=bond0,但新机器上你根本没建 bond0,结果网卡起不来。这种时候journalctl -u NetworkManager或者dmesg | grep -i bond会给出线索,别盲改。
5.4 重启之后 bond 没起来,但手动 up 就好
如果每次重启都要手动nmcli connection up bond0才能恢复,问题基本都在启动顺序和自动连接属性上。检查两个地方:nmcli connection show bond0 | grep autoconnect是不是yes;slave 连接上的master属性是否指向了bond0而不是连接名搞错。
另一种可能是 slave 的connection.autoconnect-priority或者autoconnect-slaves没设好。在 NetworkManager 里,bond 连接的bond.options如果包含primary=指定的网卡,而这网卡在启动时还没被识别,bond 会等待或者降级启动。可以临时去掉primary验证一下是不是这个原因,虽然主备模式不苛求primary,但它确实会影响启动时序。
还有一个历史问题:早期用/etc/modprobe.d/bonding.conf做alias bond0 bonding加options bond0 mode=... miimon=...的方式,和BONDING_OPTS会打架。两处都配了、参数还不一致的话,最终生效的是谁取决于加载顺序,非常难查。统一到一处,我一般只保留BONDING_OPTS(ifcfg 路线)或 nmcli 的bond.options(NetworkManager 路线)。
6. 让它长期稳住:监控、参数收敛与版本升级
6.1 用一个十行脚本盯住 bond 状态
配完不等于结束,bond 的故障往往是"静默"的:主卡坏了切到备卡,业务无感,于是没人发现备卡也在抖。等哪天备卡也挂了,才知道冗余早就名存实亡。所以我习惯加一个定时检查,每五分钟扫一次状态,异常就告警。
逻辑不复杂:读/proc/net/bonding/bond0,统计MII Status: up的 slave 数量,如果少于预期(两块)就发告警;再检查Currently Active Slave是否为空。用 shell 写就够,不需要引入额外组件:
#!/bin/bash BOND=bond0 UP=$(grep -c "MII Status: up" /proc/net/bonding/$BOND) ACTIVE=$(awk '/Currently Active Slave/ {print $4}' /proc/net/bonding/$BOND) if [ "$UP" -lt 2 ] || [ -z "$ACTIVE" ]; then echo "ALERT: $BOND degraded, up_slaves=$UP, active=$ACTIVE" fi注意grep -c "MII Status: up"会把 bond 自身那一行也数进去,所以判断阈值得算清楚——bond 层一行加两个 slave 两行,正常是 3。这种小细节如果不校准,告警会一直误报,最后大家都去屏蔽它,监控就废了。这类阈值一定要在正常状态下先跑一遍看真实输出再定。
6.2 miimon 和 updelay/downdelay 的取值逻辑
这三个参数是最容易"抄了别人的配置但不知道为什么"的地方。miimon是检测周期,单位毫秒,值越小检测越灵敏、开销越大。100ms 是绝大多数场景的平衡点,30ms 以下基本没必要,反而增加中断处理负担。
downdelay是"检测到故障后等多久才真正认定故障",updelay是"检测到恢复后等多久才启用"。这两个值的设计初衷是吸收链路抖动,避免来回切换。取值一般设为miimon的整数倍,比如miimon=100配downdelay=200、updelay=200,意思是连续两次检测失败才算故障。如果环境里链路特别稳,可以适当拉长到 500ms 甚至 1000ms;如果业务对切换时延极其敏感,那就设成和miimon相等,牺牲一点抗抖动能力换取快速切换。
需要强调的是,这两个参数在虚拟机环境下的实际效果会受到虚拟交换机链路状态上报机制的制约,不是设了 100ms 就一定能 100ms 感知。可以做一次实测:断开一块网卡,用ping -i 0.1记录丢包个数,反推真实切换时间,这个数据比任何文档都有说服力。
6.3 内核升级或迁移之后,bond 配置可能悄悄失效
有几个已知的兼容性变动值得留意。一是 CentOS 8 及之后的版本里,network服务被 NetworkManager 取代,老 ifcfg 文件虽然还能被读取,但NM_CONTROLLED=no的语义和 CentOS 7 时期并不完全一致,行为可能有细微差别。二是 team 这种 bonding 的替代方案在较新的发行版中被标记为不再推荐,如果你原来的环境用的是 team,迁移时要评估是否换成 bonding。
三是内核版本变动对 bonding 模块参数的支持范围。比如fail_over_mac在很老的内核上只有none和active两个值,新内核增加了follow。如果配置里写了一个当前内核不认识的取值,bond 会加载失败或者回退到默认值,而日志里可能只有一行不起眼的警告。养成升级后跑一遍modinfo bonding和cat /proc/net/bonding/bond0的习惯,比出事之后再翻日志效率高得多。
最后分享一个小技巧:如果你的环境里有多台机器要用同一套 bonding 配置,别手工复制 ifcfg 文件。用一套参数模板加上主机名和 IP 的变量替换,配合配置管理工具下发,能避免"某台机器的 miimon 少写了一个零"这类低级但致命的错误。我在一次批量部署里就因为模板里mode=1被误写成mode=0,导致十几台机器在上游交换机上疯狂制造 MAC 漂移,事后复盘时发现,加一条"部署后自动校验 bonding mode 与预期一致"的检查,成本几乎为零,却能挡住绝大多数手滑。