InfiniBand 专题【左扬精讲】—— InfiniBand SM 监控与拓扑变化:选举、故障切换、扫描与重收敛

InfiniBand 专题【左扬精讲】—— InfiniBand SM 监控与拓扑变化:选举、故障切换、扫描与重收敛

子网初始化只是开始,子网激活之后的故事才真正决定一个 fabric 能跑多久。本系列上一篇已经把 "从一堆线缆变成一个可传数据的子网" 的六个阶段讲完——拓扑发现、LID 分配、路径计算、端口配置、节点编程、最终激活。但在生产环境里,一个 fabric 真正的工作时间远比这一次性的初始化过程长得多:交换机可能会重启,链路可能会 down,HCA 可能拔下来或新插一块进来,HCA 本身或它上联的那台叶交换机可能整台故障。

这些变化发生时,子网必须重新收敛(converge)到新的拓扑上,且收敛时间越短越好。负责这件事的,仍然是子网管理器(Subnet Manager,SM)。SM 的第二类职责——持续监控子网、检测变化、并触发必要的重新初始化——是本篇的主题。

本篇是 InfiniBand 专题【左扬精讲】 系列的 第 9 篇,承接第一篇的 SM / SMA / MAD 三角色、本系列上一篇的风格总结向——"数据结构层" 六个初始化阶段,按 "持续运行期" 的四个主题展开:先讲 多个 SM 同时存在时的属性与主备选举,再讲 主 SM 自身故障时的 failover 与备 SM 接替后的 handover,再讲 SM 如何通过轻扫/重扫(light sweep / heavy sweep)持续监控拓扑变化,最后落到 运维手里的几个 OFED 工具:smpquery / ibstat / ibnetdiscover / ibswitches / ibroute,全部对应该领域在 Linux rdma-core 与 OFED infiniband-diags 工具集中的真实可观测行为。

本篇的核心命题只有一句:InfiniBand 子网的"高可用"不是单点机器的不死,而是监控平面 + 控制平面 + 数据平面三层互相补偿后达到的快速重收敛。理解了这三层的工作分工,"为什么备 SM 接替时业务会话几乎不受影响"与"为什么一条链路 down 之后能很快恢复"就有了确定的解读路径。

本篇核心术语:
Subnet Manager (SM) 子网管理器 / Standby SM 备用 SM / Master SM 主 SM
SM Priority SM 优先级 / SM GUID SM 全局唯一标识符 / SM Key SM 密钥 / SMInfo attribute SM 信息属性
Poll / Polling 轮询 / Failover 故障切换 / Handover 接管
Heartbeat 心跳 / In-Band 带内 / Trap 陷阱 / Notice 通知
Light Sweep 轻扫 / Heavy Sweep 重扫 / Sweep Interval 扫描周期
SMP (Subnet Management Packet) 子网管理包 / Get / Set / Get Response / Trap
NodeInfo 节点信息 / PortInfo 端口信息 / SwitchInfo 交换机信息 / Port GUID / Node GUID
LID assignment LID 分配 / LID-to-GUID database LID 到 GUID 映射库
OpenSM opensm 用户态守护进程 / perftest ib_* 一组性能测试工具

本篇核心命令:smpquery / ibstat / ibnetdiscover / ibswitches / ibroute / opensm -d / perfquery

本篇权威依据:IBTA Vol 1 Release 1.3.4(An InfiniBand Architecture Specification, Release 1.3.4, 2020)
rdma-core include/rdma/ib_mad.h 与 include/rdma/ib_smi.h 与 include/rdma/ib_smp.h
Linux 内核 drivers/infiniband/core/sa.c SM 路径选择 / drivers/infiniband/core/mad.c MAD 处理
OpenSM 用户手册 opensm(8) man page 与 doc/OpenSM_UM.pdf / infiniband-diags 官方手册

InfiniBandSMSM 选举FailoverHandoverDouble FailoverLight SweepHeavy SweepTrapNoticeTopology ChangeOFEDsmpqueryibstatibnetdiscoveribswitchesibrouteopensm

★ 学完这一篇你能掌握什么(渐进式路径:1→2→3→4 不可跳跃)

  • 第 1 步 · 选举(第一节、第二节)
      • What:每个 SM 含一个 4 位 SM Priority 字段(取值 0~15,0 最低,15 最高,默认 0);多个 SM 时的决策依据:优先级最高者胜出 → 优先级相同时 GUID 最小者胜出
      • How:能复述 SMInfo 属性在 SM 之间的交换方式,以及为什么"相同配置下选 GUID 最小"是一种"随机但确定的"选举
      • Why:理解 "为什么需要至少两个 SM"——主 SM 故障后若无备 SM,所有新会话无法建立;同时理解"管理员手动配置优先级"如何决定主 SM
  • 第 2 步 · Failover 与 Handover(第三节、第四节)
      • What:Failover = 主 SM 失效后,备用 SM 接替为新主 SM;Handover = 新 SM 优先级比当前主 SM 更高时,mastership 移交;Double Failover = 失效的主 SM 恢复后,由于其优先级更高而触发再次移交
      • How:能描述新主 SM 接替时的"LID 复用策略"—有 LID-to-GUID 数据库就先复用、没有就回退到节点侧查询
      • Why:理解 "为什么推荐把 master SM priority 设为 15"。设为 15 后,任何正在运行的主 SM 都不会因为另一 SM 优先级更高而发生 handover——从而避免双故障
  • 第 3 步 · Sweep(第五节、第六节)
      • What:Light Sweep 每 10 秒一次(可在 opensm.conf 中改),只查节点信息和端口状态;Heavy Sweep 在 Light Sweep 检测到变化或 SM 收到 Trap 时触发,相当于"重跑七步初始化"
      • How:能列举 Light Sweep 监视的四类事件(端口状态变化、SM 信息传播、Trap 接收、HCA 状态变化),并判断哪些事件会升级为 Heavy Sweep
      • Why:理解 "为什么 Heavy Sweep 不一定需要重算所有转发表"——针对 HCA 故障或离叶故障,有专门配置可跳过转发表重算
  • 第 4 步 · OFED 工具(第七节)
      • What:smpquery 用 SMP 拉取单个节点/端口信息;ibstat 显示本地端口状态;ibnetdiscover 拓扑发现并打印节点;ibswitches 列出所有交换机;ibroute 查交换机转发表
      • How:能在已知主 SM LID 的前提下,用 smpquery -D sminfo LID 查任意 SM 的状态
      • Why:理解 "为什么这些工具里只有 smpquery 能指定非 LID 寻址"——因为它要服务发现期 LID 还没分配的场景

★ 阅读前提 & 本篇不涉及的内容

  • 前置知识:本系列第一篇《InfiniBand 架构简介:从五层模型到子网管理》中的 Fabric vs. Subnet、SM / SMA / MAD 三角色、GUID / LID / GID 三层地址、LID 路由与定向路由;以及本系列上一篇《子网初始化:拓扑发现、LID 分配、路径计算与子网激活》中的"六/七阶段初始化流程"、端口物理/逻辑状态、LFT 表项结构。本篇不重复解释这些内容
  • 信息来源:本篇所有字段名(SM Priority / SM GUID / SM Key)、方法码(Get / Set / Trap)、属性 ID(NodeInfo 0x0011 / PortInfo 0x0015 / SwitchInfo 0x0012 / SMInfo 0x0020)均引自文末「参考资料」列出的 include/rdma/ib_mad.h、include/rdma/ib_smi.h、include/rdma/ib_smp.h 与 IBTA / O'Reilly 规范原文;工具输出格式引自 infiniband-diags 官方 man page
  • 本篇不涉及:QP / RC / UD 等传输层细节(见第二篇)、子网初始化六个阶段的内部细节(见第八篇)、QoS 策略配置语法、组播路由的具体算法、随机转发表(Random Forwarding Table)的散列细节

一、SM 属性:优先级、guid、key 与 SMInfo

What — 这一节讲清楚四件事

课程明确:SM 与 SMA 的关联 已经在第一篇讲过;本节要展开的是 "多个 SM 同时存在于一个子网" 时必须先定义清楚的四类属性。它们是后续选举、failover、handover 共同依赖的基础词汇:

  1. 每个 SM 含一个 4 位优先级字段,零最低,十五最高,默认值是零(each SM contains a four-bit priority value with zero being the lowest priority and fifteen the highest. The default is zero.)
  2. 子网中可以同时存在多个 SM,但必须有一个被选为主 SM(only if one of them is elected as the master)。其余的作为备用 SM 不断轮询主 SM 的活动状态(standing by polling the master activity)。
  3. 当主 SM 失效时,其中一个备用 SM 将被选为新的主 SM(in case the master fails, one of them will be elected as the new master)。
  4. 通常推荐运行两个 SM(generally, it is recommended to run two subnet managers)——一个主、一个备。

把四点合起来看,"多 SM + 主备 + 默认都是 0" 是规范描述的常态。这意味着两台默认配置的 OpenSM 没有任何主备倾向,实际胜出者将由它们各自的 GUID 决定——这一点第二节会展开。

1.1 SMInfo:SM 之间交换心跳的载体

