从 IP 到 SRv6 计算编排 · 第六编

第六编|Anycast 从逻辑服务选择实例

2026-08-20 · COMPIN Lab · 阅读约 6 分钟

系统仿真AnycastFIB弹性路由

前五编已经建立普通 IPv6 FIB、逻辑/具体 SID、任务和算子实例。本编才第一次系统学习服务选择:先从普通路由理解“多个实例共享一个逻辑地址”,再观察 provider 怎样自然变化。第七编随后加入跨包状态,说明漂移的代价;第九编最后学习更复杂的全链联合选择。这样不会用尚未定义的图片窗口或调度公式反过来解释 Anycast。

40. 先从 Unicast、Multicast 和 Anycast 的区别开始

学习 Anycast 以前先比较三种交付方式:

方式中文一个包交给谁
Unicast单播一个明确地址对应的一个目的
Multicast组播加入同一组的一组接收者
Anycast任播多个实例共享一个地址,路由选择其中一个

Anycast 不会把同一个包复制给所有 provider。它仍是一条普通 IPv6 /128 路由,只是多个位置都能提供这个逻辑目的。哪一个实例收到包,由当前节点的 FIB 和下一跳决定。

41. 为什么计算服务需要逻辑地址

第五编已经区分 operator type(算子类型)与 operator instance(算子实例)。若调用者写:

fd42:3:14::100

它明确要求 node-20 上的 Gray,节点 20 不可达时这个地址不会自动变成 node-38。若调用者只要求“某个可达 Gray”,则使用逻辑服务 SID:

fd42:7::100

因此:

具体SID = 功能 + 物理实例位置
逻辑Anycast SID = 只有功能身份,位置交给路由选择

当前节点本地 Anycast FIB 覆盖五种图像服务:BNN Fire Filter、Gray、Tile Mean 2×2、Tile Blur 3×3 和 Edge。Fire Mask 与 Binary Fire Mask 仍有具体实例能力,但不属于当前Issue 243 逻辑 Anycast 图像链,不能仅凭“统一镜像里有七类算子”就虚构其 Anycast route。

42. Provider 事实从哪里来

Provider(提供者)是当前真实运行某个算子实例的网络节点。节点启动自己的算子以后, 把 operator bitmap、进程 instance、resource sequence 和 lifetime 作为事实上报。控制器只汇总这些节点事实,再把同一份资源视图传播给网络节点。

每个节点本地计算 Anycast 路由时只使用自己已经接收并应用的:

confirmed topology graph
+ operator provider bitmap
+ 本地HELLO观察到的直接邻居可用性

配置文件声称某节点“应该有 Gray”不等于该实例当前可用;事实过期、进程重启或节点不可达都必须自然改变候选集。控制器不进入容器探测,也不替节点选 provider。

43. 每个节点怎样计算 Primary 和 Backup

scripts/anycast_fib.py 从观察节点对当前双向图执行 BFS,为每个 provider 寻找经不同本地first hop 可达的确定性路径。候选按以下规则排序:

图 1 节点本地计算 Primary / Backup:hop 数最少者为 primary,backup 必须来自另一个 provider,并尽量换一个 first hop

图 1 节点本地计算 Primary / Backup:hop 数最少者为 primary,backup 必须来自另一个 provider,并尽量换一个 first hop

  1. primary 先选 hop 数最少者;
  2. hop 数相同按 provider node ID 和完整 path 稳定排序;
  3. backup 必须来自另一个 provider;
  4. 有条件时优先选择与 primary 不同的 first hop;
  5. 其余 provider 继续保留为有序候选。

“不同 provider”避免把同一实例的另一条等价路径误称为实例冗余;“尽量不同 first hop”让直接邻居故障时更可能立即切换。它是一条通用、确定性的路由规则,不读取当前有哪些 task,更不按某次业务结果安排答案。

44. 逻辑服务怎样安装进 Linux FIB

