第四章 最佳主时钟算法(BMCA)
说实话,我刚开始搞时钟同步那会儿,觉得 BMCA 挺神秘的。后来自己调了几个项目,发现说白了它就是一套“选老大”的规则——所有节点坐下来比比谁更靠谱,然后大家跟着它走。本章我把原理、选举流程、状态机拆开讲,你跟着走一遍,基本就能上手了。
4.1 为什么要选主时钟?
IEEE 1588 的域模型里,不可能每个设备都当“主”。你想想看,如果每个节点都发同步报文,网络就乱套了。所以必须有一个 最佳主时钟(Grandmaster, GM) 来统领全局。BMCA 就是干这个的——它运行在每个端口上,通过比较自身和邻居的 数据集,决定谁当主、谁当从。
我的经验: 有一次在工厂调试,某个交换机的优先级设得太低,结果一个普通设备当了 GM,整个同步精度掉了好几个微秒。后来我养成习惯——关键链路节点手动指定高优先级,避免 BMCA 选错。
4.2 选举过程:比什么?怎么比?
BMCA 的选举说白了就三步:收集 → 比较 → 决策。每个端口周期性发送 Announce 报文,里面带着源端口的数据集。收到 Announce 后,本端口把自己和对方的数据逐项比较。比较顺序如下:
- 优先级 1(priority1):数值越小优先级越高。管理员可以手动配,范围 0–255。
- 时钟 Class(clockClass):表示时钟的质量等级。比如原子钟 Class 低(好),普通晶振 Class 高(差)。
- 时钟 Accuracy(clockAccuracy):偏差指标,越小越准。
- 时钟 Variance(offsetScaledLogVariance):抖动指标,越小越好。
- 端口号(portIdentity.portNumber):如果前面全部一样,端口号小的胜出。
比较是逐级进行的——只要某一项分出高低,后面就不比了。听起来是不是跟体育比赛积分榜有点像?
| 比较项 | 说明 | 推荐设置 |
|---|---|---|
| priority1 | 用户可配,0 最高 | GM 设为 128,普通设备 255 |
| clockClass | 6–248,越小质量越好 | 原子钟 6,TCXO 52,OCXO 45 |
| clockAccuracy | 0x00–0xFF,0xFE 表示未知 | GPS 授时 0x21,网口同步 0xFE |
| offsetScaledLogVariance | 数值越小越稳定 | 典型值 0x4E5D(约 0.1ns) |
| portIdentity.portNumber | 设备内端口号,唯一 | 硬件自动分配 |
核心口诀: “先看 priority1,再看 Class,然后 Accuracy,接着 Variance,最后拼端口”——我们团队内部都这么记。
4.3 BMCA 状态机:节点到底在干嘛?
BMCA 给每个端口定义了若干状态。我记得第一次看状态机图时一脸懵,后来发现只要理解三个核心状态就够了:
- MASTER:我是老大,我来发同步报文。
- SLAVE:我跟你同步,我收报文、做跟随、调本地时钟。
- PASSIVE:我不当主也不当从,但监听 Announce,随时准备切换。
除此之外还有 LISTENING(初始/重启后等待)、PRE_MASTER(刚当选主但还没开始发报文,先做个自我检查)。完整状态迁移如下图:
4.4 状态迁移的典型场景
光看状态图你可能觉得抽象,我举几个实际工作中的例子:
- 上电启动:所有端口进入 LISTENING,等待 2–3 个 Announce 周期(默认 2–3 秒)。如果没收到任何 Announce,该端口自己就成为 MASTER——这就是为什么普通交换机上电后也会发 Sync。
- 主时钟掉线:SLAVE 端口连续收不到 Sync,超时后回到 LISTENING,重新参与选举。这时如果其他设备更优,可能选出一个新 GM。
- 人工干预:我曾经在一个测试中把 GM 的 priority1 改成 1(比原来低),结果其他节点立刻检测到,整个网络 2 秒内完成主时钟切换——BMCA 没有你想象的那么慢。
注意: 不要频繁调整 priority1 或硬重启 GM 节点。我曾经见过有人批量修改配置后,设备同时进入 LISTENING 和 PRE_MASTER 震荡,花了 30 秒才收敛。如果你需要热切换,建议通过 Announce 间隔 和 priority2 来做软切换。
4.5 BMCA 的“避坑”指南
我结合自己踩过的坑,列几个要点:
- Announce 超时设置别太短。 默认 3 倍 Announce 周期(比如 2s × 3 = 6s)。太短会导致误判,太长切换延迟大。建议对网络稳定的场景保留默认,无线或卫星跳变场景可以适当延长。
- Priority 不要都设成 128。 所有设备 priority1=128 时,BMCA 会继续比拼 clockClass。如果 clockClass 也一样,就拼 Accuracy……最后可能因为端口号不同选出个意料之外的 GM。建议至少把“预期 GM”的 priority1 设成 127 或更低。
- 边界时钟和透明时钟的 BMCA 行为不同。 普通端口的 BMCA 是全功能;但透明时钟(TC)默认不参与选举,只转发 Announce。我们组有一次差点把 TC 的端口也配成 BC,导致 BMCA 选出了两个 GM。记住:TC 不能主动当 GM。
总结: BMCA 不是什么玄学。你只要抓住“逐级比较 → 状态机 → 收敛时间”这个链路,就能看懂任何日志。我习惯在调试时先用
ethtool -P 确认端口,再用 ptpd --show-dataset 看 Announce 内容——直接对比就能判断 BMCA 决策是否合理。