课程指出:SM Info 属性被 SM 用作子网发现/轮询期间的交换信息(the SM info attribute is used by subnet managers to exchange information during subnet discovery and polling)。这段表述拆开来看,包括三件独立的事:

  • 一是 "exchange information"。这意味着 SMInfo 是一个公共可读的属性,任何 SM 都可以从任何其他 SM 那里 Get 到它的 SMInfo,从而得知对端的 SM GUID / 值班优先级 / 状态。
  • 二是 "during subnet discovery"。这表明 SMInfo 在 fabric 刚初始化完时就已经开始交换。SM 之间的互相识别 不是等第一个主 SM 上线才开始,而是子网建立过程的伴随动作。
  • 三是 "as a heartbeat"。备用 SM 通过观察主 SM 的 SMInfo 是否还在定期更新 来判断主 SM 是否还活着。SMInfo 因此承担了带内心跳的角色。

SMInfo 还包含了一些具体的字段,这些字段本身就是 IBTA 规范定义的,并非任何实现的私有扩展:

字段名含义取值来源
SMKey SM 的认证密钥 8 字节,默认为全 0,相同 key 的 SM 之间才有"备对主"的发现关系 include/rdma/ib_smi.h
SMPriority SM 优先级 4 位,0 最低 / 15 最高 / 默认 0 同上
SM GUID SM 所驻端口的 Port GUID 64 位,全局唯一 同上
SM State SM 状态 4 位:NotActive (0) / Discovering (1) / Standby (2) / Master (3) include/rdma/ib_mad.h
ActivityCount 心跳计数器 每个心跳 +1,主 SM 每隔 ~10s +1(与 Light Sweep 节拍一致) include/rdma/ib_smp.h

把这些字段放回原句 "SM info attribute" 能得到一个完整的画面:SMInfo 是唯一一个把 "GUID(我是谁)+ Priority(我的优先级)+ State(我是哪种 SM)+ ActivityCount(我最近一次心跳是什么时候)" 同时打包到一个 MAD 属性里的字段。它在 1.2 节的选举算法与 1.3 节的 failover 判定里都会被用到。

关于 "SM GUID" 字段的命名:IBTA 规范把这个字段命名为 SM GUID,但它的实际值 是 SM 所在端口的 Port GUID,不是 SM 进程的某个唯一编号。这意味着两台启动在同一台主机的不同端口上的 OpenSM 将拥有两个不同的 SM GUID——它们以端口为单位区分身份。这一点在排查 "两台 SM 抢同一个 master" 时很关键。

1.2 默认配置下,选举其实是"随机的"

Why — 这句话出自课程原话

课程在描述选举标准时给出了一个非常清晰的陈述:

当多个 SM 存在于子网时,主 SM 的选举遵循以下标准。具有最高 SM 优先级的 SM 被选为主 SM。如果多个 SM 优先级相同,则择高 guid 最小者胜出,其余作为备用。

这意味着如果两台 SM 都按默认优先级 0 启动(即出厂即"双 0"),选举判据就完全退化为 GUID 比较,GUID 最小的那台成为主 SM。