每个逻辑 service SID 都有稳定的 Linux nexthop object 和一条普通 IPv6 /128 路由。初始化时nexthop 先指向 blackhole(黑洞),表示尚无合法 provider;节点得到事实后用一次 iproute2 batch 替换对应 nexthop:

远端provider:via fe80::<next-hop> dev 数据接口
本地provider:via 算子namespace网关 dev 本地算子veth
无provider:blackhole

路由本身保持稳定,活动 nexthop 对象改变。直接 HELLO 发现 primary first hop down 时,节点可从预计算候选中立即选择 backup,不等待控制器生成一份“正确答案”;之后的新全局拓扑再重建完整候选集。

45. Resilient 任务怎样使用 Anycast

Resilient Placement(弹性放置)把 DAG 中的算子类型编译成逻辑 SID 链。例如:

逻辑Gray SID → 逻辑Mean SID → 逻辑Edge SID → 最终交付SID

入口安装 task SR Policy 时不运行 HEFT,也不选择 node-20 或 node-38。包到达某个逻辑 SID 时,该位置的普通 IPv6 FIB 选择当前 provider。拓扑或实例变化只替换逻辑服务 nexthop,task_id、Color 和 SRH 服务顺序保持稳定。

这就是 routing-based placement(基于路由的放置):每项服务在到达时做局部路由选择。它与第九编的 HEFT 全链联合编排是两种不同模型,不能因为最终都得到某个 provider,就把Resilient 选择称为 HEFT 结果。

46. Provider 漂移为什么是自然现象

假设 node-17 当前到 Gray 的排序为:

primary = Gray@20, first hop 18
backup  = Gray@38, first hop 44

当 17 实际收不到 18 的 HELLO/ACK,或 Gray@20 事实过期,FIB 自然改选 Gray@38。已经发出的旧包可能到 20,新包到 38;没有任何组件把一个包复制给两个容器。

这种变化叫Provider Drift(提供者漂移)。对单包无状态算子,两个合规实例给出相同算法结果,漂移通常只造成路径变化。对需要跨包缓存的有状态算子,不同包落到不同实例会拆散窗口。第七编在定义 SPP 对象和 Tile 以后再精确解释这种损失,当前只保留因果链:

拓扑/实例事实变化 → 各节点本地FIB变化 → 后续包选择变化

47. Anycast 应该记录和展示哪些事实

节点对每个逻辑服务记录:

  • anycast_route_selected:从无路由变成选中 provider;
  • anycast_route_changed:活动 provider 或 first hop 变化;
  • anycast_route_withdrawn:没有合法 provider;
  • anycast_candidates_changed:活动转发身份未变,但主 provider/下一跳或备provider/下一跳发生变化;
  • service SID、operator、primary、backup、candidate count 和 topology generation;
  • 受影响 Resilient task 的稳定 nexthop 是否重新绑定。

第三顺位以后的候选路径仍由每个节点持续计算,并保存在 latest-only 状态中。它们没有改变当前内核 FIB,也没有改变立即可用的主备转发前沿,因此不为每次路径重算写一条永久事件。减少的是可重建的派生转录,不是资源、拓扑、故障或业务事实。

前端只能把这些真实 FIB 事件画成 Anycast 漂移,不能根据两颗卫星在画面上的距离猜 provider。排错时先问“该观察节点当时有哪些已应用 provider 事实和路径”,不能从目的端结果倒推出一条人为粘性规则。

47.1 第六编自测

  1. Anycast 与 Multicast 的核心差别是什么?
  2. fd42:3:14::100 和 fd42:7::100 分别表达什么?
  3. 为什么每个节点会算出自己的 Anycast FIB,而不是控制器下发一个全网 provider?
  4. backup 为什么要求另一个 provider 并尽量使用不同 first hop?
  5. provider 变化为什么不需要替换 Resilient task 的 SRH?
  6. 同一个包会不会因为 Anycast 被复制给五个容器?

< 返回技术专栏