课程随后给出了一个让工程人员意外但又明确的说法:"按 GUID 最小者选出"是随机选举,如果主备节点有相同的配置,哪一个被选为主并不重要(election based on lowest guid ID is a random election if the master and stand by nodes have identical setups. It's irrelevant, which one is elected as the master.)。

把这两句话并起来读,会发现一个关键推论:在没有人工干预的情况下,哪台 SM 成为 master 是"随机但确定的"——随机是因为 GUID 不携带"我应该当 master"的语义,确定是因为 GUID 永远不会随机生成。对运行后自动选择无所谓的设计,可以信任这个默认机制;对运行后需要稳定主备的部署,应该主动设置 sm_priority。

1.3 何时需要管理员手动设置优先级

课程给出了清晰的判定原则

课程原话是:然而,如果存在一个节点更适合作为主 SM 运行,建议系统管理员手动配置优先级(however, if there is a node that is preferred to run as the master SM, it's recommended that the system administrator configures the priorities manually)。

这句话看似温和,但实际上说出了三件事:

  • 一、默认配置下管理员是被动的。SM 之间会自动选出一个,管理员无法在不调整优先级的情况下指定哪一个是主。
  • 二、人工配置不是越权。管理员手动设定优先级并不"篡夺"自动机制——它只是把自动选举的随机性去掉,指定一个唯一更高的优先级。
  • 三、人工配置的目标是"可预测"。其背后是运维场景中"我希望 A 永远作主,B 永远作备"的硬性需求,默认配置不能满足。

本节关键记忆:4 个字段 + 1 个判断

  • 4 个核心字段:SMKey(8 字节认证密钥)/ SMPriority(4 位,默认 0)/ SM GUID(64 位 Port GUID)/ SM State(NotActive / Discovering / Standby / Master)
  • 1 个判断: 课程原话 "如果存在一个节点更适合作为主 SM,建议管理员手动配置优先级"——默认配置下哪台当主是"随机但确定的"
  • 1 个官方建议: 通常推荐运行两个 SM,一个主、一个备,单 SM 部署在新主选举前新会话全部不可建立
  • 1 个易错点: SM GUID 字段的值是 SM 所驻端口的 Port GUID,同一节点不同端口启动两台 OpenSM 会得到两个不同的 SM GUID

二、Master SM 选举:优先级 → GUID 最小者胜出

What — 选举的两步决序

上一节把选举的依据字段介绍清楚了,本节讲具体的选举过程。课程给出的判据只包含两步:

  1. 优先级最高者当选。该字段为 SMInfo 的 SM Priority 字段,4 位。
  2. 如果多个 SM 优先级相同,则 GUID 最小者当选。该字段为 SMInfo 的 SM GUID 字段,64 位 Port GUID。

这两步合起来构成的判据是字典序:(Priority 降序, GUID 升序) 排第一的就是 master。

2.1 选举在什么时候发生

课程没有明说选举发生的时刻,但根据 1.1 节的字段语义可以推论得很清楚:

场景触发选举的动作选出的结果
初始上线 第一台 SM 完成发现 → SMInfo 交换 该 SM 成为 Master,其余为 Standby
新 SM 启动 其 SMInfo 与现有 SM 比较 若新 SM 优先级更高——handover(第四节)
Master SM 失效 Standby SM 在多个心跳周期后未收到主 SM 的 SMInfo Standby SM 之间重新运行同一种选举,胜出者转为 Master

第三条就是 1.1 节里的"为什么 SMInfo 是 heartbeat"的反面——在主 SM 心跳停止后,备 SM 在 多个心跳周期 内没有收到主 SM 的 SMInfo,于是重新运行选举。这个"多个心跳周期"在 OpenSM 实现里是两个心跳,即 ~20 秒,对应 Light Sweep 10s/次、连续 2 次缺失。

关于 "两个心跳" 这个阈值的来源:它来自 OpenSM 的 include/osm.h 中 OSM_SM_POLLING_TIMEOUT 的默认值 2000ms(单次轮询周期),以及 sm_info.c 中 OSM_DEFAULT_TIMEOUT_MULT 的乘数 10 倍数含义——两个乘数之内的心跳即被视为"主 SM 未失效"。本地资料与规范检索中未找到 IBTA 规范对这一阈值的明文强制,本节如实说明其为 OpenSM 实现的选择,不将它表述为协议层规定。

2.2 SMInfo 字段如何被读到

SMInfo 在协议层是 Subn Get Response(SMInfo) 这个 MAD 应答中的一个属性。备用 SM 主动 发起 Get 请求去读主 SM 的 SMInfo,根据返回值判断主 SM 是否还活着。这个过程不在 "Trap" 类消息里——课程明确指出 SM 之间使用 通过轮询主 SM 的活动,而不只是被动的 Trap。

     Master SM 选举后的三方交互概览
   
        主 SM 字段:                        备 SM 字段:
        SM State = Master (3)             SM State = Standby (2)
        ActivityCount 每 +10s 加 1         主动轮询主 SM 的 SMInfo
        周期下发 SMP(Heavy Sweep 触发时)  发现 ActivityCount 不再上升
        ↑                                       ↓
        ↑          Get(SMInfo)                  ↓
        ↑       <──────────────────┐              ↓
        ↑                            │              ↓
        SMInfo = 3 节点                    │           备 SM 之间的选举:
        (GUID 备份)         GetResponse(SMInfo)       Priority 高者 → master
        (ActivityCount)        │           │           ↑ 得去原 master 则重叠
        ↑                            │           新 master 上线 → 重扫、重算、重激活
        ↑                       SMInfo 包含的所有信息
        ↑                       (GUid、Priority、State、ActivityCount)
        ↑
        主 SM 同样会 轮询其它 SM 的 SMInfo
        (判断是否有未覆盖的 SM 在准备接管)
结构视角 — 为什么 SMInfo 既能被 Get 又能被 Get,轮询是一组双向动作

把 1.1 节的字段定义与本节的"心跳 + 选举"动作合并起来看,会发现 SMInfo 有一个非常特殊的属性:它既能被"读"也能被"写",轮询的双方都同时是请求者与应答者。这一点与典型的"主从服务"模式不一样,理解这个区别是选错其他设计模式的根源。

看看读的方向。主 SM 的 SMInfo 包含 SMKey / SMPriority / SM GUID / SM State / ActivityCount。备 SM 通过 Get(SMInfo) 读到这五个字段,从而判断主 SM 是否还活着、是否仍然是 master、优先级是否发生了变化。

再看写的方向。每个 SM 会定期更新自己的 SMInfo 中的 ActivityCount。这个更新通过 < 当前 ActivityCount + 1> 并 Set(SMInfo) 写入。课程里这个动作隐含在 "polling the master activity" 的描述中——它不是一个独立的"心跳消息",它就是 SMInfo 自身。

这种"自报"模式的双向性。主 SM 不向备 SM "发心跳",主 SM 只是定期更新自己的 SMInfo;备 SM 不等待主 SM "推心跳",备 SM 只是周期性去 Get 主 SM 的 SMInfo。主 SM 的 ActivityCount 在递增 + 备 SM 的 Get 读到这个递增 = 心跳信号。这个设计的优势是不需要定义额外的心跳报文类型,所有 SM 之间的状态同步都复用同一个属性。

这个设计的代价是有限的"失效检测延迟"。备 SM 不会立刻发现主 SM 的失效——它要等到下一次轮询周期超时才知道 ActivityCount 不再上升。延迟的长度 = 轮询周期 × 失效检测倍数,课程并没有明文规定,但 OpenSM 默认是 ~10s × 2 = ~20s 量级。这个延迟决定了 failover 的下限。

本节关键记忆:2 步判据 + 1 个选择 + 1 个延迟

  • 2 步判据:Priority 高者胜 → 相同则 GUID 小者胜——字典序 (Priority desc, GUID asc)
  • 1 个选择:默认两台 SM 优先级都是 0 时,GUID 最小者随机但确定地成为 master
  • 1 个延迟:failover 检测延迟取决于轮询周期 × 失效倍数,默认值约 20 秒
  • 1 个双向:SMInfo 既可 Get 又可 Set,心跳是"自报 + 轮询"的组合,不需独立的心跳报文类型

三、Failover:主 SM 失效后的接管流程

What — 课程对 Failover 的完整定义

课程给 Failover 下了一个完整的定义,必须逐句拆解:

  • 场景。主 SM 自身失效。这是一个必须被考虑到的故障场景。
  • 响应。每个备用 SM 都应随时准备成为主 SM,当主 SM 失效或失去连接时。
  • 交通。当主 SM 失效时,正在运行的会话的流量不应受影响——即在主 SM 失效之前已经建立的会话 仍能保持流量。
  • 新会话。新会话需要等待新主 SM 被选出后才能传输数据。
  • 无备场景。如果没有备用 SM 且主 SM 失效,新会话无法建立。
  • LID 不变。通常建议在新主 SM 上线时不要更改 LID,因为可能有依赖 LID 编号的服务会因此中断——这样的服务会中断。

这 6 句话其实传达了 6 个独立的运维含义。把它们与本系列上一篇「子网初始化」的 6 个阶段对齐,可以看到一条清晰的脉络:

  • 业务老会话不受影响——因为现有 LFT 已经写进了交换机硬件,新主 SM 不需要重写这些表项
  • 新会话需要等待——因为新主 SM 还没完成 重发现 → 重新分配 → 重算路径 → 重新编程转发表 → 重新下发 Active 这套流程
  • 无备即停摆——这是为什么课程一开始就推荐"通常两个 SM"

3.1 新主 SM 接替时的"LID 复用策略"

课程给出的策略描述非常具体:

  • 新主 SM 将尝试从 LID 到 GUID 数据库中提取前一个 master 分配的 LID(the new master will try to pull the lids assigned by the previous master from the lid to guid ID database)
  • 这个数据库在 fabric 初始化时创建——指本系列上一篇讲过的 LID 分配
  • 如果该数据库不可用,新主 SM 将尝试从节点本身拉取分配的 LID
  • 当一个节点被 master SM 分配 LID 时,它会本地存储——这是课程原话 "when a note is assigned a lid number by the master SM it stores it locally"
  • 如有必要,LID 信息由新 master SM 在其 fabric 发现阶段收集——这是课程原话 "if required, lid info is gathered by the new master SM during its fabric discovery stage"

把这两条策略连起来看,可以得到一个明确的优先级顺序:

顺序数据源使用条件含义
1 LID-to-GUID 数据库 可用 优先使用。复制旧 master 的 LID 分配
2 节点本地存储 数据库不可用 每个 HCA / 交换机从 PortInfo.LID 读出上一次的 LID
3 新分配 前两者都不可用 重新分配 LID,但通常应避免

课程说 "the lid info is gathered by the new master SM during its fabric discovery stage"——这意味着 LID 信息是新 master SM 在重跑发现阶段顺便收集的,不是一次独立的"全网节点配置信息备份"。这解释了为什么 OpenSM 默认会把 LID-to-GUID 数据库持久化在 /var/lib/opensm/ 下——主 SM 进程一旦重启,这个文件就是 LID 复用的最后一道防线。

     LID 复用优先级顺序
  
                1、LID-to-GUID 数据库
     /var/lib/opensm/guid2lid.lid  (默认存放路径)
     旧 master 在位时定期写盘
          ↓  不可用
                2、节点本地存储
     HCA 、交换机每个端口的 PortInfo.LID 字段
     旧 master 分配的 LID 本地存储
          ↓  不可用
                3、新分配
     新 master SM 重新分配 LID
     (可能会造成依赖 LID 的服务中断)
     课程明确不推荐走到这一步
会话视角 — 为什么"老会话不受影响"并不意味着"什么都不变"

课程给了一个看似简单的承诺:"会向老会话不受影响"。但这个承诺背后有几个互不重叠的部件,每一件都必须验证才能保证老会话不断流。

看 QP 状态。QP(Queue Pair)的状态保存在本端 HCA 的内存里,不依赖 master SM。这是 RC(Reliable Connection)传输类型中"老会话不受影响"的最根本原因——只要 HCA 不被替换,原 PSN(Packet Sequence Number)窗口、ACK 状态、未完成的 WR(Work Request)都还在。

看 LFT 表。老会话用的所有路径信息都已经写入了每一台交换机的 LFT 表,并且以硬件速度运行。Failover 期间新 master 不需要重写这些表——交换机继续按现有 LFT 转发老会话的数据包。

看 ARB / PKEY 表。QoS 表(0x0017 / 0x0018)与分区表(0x0016)是永久性配置,主 SM 下发后不会自己修改,Failover 也不需要修改。

但新会话需要新的 master。新会话要建立一个新的 RC 连接时,Connection Manager 或应用层需要查询新 master获取路径信息。这意味着 CM 内部会使用 SA (Subnet Administrator) PathRecord 查询 ——这个查询的应答者是 当前 master SM。如果新 master SM 还没完成发现与路径计算,CM 查询就会阻塞或报错。

所以老会话不受影响的边界是:老会话本身能跑,新会话需要等 CM 查询被新 master 应答。课程说 "new sessions need to wait until the new master SM is elected"——这句话的更准确含义是 "until the new master SM has completed the discovery → re-LID → recompute path → reprogram LFT → send Active to ALL ports cycle"。

3.2 Failover 检测延迟:从心跳停止到新 master 上线

“两个心跳”是工程上的经验值,不是规范中的明文

课程没有明说 Failover 从 "心衰" 到 "新 master 上线" 总共需要多久。但这个延迟是运维同学必须理解的,因为它直接决定业务会话能接受多长时间的不可用。

把本节与 2.1 节合并起来,可以得到一个延迟分解:

  • 检测阶段(从主 SM 失效到备 SM 决定接管)。包含两个心跳周期的轮询——~10s/轮 × 2 = ~20s。
  • 选举阶段(多个备 SM 之间决定谁是新 master)。备 SM 之间运行同一种 Priority+GUID 选举,耗时 ~1 个心跳周期,~10s 量级。
  • 收敛阶段(新 master 完成重发现 → 重分配 → 重算 → 重编程 → 重激活)。本系列上一篇讲过的 5 个阶段,耗时与 fabric 规模相关,对几百节点到上千端口的拓扑通常 < 5s。

加起来总延迟:检测 + 选举 + 收敛 ≈ 30 秒到 35 秒。这解释了为什么课程一开始就明确推荐了两套 SM——一个主、一个备——而不是仅仅一个:单 SM 部署下,Failover 延迟还是这么多,但中间业务却“完全不可建连接”。

本节关键记忆:6 件事 + 1 个优先级 + 1 个延迟分解

  • 6 件事:业务老会话不受影响 / 新会话需等待 / 无备即停摆 / 推荐两个 SM / LID 应保持不变 / 复用优先于重分配
  • 1 个优先级:LID-to-GUID 数据库 → 节点本地存储 → 新分配,课程不推荐走到第三步
  • 1 个延迟分解:检测 ~20s + 选举 ~10s + 收敛 < 5s ≈ 30~35s
  • 1 个边界:老会话不受影响是因为 QP 状态、LFT 表、PKEY 表这三件都不依赖 master;新会话需等待是因为 CM 路径查询依赖新 master

四、Handover 与 Double Failover:为什么推荐 master priority 15

What — Handover 与 Failover 的区别

课程给了一个非常清楚的区别:

  • Failover 发生在主 SM 失效后。这是一个"被动"动作——不是有谁主动让出,是主 SM 不在了。
  • Handover 发生在子网中引入了一个比当前主 SM 优先级更高的新 SM 时。这是一个"主动"动作——是优先级排序的结果。

两个动作的结局都是 mastership 易手,但触发原因不同:前者是原主不在,后者是新的胜者出现。

4.1 Double Failover:为什么这是一个需要单独定义的场景

课程给出了一个具体的例子用于解释 Double Failover:

  • 场景前提:fabric 中运行着两个 SM,一个主 SM 优先级为 14,一个备 SM 优先级为 13。
  • 中间动作:主 SM 失效。优先级为 13 的备 SM 通过 failover 接管成为新主 SM。
  • 后续动作:失效的主 SM 恢复上线。由于它的优先级 14 高于当前主 SM 的优先级 13,当前主 SM 必须向刚刚恢复的 SM 进行移交。
  • 结局:再次触发流量密集的发现过程——也就是另一个 heavy sweep 周期。

课程原话是这样描述这种场景的:"这个场景也被称为双重失效"(this scenario is also called a double failover)。课程明确建议避免 SM handover 以提高稳定性、减少开销、改善整体性能(it's recommended to avoid SM handovers in order to increase stability, decrease overhead and improve overall performance)。

Why — 为什么 Double Failover 是一个独立场景

把 4.1 节与 3.2 节的延迟分解合并起来看,Double Failover 是一个由人工优先级配置错误引入的多余一次重收敛。代价分解:

  • 第一次收敛:原主失效 → 备 SM 接替 → 重发现、重算、重激活。耗时 ~30~35s。
  • 第二次收敛:原主恢复 → 优先级高 → 强制 handover → 再次重发现、重算、重激活。再耗时 ~30~35s。
  • 总代价:在 ~1 分钟内连续两次重收敛。中间老会话可能因为表项重写而丢包,新会话在这两个周期内都被阻塞。

课程对这个代价的描述是 "increase stability, decrease overhead, improve overall performance"——这意味着 handover 的代价不仅是收敛时间,还包括这条路径上所有会话的临时中断。换言之,避免 handover 不是优化,是必选项。

4.2 解决方案是把 master SM priority 设为 15

课程给出了一个非常具体且可操作的解决方案:

  • 推荐将参数 master SM priority 设为最高值,即 15。设置后,只要一个 SM 是 master,它就具有由 master SM priority 标志设置的优先级。
  • 也建议 master SM priority 的值高于 SM priority。这里的 SM priority 指 Standby 优先级。

把这两句话组合起来,可以得到一个清晰的规则:

字段课程推荐的取值意义
master_sm_priority 15 正在运行的主 SM 的实际优先级——不管新加入的 SM 配置了什么 sm_priority
sm_priority 小于 15 备用 SM 的优先级——必须小于 15,否则会抢主

这个配置的精妙之处在于:只要主 SM 还在线,它的优先级始终是 15。这意味着无论后面启动多少个新 SM,只要它们各自把 sm_priority 设到 14 及以下,都不可能触发 handover。反过来说,只有当主 SM 真的失效时,备 SM 才能接管——因为当原主失效后,它不能再"维持"自己的 15 了,备 SM 之间的选举回到常规 sm_priority 比较。

     master_sm_priority = 15 下的 handover 避免机制
  
       主 SM                  新启动 SM
       SM Priority = 15       SM Priority = 14
       (该值是"正在运行"才有效)  (不能超过主)
       ↑                              ↓
       ↑          Get(SMInfo)           ↓
       ↑       <──────────────────────┐ ↓
       ↑                              │ ↓
       SMInfo:                          │ ↓
       SMPriority = 15                 发现主 SM 优先级 15 > 自己
       SM State = Master                → 保持 Standby
       ↑                                ↓
       ↑          GetResponse         ↓
       ↑       <────────────────────── ↓
  
       只有主 SM 失效 → 备 SM 之间重新选举
       (这个时候 没有 "在线主 SM")
       → 才会避免 "原主恢复后又 handover" 这个 双重失效场景
字段视角 — 为什么 OpenSM 必须把 "主 SM 优先级" 与 "备 SM 优先级" 分开为两个变量

课程推荐 master_sm_priority = 15 这个看似简单的设置,背后揭示了一个 OpenSM 设计中的事实:"主 SM 的优先级" 与 "备 SM 的优先级" 在配置文件中是两个完全独立的字段。

看配置文件中的字段。OpenSM 的 opensm.conf 默认会包含两个字段:

  • master_sm_priority:决定正在运行的主 SM使用的优先级,默认 15。
  • sm_priority:决定这台 SM 作为备用时使用的优先级,默认 0。

两个字段在选举中互不干扰。当本机是 master 时,它对外报出的优先级是 master_sm_priority,不报 sm_priority。换台机变主时,则反过来用新主机的 master_sm_priority。这意味着同一台机器的 master 与 standby 优先级可以在配置上不同,同一 fabric 中所有 master 拥有候选的 "最大优先级" 都是 15。

这个设计的额外好处。如果发生 Failover、原主恢复,原主恢复后重新加入主位。原始 master 的 master_sm_priority 还是 15,与当前主 SM 在 master 位报出的 15 相同——二者 GUID 比较决出胜者。这是另一个稳定的优化点。

为什么课程要明确推荐 15。从上面可以看出,master_sm_priority 的值决定了"原主恢复后会不会抢回 master 位"。15 是最大可能值,是这个字段不可能被超过的上限。设为其他值意味着可能被一个同样配置为更高 master_sm_priority 的新 SM 抢主——这又是一种 double failover 的变体。

4.3 "推荐" 与 "不强制" 的边界

课程在原话中使用了 "it's recommended" 这个词

课程原话是 "it's recommended to avoid SM handovers"——这只是一个推荐,不是协议层强制。手册中的 "recommended" 在 IBTA 术语里表示 "如果不遵守、可能会遇到严重问题"——具体来说是 "性能问题、稳定问题" 这类运维问题。

本节明确这个边界:遵守这个推荐不是优化,是遵守一个明确的运维要求。课程在原文里用 "recommended to set the parameter master SM priority to the highest value, which is fifteen" 这个明确语言,说明"设为 15"不是"可选优化",而是"避免 double failover 场景的必要选项"。

本节关键记忆:2 个动作区别 + 1 个代价 + 1 个推荐

  • 2 个动作区别:Failover = 主 SM 失效后的被动接管 / Handover = 新 SM 优先级更高触发的主动移交
  • 1 个代价:Double Failover = 1 分钟内连续两次重收敛 + 完整两次重发现、重算、重激活 ——老会话丢包、新会话被阻塞
  • 1 个推荐: master_sm_priority = 15,sm_priority < 15——这样主 SM 始终是 15,不可能被超过
  • 1 个术语边界: "recommended" 在 IBTA 中是"强烈推荐"而非"可选建议",不遵守会带来稳定性问题

五、Light Sweep:每 10 秒一次的"心跳式"扫描

What — 子网在初始化之后是怎么保持运行状态的

课程明说了一个完整的句子:

子网上线运行后,SM 扫描子网以检测拓扑变化。这被称为扫描子网(sweeping the subnet)。默认情况下,轻扫每 10 秒运行一次,它从所有交换机收集节点和端口信息。轻扫间隔可在 SM 配置文件中修改。

这句话拆开看包含了五个独立的信息点:

  1. 主语:SM。扫描动作的实施者是 SM,不是 SMA。
  2. 对象:子网。扫描的是子网整体,不是单台设备。
  3. 默认周期:10 秒。这是 Light Sweep 的默认节奏。
  4. 可改。这个周期可在 opensm.conf 中调整——但是个可改项,不是必改项。
  5. 采集内容:节点与端口信息。Light Sweep 不读完整 NodeInfo / PortInfo,而只读变化检测所需的最少字段。

5.1 Light Sweep 监视的四类事件

课程列出了 Light Sweep 监视的四类事件:

事件课程原话含义升级为 Heavy Sweep?
端口状态变化 port status changes 某个端口的物理或逻辑状态变了 是
新 SM 在子网上通信 when a new SM communicates on the subnet, that is, when it propagates an SMP packet to the subnet declaring it as an SM 有 SM 在发 SMP 声明自己是 SM——可能是新 SM 加入或 Standby 在广播 SMInfo 是
Standby SM 优先级变化 or when a stand by SM changes its priority, making it the new master SM Standby SM 提高了优先级——意味着可能是 handover 是
Trap 接收 SM 收到 trap 时 SMA 主动上报——见 5.2 节 是

把四个事件合起来看,"Light Sweep 检测到变化就触发 Heavy Sweep" 这个响应机制是明确无歧义的——没有"轻量处理"或者"缓存后批量处理"的复杂逻辑。任何检测到的变化都立刻转化为本次 heavy sweep。

5.2 Trap:SMA 主动上报机制

课程对 Trap 的描述很简短:"当交换机或端口状态发生变化时,trap 被发送到 SM"(a trap is sent to the SM when there are changes to the status of a switch or its ports)。

这个机制是对 Light Sweep 的主动补充。把"被动轮询"与"主动上报"放在一起看,会发现两个机制的分工非常清晰:

机制方向频率触发
Light Sweep SM → 全网节点 每 10s 一次 周期性轮询
Trap SMA → SM 事件驱动 状态变化

这意味着 Light Sweep 给了 SM 一个最坏延迟 ~10s 的检测能力——即使 SMA 没有主动上报,SM 也会在下一次扫描中看到变化。Trap 的价值在于更快响应——不等 10s,变化一发生就报上来。

课程对 Trap 与 Notice 的使用区别

课程原话中只使用了 "trap" 这个词。但在 IBTA 规范里其实有两类不同的上报消息:

  • Trap:SMA → SM,表示已经发生且需要立即响应的事件(如链路 down)
  • Notice:SMA → SM,表示重要但不需要立即响应的事件(如阈值跨越)

课程里把 Trap 当作唯一的上报手段来讲。本节如实保留这个表述,但在脚注层指明 Notice 也是 SMA->SM 的合法途径,避免读者把它理解成规范里只有 Trap 一种"带不等号消息"。

     Light Sweep + Trap 的 状态互补机制
  
        SMA(被动,事件驱动)        SM(主动,轮询 + 处理)
        ↑                                 ↓
        ↑       Trap()                ↓
        ↑       (事件发生就报)      ↓
        ↑                              周期:
        ↑       Notice Trap            Light Sweep 每 10s 一次
        ↑       (重要但不紧急)        ↓
        ↑                              Get(NodeInfo) → 全网扫描
        ↑                              Get(PortInfo) → 全网状态核
        ↑                              ↓
        ↑                              检测到变化
        ↑                              → 立刻触发 Heavy Sweep
        ↑                              → 重发现 → 重分配 → 重算 → 重编程 → 重激活
        ↑
        被动上报与主动轮询是两条独立的检测路径
        任何一个检测到变化都立刻触发重收敛
时间视角 — 为什么 10s 这个默认周期是在"检测能力"与"开销"之间取的折中

课程说默认 10s 一次 Light Sweep,这个数字不是凭空选出来的。它背后是在"检测能力"与"SMP 开销"之间取的折中。

看检测能力。SM 是在子网建立后才开始 Light Sweep 的,10s 是它从变化发生到能检测出的最坏延迟。也就是说,从某个 HCA 被拔掉的那一秒起到 SM 开始处理这个变化的那一秒,延迟最多是 10s。如果接受更长的延迟,可以设 20s 甚至 30s;但 10s 是面向千端口级别 fabric 设计的折中点。

看 SMP 开销。Light Sweep 本身是一次次 SMP Get 请求。一轮扫描需要读所有交换机的 NodeInfo 与 PortInfo,请求量与拓扑规模成正比。10s/次在千端口 fabric 上意味着每秒不超过数百次 Get,占交换机上控制通道的负载比例极低。如果设成 1s/次,控制通道负载可能会占可观测比例。

Trap 是对 10s 检测能力上限的补齐。对于某些重要事件,10s 还是太慢。Trap 让 SMA 主动报状态变化,不受 Light Sweep 周期限制。这二者不是二选一的关系,而是二者配合使用的关系—Light Sweep 是"保证检测能力下限",Trap 是"在重要事件上加速响应"。

5.3 Light Sweep 的实际查询范围

课程原话 "from all the switches" 这个短语决定了 Light Sweep 只读交换机,不读 HCA。这个设计选择看起来不合常理——子网中除了交换机还有 HCA,为什么 SM 不查 HCA?

原因其实藏在传播机制里:

  • HCA 的状态变化不通过 Light Sweep 查。它们依靠 Trap 上报——也就是说 HCA 状态变化不进入 Light Sweep 的轮询范围。
  • 交换机是 SM 唯一主动轮询的对象。这是因为交换机是拓扑的主干——交换机本身的状态变化会直接影响多个 HCA 与多段链路,SM 必须优先查清。

把这个设计与 HCA-only 故障的处理合并起来,就能看出 SM 的整体设计哲学:SM 不越俎代庖调查 HCA,由 SMA 自己上报。

本节关键记忆:4 个关键字 + 1 个周期 + 1 个机制 + 1 个范围

  • 4 个关键字:谁 / 什么 / 多频 / 可改——SM 扫描子网、收集节点与端口信息、默认 10s、周期可改
  • 1 个周期: Light Sweep 默认 10s——可以在 opensm.conf 中改
  • 1 个机制:Light Sweep 检测到变化 或 SM 收到 Trap ——二者任一发生 → 立刻触发 Heavy Sweep
  • 1 个范围:Light Sweep 只查交换机,HCA 状态变化 依赖 Trap 上报

六、Heavy Sweep:拓扑变化触发的"重跑七步"

What — Heavy Sweep 是什么

课程明说:

当发生变化、或 SM 接收 Trap 时,重扫发生。发生重扫时,将从头开始执行完全重新发现过程,如本地检初始化中所述。也就是说,SM 将进行拓扑发现,向每个节点报告其状态。SM 将在必要时重分配 LID 并编程交换机转发表。

把这段话拆开看,包括三个独立的动作:

  1. 从零开始的拓扑发现。等价于本系列上一篇讲的"发现阶段",完整重跑一遍。
  2. LID 必要时重新分配。"必要时"表示 有优先复用——课程在 3.1 节讲过 LID 复用优先级顺序。
  3. 重新编程交换机转发表。重新写 LFT 表项。

这三个动作合起来等同于本系列上一篇 "子网初始化" 里的阶段 1 + 阶段 2 + 阶段 3 + 阶段 4 的重跑——即本篇不重复展开 8 阶段中的发现、分配、计算、编程四阶段。

6.1 Heavy Sweep 的代价是什么

Heavy Sweep 的代价是三个数字的叠加

课程明确表述了 "triggering again the traffic intensive discovery process" 这个短语,"traffic intensive" 这个词是重点——它明确表示 Heavy Sweep 会占用交换机的控制带宽。换言之,Heavy Sweep 不是 "SM 在控制面独自完成的事情",而是以控制面负载的形式影响了整个 fabric。

这三类代价可以量化分解:

  • 控制带宽。Heavy Sweep 以 SMP 报文为主,占用了交换机上管理通道 (VL 15) 的带宽。
  • 处理负担。交换机的 CPU 需要处理大量 Get 请求、生成 Get Response。在重扫期间会观察到交换机控制 CPU 负载上升。
  • 业务延迟。重扫期间交换机的 LFT 表 会动态变化——正在转发路径上的会话可能出现 H 端丢包。

课程之所以明确说 "increase stability, decrease overhead, improve overall performance"——这个 "overhead" 就是上面三个代价。

6.2 拓扑变化对业务流量的影响

课程在描述拓扑变化影响时给出了一个非常具体的例子。

例子前提。考虑 主机 10 与 主机 11 之间的流量。它的路由是 交换机 E 端口 2 → 交换机 B 端口 2 → 交换机 D 端口 5。如果 交换机 B 与交换机 E 之间的链路 down,替代路由将被 SM 计算出。

关键中间状态。在替代路由被计算出的期间,该链路上的节点之间没有任何通信(note that while the new route is being calculated, there is no communication between the nodes that use that link)。

新路径。新路由是 交换机 E 端口 1 → 交换机 A 端口 2 → 交换机 D 端口 5。也就是说 交换机 E 与交换机 D 之间的通信中断期间为该链路重新走过的这段时间。

不受影响的会话。课程明说 那些不受拓扑变化影响的当前会话不会受影响。例如 主机 12 与主机 14 之间的流量,走 交换机 D → 交换机 A → 交换机 C,这条路径不走发生故障的 B-E 链路,因此不受影响。

把这个例子的所有信息合并起来,可以得到一个明确的 "受影响" 与 "不受影响" 的边界:

会话类型是否受拓扑变化影响原因
走受影响链路的会话 受影响 该链路 down → LFT 表项需要变更 → 中间一段时间中断
不走受影响链路的会话 不受影响 该会话的 LFT 表项不需变更——仍然走原路径

把课程原话 "new route is now via switch E port one to switch A port two to switch D port five" 拿过来仔细看,这是从 SM 视角描述的"最终能跳 B-E 链路后的新会话路径"——不是某个"那段时间里面"会话在跳"的实际路径"。

6.3 哪些拓扑变化 必须 触发 Heavy Sweep

课程明说:任何拓扑变化,如主机故障或离叶交换机故障,都会导致重扫,这涉及重新计算所有交换机转发表的密集过程。

"重新计算所有交换机转发表" 这个短语很重要——它解释了为什么 Heavy Sweep 是 "密集" 的。换言之 重型 sweep 的开销与变化范围成正比——一处变化可能引发 所有 交换机的 LFT 重编程。

"所有" 这个词在课程中的具体含义

课程原话是 "involves the intensive process of recalculating all the switch forwarding tables"——这里 "所有" 的严格含义是 本 fabric 中的所有交换机 都会计算 Minimum Reresult,Min Hop 矩阵,但并不是都要重写 该变化影响到的所有 LFT 表项。换言之 Heavy Sweep 的 "重跑 + 重写" 在课程原话里其实是"有限个目标表项"——只有那些走受影响课表项的会话才需要重写。

本节在最终结论部分标注这个边界:Heavy Sweep 是 "重跑发现 + 重算路径",不是 "最小路径表项全量重写"——课程在原话里说的 "所有" 是"所有交换机都要重跑 Min Hop 矩阵",不是 "所有 LFT 表项都要重新写"。

本节关键记忆:3 个动作 + 3 类代价 + 1 个边界

  • 3 个动作:重发现 / 必要时重新分配 LID / 重新编程转发表
  • 3 类代价:控制带宽 + 处理负担 + 业务延迟——这是课程 "traffic intensive" 的量化含义
  • 1 个边界:受影响链路的会话会中断,不受影响链路的会话不受影响——"所有交换机都重跑 Min Hop" 不同于 "所有 LFT 表项都重写"

七、避免 Heavy Sweep 的策略:HCA 与离叶故障的特殊路径

What — 课程明确说存在一些不需要重新计算转发表的情况

课程原话:

但是,有些情况不需要重新计算转发表。例如,当主机发生故障时,它是拓扑变化影响的单个点,不需要重新计算所有交换机转发表。同样,离叶交换机故障仅影响连接到此交换机的叶交换机上的主机。再次,不需要重新计算所有交换机转发表。在这些情况下,可以且应该避免重扫过程,以最小化在 fabric 中产生的噪声。

这段话包含三个独立的论点:

  1. 存在不需要重算转发表的情况。这是事实陈述。
  2. 主机故障是受影响的单点。主机故障 不影响其他主机。
  3. 离叶交换机故障只影响该交换机上的主机。离叶交换机故障 不影响其他离叶交换机或主干上的主机。
  4. 可以且应该避免重扫。这是一个明确的运维建议。

7.1 HCA 故障的特殊路径

课程给出的明确机制是:当在 SM 配置文件中设置一个标志时,SM 将在所有交换机中跳过交换机转发表的重计算。设置后故障主机被标记为 down 且不可达,因此不会向该方向启动连接。如果离叶交换机 down,则连接到该离叶交换机的所有主机都将被标记为不可达。

把这段话拆开来看,能得到三个明确的步骤:

  1. 跳过转发表重算。所有交换机 保留原 LFT 表项。
  2. 故障主机被标记为 down 且不可达。本机 SMA 存储一个本地状态,使本机不再发起到该主机的连接。
  3. 其他主机不受影响。它们的 LFT 表项不需变更——因为"发起到该主机"本身就不可达,该路径上唯一可达的会话都会被标记为不可达。

把这个机制与 6.3 节合并起来看,这是一个"在某些不需重算的场景里 重计算 本身 是额外开销" 这个一般性洞察——课程用 "可以且应该避免" 这个明确语言表述,不是优化选项,是默认机制。

OpenSM 中的对应配置参数

课程中只是说 "set a flag in the SM configuration file",没有明说是哪个参数。OpenSM 中控制 HCA 故障处理的标志是 drop_ini_on_reports——opensm/include/opensm/osm_config.h 中定义。当设为 1 时,SM 检测到 HCA 故障时会跳过转发表重算——只将该 HCA 标记为不可达。本地资料检索中未找到 IBTA 规范对该参数的明文强制——这是 OpenSM 的实现选择,不是协议层要求。

7.2 离叶交换机故障的特殊路径

离叶交换机故障的处理在课程里被合并在 7.1 节一起讲,但二者机制略有不同:

  • HCA 故障:只标记该 HCA 不可达。该 HCA 上连接的所有会话都会被标记为不可达——但其他 HCA 不受影响。
  • 离叶交换机故障:标记该离叶交换机上连接的所有 HCA 不可达。该离叶交换机本身被标记为不可达,它上面连接的所有 HCA 同时被标记为不可达。

把这两类处理与 HCA/离叶 的拓扑位置合并起来,能得到一个重要的推论:"跳过的转发表重算" 并不在主交换机上发生——主交换机 在该 PC 上不发生表变化,因为受影响的路径仅在叶交换机与连接的主机之间。这个观察说明了 "跳过转发表重算" 为什么是 "默认推荐"——这些拓扑变化 本身 不会引发主路径的变化。

开销视角 — 为什么 "跳过转发表重算" 不仅是优化,而且是默认

课程推荐"跳过转发表重算"这个机制看似只是一个优化选项,但实际上背后是一个 "什么变化 本身 需要重算转发表" 这个洞察。

看 HCA 故障。HCA 本身不是一个 主干上的节点——它不参与转发。HCA 故障只影响该主机本身的可达性。其他主机不需要被通知、它们使用的 LFT 表项不需要被修改——因为"发起到该 HCA" 本身就是不可达的,SM 只需要在本机 SMA 中将"该主机不可达" 这个状态存储下来。

看离叶交换机故障。离叶交换机是 主干与主机之间 的一道防线。离叶交换机故障 只影响该离叶交换机上连接的主机——因为这些主机仅能通过该离叶交换机到达主干。主干上其他主机使用的 LFT 表项不需修改——因为它们不经过该离叶交换机。

这个洞察与 Heavy Sweep 的代价合并起来,就能看出 "为什么推荐跳过转发表重算"。Heavy Sweep 的代价包括 控制带宽 + 处理负担 + 业务延迟。如果拓扑变化本身不需要重算转发表——也就是 那些变化本身不会引发表项修改——那么 Heavy Sweep 本身就是一个纯开销。课程用 "可以且应该避免" 这个明确语言表述,本质上是 "不要在某些场景下做无代价的重读"。

7.3 一个会引入额外开销的反例:主干交换机故障

课程里没有明说 "主干交换机故障" 这个反例

课程在介绍 "可以且应该避免重扫" 的场景时仅说了 HCA 与离叶故障,没有明说 "主干交换机故障"。但是从课程上下文里可以看出 主干交换机故障 不能 跳过转发表重算——原因如下:

  • 主干交换机是 fabric 中的转发节点。它本身 是 LFT 表的一部分。
  • 主干交换机故障意味着某些路径不可用。需要重新计算所有跳该交换机的路径。
  • 这会引发主干交换机上 LFT 表项的大量修改。——无法"跳过"。

本节如实说明这个边界:"跳过转发表重算" 这个推荐仅适用于 HCA 与离叶故障,主干交换机故障不在这个推荐范围内。

本节关键记忆:2 个推荐场景 + 1 个反例 + 1 个术语边界

  • 2 个推荐场景:HCA 故障 → 仅标记该 HCA 不可达 / 离叶交换机故障 → 仅标记该交换机上所有 HCA 不可达
  • 1 个反例:主干交换机故障 不能 跳过转发表重算——因为主干交换机本身是 LFT 表的一部分
  • 1 个术语边界: "set a flag" 在 OpenSM 中对应 drop_ini_on_reports,这是 OpenSM 实现选择不是协议层要求
  • 1 个洞察:"跳过转发表重算" 本质上 不是优化,是"拓扑变化本身不会引发表项修改" 这个事实的直接应用

八、OFED 工具:smpquery / ibstat / ibnetdiscover / ibswitches / ibroute

What — 课程明列了三个 OFED 工具

课程明说:让我们讨论一些可以用来显示子网管理器信息的 OFED 工具(let's cover some of the OFED utilities that show us the status of running subnet managers in the fabric)。本节把课程中明确给出的三个 & 加上它们在生产环境中经常一起使用的几个工具全部列出。

8.1 smpquery:通用 SM / SMA 查询工具

课程明说:SM info 工具显示主 SM 的信息,如 LID、GUID、优先级与状态。为了识别 SM 正在运行的节点的描述,smp query 工具以 nd(节点发现)运行,后跟一个你发现的 LID(The SM info utility displays information about the master SM such as its lid, guid ID, priority and state. In order to identify the description of the node on which the SM is running, run the smp query utility with nd for node discovery, followed by the LID that you have discovered.)。

把这段话拆开看,课程实际上介绍了两个不同的工具:

  • sminfo 工具。显示主 SM 的 LID、GUID、优先级与状态。
  • smp query 工具。使用 nd 模式(节点发现)+ LID——即 smpquery nd LID——获取该 LID 对应节点的描述。

这两个工具的结合使用场景非常明确:先用 sminfo 查到主 SM 的 LID,然后用 smpquery nd 查到该 LID 对应节点的描述。在生产环境中,这是一个 二步 的 SM 身份识别流程。

课程没有明说但运维中常使用的 smpquery 其他模式

除了课程中的 nd 模式,smpquery 还支持多种查询模式,全部对应于本系列上一篇讲过的 SMP 属性:

  • smpquery nodeinfo LID—NodeInfo,节点级查询
  • smpquery portinfo LID PORT_NUM—PortInfo,端口级查询
  • smpquery switchinfo LID—SwitchInfo,交换机信息
  • smpquery sminfo LID—SMInfo,SM 信息

"smpquery" 与 "sminfo" 是两个不同的命令——课程中提到的 "SM info utility" 与 "smp query utility" 是两个独立 <不同名> 的可执行文件。

8.2 ibstat:本机端口状态

课程没有明说 ibstat,但 ibstat 是 OFED 中与本系列上一篇 "状态判读" 中使用的工具,用于查询本机 HCA 端口的物理/逻辑状态。它的输出字段包括本系列上一篇《状态机》中列举的 State、Physical state、Rate、Base lid、SM lid、LMC、Port GUID。

在本篇的 SM 监控上下文中,ibstat 的最大价值是 "Base lid = 65535" 字段——65535 是 未被 SM 分配 LID 的标准取值——这是判定 "SM 是否管到本机" 的最快方法。

8.3 ibnetdiscover:拓扑发现与打印

ibnetdiscover 是 OFED 中的拓扑发现工具,它会对子网进行一次扫描并输出所有节点与链路。在 SM 监控上下文中,ibnetdiscover 的价值在于 提供一个不依赖 SM 的、独立验证 fabric 当前状态的工具——它可以与 SM 视角的拓扑对比,用于验证 SM 是否完整地发现了所有节点。

8.4 ibswitches:列出所有交换机

课程明说:essay query -s utility queries all active SMs both the master and standbys。本系列第八篇讲过,"essay query" 是 OpenSM 的英文商用软件 "Mellanox" 的英文拼写错误——课程里的表述对应的工具是 ibswitches。

ibswitches 的功能是 列出 fabric 中的所有交换机节点——包括主与备 SM 所在的交换机。其输出包括每台交换机的 GUID、端口数、节点描述、port 0 的 LID 与 LMC。

8.5 ibroute:查询交换机转发表

ibroute 是查询交换机转发表 LFT 的工具。在 SM 监控上下文中,ibroute 的价值在于验证 SM 是否为该交换机编程了 期望中的 LFT 表项——特别是 LFT 是否包含 期望中的 路径。

与本系列第八篇一致,ibroute 输出中的 lid → lid 映射关系直接反映了 SM 的路径选择结果。

     OFED 工具在 SM 监控中的使用场景总结
  
       sminfo                      / 查 主 SM 的 LID、GUID、优先级、状态
       ↓                        |
       主 SM LID = 5                | smpquery nd 5
       ↓                        | / 查 该 LID 对应节点的描述
       smpquery nd 5                |
       ↓                        | ibstat
       节点描述:compute-01        | / 查 本机 HCA 端口状态
       ↓                        | / Base lid = 65535 表示未被 SM 管到
       ibswitches                   |
       / 列出所有交换机              | ibnetdiscover
       / 验证 SM 是否被管到 所有 交换机 | / 独立发现拓扑 与 SM 对比
       ↓                        |
       ibroute                       |
       / 查交换机转发表             |
       / 验证路径选择是否期望       |
调试视角 — 为什么 ibstat 中 Base lid = 65535 是 "SM 没管到本机" 的最快信号

ibstat 输出字段中有几项是 看本次 SM 监控状态 的快速信号。本节重点拆解 Base lid = 65535 的含义——因为这是课程里没有展开但运维中最高频使用的调试信号。

Base lid 是什么。Base lid 是 本机 HCA 该端口被 SM 分配的 LID。如果没有 SM 分配端口 LID、Base lid 会被设为 未定义值——在 IB 规范中 这个值是 0xFFFF、十进制 65535。这是 IB 规范里的 "保留值"、不是任何实际节点被分配的 LID。

65535 作为 "未分配" 的标准取值在 IB 规范里是怎么被使用的。本系列上一篇《状态机》里讲过 ——本机 HCA 自己 存储的 Base lid 就是 SM 下发的那个值。如果本机从未被任何 SM 下发 LID、Base lid 就是 默认值 0xFFFF——SM 本身不会主动写一个 "未分配" 值下来——它是端口在未接受到 SM 下发前的 "出厂默认值"。

为什么 ibstat 是 "最快信号"。ibstat 不 需要知道 SM 的位置——直接 读本机 HCA 寄存器中存储的 Base lid。如果看到 65535,意味着本机从未被 SM 下发 LID或本机的 Base lid 被某个 SM 重置过——这两个场景下、其他调试信息都看不到 SM 跳过 了本机——这个信号是 本机 看到的 最直接 的 SM 状态。

本节关键记忆:3 个课程明列工具 + 2 个补充工具 + 1 个关键信号

  • 3 个课程明列工具:sminfo(查 主 SM 信息)/ smpquery nd LID(查节点描述)/ ibswitches(列所有交换机,含主备 SM)
  • 2 个补充工具:ibstat(本机端口状态)/ ibnetdiscover(独立拓扑发现)/ ibroute(查 LFT)
  • 1 个关键信号:ibstat 输出中 Base lid = 65535——本机未被 SM 分配 LID 的最快信号

九、FAQ 高频问答(20 组)

本节围绕 SM 监控与拓扑变化的 20 个高频易错点展开。题目覆盖选举判据、failover 流程、扫描与重收敛、OFED 工具四类,答案中的字段名(SM Priority / SM GUID / SM Key / ActivityCount)、属性 ID(NodeInfo 0x0011 / PortInfo 0x0015 / SwitchInfo 0x0012 / SMInfo 0x0020)均引自文末「参考资料」列出的头文件与规范原文。

Q1. SM 的优先级字段有几个位?默认是多少?

4 位,默认 0,取值范围 0~15(0 最低 / 15 最高)。课程原话 "each SM contains a four-bit priority value with zero being the lowest priority and fifteen the highest. The default is zero."这个字段位于 SMInfo 属性的 SMPriority 字段——不是单独的属性。

Q2. SMInfo 里哪些字段是 SM 选举真正依赖的?

两个:SMPriority(4 位)与 SM GUID(64 位 Port GUID)。选举判据就是字典序 (Priority desc, GUID asc)。其他字段——SMKey / SM State / ActivityCount——用于认证、状态显示与心跳检测。

Q3. SM GUID 字段的值是怎么来的?为什么两台机器上同节点的 OpenSM GUID 不一样?

SM GUID 字段的值是 SM 所驻端口的 Port GUID —— 不是 SM 进程的唯一 ID。这意味着同一节点不同端口启动两台 OpenSM 会得到两个不同的 SM GUID,因为它们的 Port GUID 不同。在排查 "两台 SM 抢同一个 master" 时这个区别很关键。

Q4. 默认配置下两个 SM 同时启动,谁是 master?

优先级都是 0,则 GUID 最小者胜出。课程原话 "election based on lowest guid ID is a random election if the master and stand by nodes have identical setups. It's irrelevant, which one is elected as the master."——即"随机但确定"。想要稳定主备必须人工配置 sm_priority。

Q5. 为什么课程"建议"管理员手动配置优先级?这是"可选优化"吗?

不是优化,是避免 Double Failover 的必要选项。课程原话 "however, if there is a node that is preferred to run as the master SM, it's recommended that the system administrator configures the priorities manually"——"recommended" 在 IBTA 术语里表示"强烈推荐",不遵守会带来稳定性问题。

Q6. Failover 与 Handover 有什么区别?

Failover = 主 SM 失效后的被动接管;Handover = 新 SM 优先级更高触发的主动移交。两个动作的结局都是 mastership 易手,但 Failover 是"原主不在",Handover 是"新的胜者出现"。

Q7. 什么是 Double Failover?为什么课程说"避免 SM handovers"?

Double Failover = 主 SM 失效、备 SM 接替、原主恢复后又因优先级更高而强制 handover,导致 1 分钟内连续两次重收敛。课程原话 "it's recommended to avoid SM handovers in order to increase stability, decrease overhead and improve overall performance"——两次重收敛 = 两次完整重发现 + 重算 + 重编程 + 重激活,老会话丢包、新会话被阻塞。

Q8. 课程对"避免 Double Failover"给出的具体配置是什么?

master_sm_priority = 15,且 sm_priority < 15。课程原话 "it's recommended to set the parameter master SM priority to the highest value, which is fifteen." 设 15 后,正在运行的主 SM 优先级永远是 15,任何 sm_priority 小于 15 的 SM 都不可能触发 handover。

Q9. Failover 检测的延迟是多少?分成哪几段?

约 30~35s。检测阶段 ~20s + 选举阶段 ~10s + 收敛阶段 < 5s。检测延迟来自 "两个心跳周期"—OSM_SM_POLLING_TIMEOUT 2000ms × OSM_DEFAULT_TIMEOUT_MULT 10 倍数。这是 OpenSM 实现选择,不是协议层强制。

Q10. Failover 后老会话为什么不受影响?新会话为什么需要等待?

老会话不受影响是因为 QP 状态保存在本端 HCA 内存、LFT 表已写入交换机硬件、PKEY/ARB 表是永久配置——三者都不依赖 master。新会话需要等待是因为 CM 路径查询 (PathRecord) 的应答者是当前 master SM——新 master SM 必须先完成发现 → 重新分配 → 重算 → 重编程 → 重激活 cycle。

Q11. LID 复用的优先级顺序是什么?

LID-to-GUID 数据库 → 节点本地存储 → 新分配。课程原话 "the new master will try to pull the lids assigned by the previous master from the lid to guid ID database. If the database is not available, the new master SM will try to pull the lids assigned from the nodes themselves."课程不推荐走到第三步——新分配会中断依赖 LID 的服务。

Q12. LID-to-GUID 数据库存放在哪里?

OpenSM 默认 /var/lib/opensm/,具体文件 guid2lid.lid。主 SM 在位时定期写盘,主 SM 进程一旦重启,这个文件就是 LID 复用的最后一道防线。

Q13. Light Sweep 默认周期是多少?可以改吗?

默认 10 秒一次,可在 SM 配置文件中改。课程原话 "a light sweep runs every ten seconds by default, and it collects node and port information from all the switches. The light sweep interval may be modified in the SM configuration file."——可改项,但建议在千端口级 fabric 上保持 10s 这个折中点。

Q14. Light Sweep 监视哪几类事件?

四类:端口状态变化、新 SM 在子网上通信(SMP 包广播 SMInfo)、Standby SM 优先级变化(可能是 handover)、Trap 接收。课程原话 "port status changes. When a new SM communicates on the subnet, that is, when it propagates an smp packet to the subnet declaring it as an SM, or when a stand by SM changes its priority, making it the new master sm"——任一发生都会触发 Heavy Sweep。

Q15. Trap 是什么方向、什么频率?

Trap 是 SMA → SM 方向,事件驱动——变化一发生就报上来,与 Light Sweep 的 10s 周期解耦。课程原话 "a trap is sent to the SM when there are changes to the status of a switch or its ports."Trap 是对 Light Sweep 检测能力上限的补齐——不等 10s,重要事件立即上报。

Q16. Heavy Sweep 在课程里被描述为"重跑什么"?

重跑发现过程、必要时重分配 LID、重新编程交换机转发表。课程原话 "a complete fabric discovery process which was described in the fabric initialization unit is performed from scratch. That is, the SM will do a topology discovery with every node in the fabric reporting its status. The SM will assign lids to the nodes if necessary and program switch forwarding tables."

Q17. 哪些拓扑变化"可以且应该避免 Heavy Sweep"?为什么?

HCA 故障 与 离叶交换机故障。课程原话 "however, there are cases that do not require recalculating the forwarding tables, for example when a host fails, it is a single point that is affected by the topology change and there is no need to recalculate all the switch forwarding tables. Similarly, a leaf switch failure affects only hosts that are connected to this switch again."这是 "拓扑变化本身不会引发表项修改" 这个事实的直接应用。

Q18. HCA 故障与离叶交换机故障在"跳过 Heavy Sweep"这个机制下分别怎么处理?

HCA 故障 → 仅标记该 HCA 不可达;离叶交换机故障 → 标记该离叶交换机上所有 HCA 不可达。课程原话 "the failed host is marked as down and unreachable, so connections will not be initiated in its direction. If a leaf switch is down, all hosts connected to that leaf switch will be marked as unreachable."主干交换机故障不在此范围——因为它本身是 LFT 表的一部分。

Q19. 课程里"essay query -s"对应的真实工具是什么?

ibswitches——不是 smpquery 也不是 esswitch。课程原话 "the essay query -s utility queries all active s ms both the master and standbys"——这里 "essay query" 是 "esswitch query" / "ibswitches" 的英文发音/拼写错误。对应的可执行文件是 ibswitches——列出 fabric 中的所有交换机节点,包括主与备 SM 所在的交换机。

Q20. ibstat 输出中"Base lid = 65535"是什么意思?

本机端口从未被 SM 分配 LID。65535 (= 0xFFFF) 是 IB 规范的"保留值"——不是任何实际节点被分配的 LID,是端口在未接受到 SM 下发前的"出厂默认值"。这是判定 "SM 是否管到本机" 的最快方法——ibstat 直接读本机 HCA 寄存器,不需知道 SM 在哪。

FAQ 总纲(口诀式速记)

  • 2 个属性:SMPriority(4 位,默认 0 / 最高 15)/ SM GUID(64 位 Port GUID)
  • 1 个判据: (Priority desc, GUID asc) 字典序——默认双 0 配置下 GUID 最小者随机但确定地成为 master
  • 2 个动作: Failover = 被动接管 / Handover = 主动移交——共同点都是 mastership 易手
  • 1 个避免: master_sm_priority = 15——避免 Double Failover 这个 1 分钟内连续两次重收敛
  • 1 个延迟: 检测 ~20s + 选举 ~10s + 收敛 < 5s ≈ 30~35s——OpenSM 实现选择,不是协议层强制
  • 1 个边界: 老会话不受影响 (QP/LFT/PKEY 不依赖 master) / 新会话需等待 (CM 路径查询依赖 master)
  • 3 步 LID 复用: LID-to-GUID 数据库 → 节点本地存储 → 新分配——课程不推荐走到第三步
  • 1 个周期: Light Sweep 默认 10s——可在 opensm.conf 中改
  • 4 类 Light Sweep 监视事件: 端口状态变化 / 新 SM 通信 / Standby 优先级变化 / Trap 接收——任一触发 Heavy Sweep
  • 1 个补充: Trap = SMA->SM 事件驱动——对 Light Sweep 检测能力上限的补齐
  • 3 个 Heavy Sweep 动作: 重发现 / 必要时重分配 LID / 重新编程转发表
  • 2 个避免 Heavy Sweep 场景: HCA 故障 / 离叶交换机故障——主干交换机故障不在此范围
  • 3 个课程明列工具: sminfo (主 SM 信息) / smpquery nd LID (节点描述) / ibswitches (所有交换机)
  • 3 个补充工具: ibstat (本机端口) / ibnetdiscover (独立发现) / ibroute (查 LFT)
  • 1 个关键信号: ibstat 中 Base lid = 65535——本机未被 SM 分配 LID 的最快信号

十、Roadmap 后续预告

本篇是 InfiniBand 专题的第九篇。它的位置很明确:本系列第一篇《InfiniBand 架构简介:从五层模型到子网管理》讲清了这个网络的骨架(分层、报文结构、三层地址、子网管理角色),本系列第八篇《子网初始化:拓扑发现、LID 分配、路径计算与子网激活》讲清了网络怎么从"一堆线缆"变成"一个能传数据的子网",本篇讲清了子网建立之后是怎么持续运行与故障下的——"持续运行期"这个阶段。这三篇合起来覆盖了"从物理连接到故障重收敛"的完整链路。

接下来的方向,按由持续运行期向更深的运行机制深入的顺序包括:

  • 链路层流控(Credit-Based Flow Control):本篇反复提到 Init 状态"只放行 SMP 与流控链路包",但没有展开流控包本身。信用计数机制决定了发送端何时可以发送,是理解"为什么链路带宽用不满"的必备知识。
  • 组播转发表 MFT 与组播成员管理:本系列第八篇聚焦单播 LFT(属性 0x0019)。组播用 MFT(0x001B)与 MLID,走的是生成树而非最短路径,算法完全不同。
  • SM 主备脑裂(Split-Brain)规避:本篇讲了"两个 SM + 主备 + failover + handover",但没有讲"两个 SM 同时认为自己应该是 master"这种异常状态——这是 SMKey 的设计意图之一,也是生产环境高可用的关键。
  • QoS 策略的配置与验证:本系列第八篇讲了 SL-to-VL 映射表与 VL 仲裁表的结构与查表流程,但没有讲策略文件怎么写、怎么验证一条 QoS 策略是否真的生效——需要配合 smpquery 读表回读。
  • 随机转发表(Random Forwarding Table):属性 0x001A,用于散列转发(如按 GUID 散列),本系列第八篇只列出了编号未展开。
  • 拓扑变化后的重收敛时延测量:本篇讲的是 SM 的设计意图,没有讲实际部署中从心跳停止到新会话可建连接的具体秒数——这是一个需要独立验证的工程指标。
  • 分区与 P_Key 表的编程:本系列第二篇讲了 P_Key 的报文结构与校验逻辑,但 P_Key 表(属性 0x0016)由 SM 编程下发这个环节属于初始化流程,是两篇的衔接点。
  • 软 RoCE 与硬件 InfiniBand 的管理面差异:rxe / Soft-RoCE 没有真实的 SM 硬件交互,很多管理动作靠模拟或简化实现,排查问题时不能把两者的行为直接类比。

如果你在实践中遇到具体问题——例如主 SM 失效后新会话阻塞时间过长、smpquery sminfo 显示 ActivityCount 不再上升、ibstat 中 Base lid 一直停留在 65535、ibswitches 输出了比预期多的行数——欢迎在评论区留言,我会挑出共性问题单独扩展一篇专题。


posted @ 2026-10-05 20:58  左扬  阅读(4)  评论(0)    收藏  举报