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

第七编|SPP、图像 Tile 与部分成功

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

系统仿真SPPTile图像处理

48. SPP 是什么

SPP(Satellite Processing Protocol,卫星处理协议)是本项目为图像 Tile 定义的业务层 二进制协议。它不是 IPv6 扩展头,不是 SRH,也不是控制面消息。

各层关系是:

Ethernet
└── IPv6
    └── SRH
        └── UDP或项目承载
            └── SPP header
                └── RGB/Gray/Edge payload

IPv6/SRH 负责“包经过哪里”,SPP 负责“包里面是哪一个任务、对象、Tile 和图像格式”。算子只在验证外层边界后读取 SPP。

49. 为什么不直接发送一整张图片

把图片切成 Tile 有四个好处:

  1. 单包大小受 MTU 约束,Tile 便于控制包长;
  2. 不同 Tile 可流水并行,而不必等整张图;
  3. 丢失影响可局部量化;
  4. 算子可按 Tile 或邻域逐步产生输出。

代价是系统必须显式管理对象身份、Tile 坐标、epoch 和不完整窗口。SPP 正是为这些语义提供共同契约。

50. SPP 64-byte 固定头

当前头长固定为 64 byte。多字节整数按网络字节序编码。

图 1 SPP 64 byte 固定头的字段布局(每行 8 byte,网络字节序)

图 1 SPP 64 byte 固定头的字段布局(每行 8 byte,网络字节序)

字节偏移字段长度含义
0magic4固定魔数,用于识别 SPP
4version1协议版本
5header_length1头长度,当前为 64
6dimensions1维度信息
7payload_format1RGB24、GRAY8 或 EDGE1
8flags2标志位
10payload_length2SPP 负载字节数
12task_id8任务身份,必须非零
20object_id8对象身份,必须非零
28tile_id8Tile 的 Morton 编码
36original_width4原对象宽度
40original_height4原对象高度
44tile_width2当前 Tile 宽度
46tile_height2当前 Tile 高度
48grid_columns2Tile 网格列数
50grid_rows2Tile 网格行数
52object_epoch4同一 object 的新版本序号
56reserved8保留,供协议演进

接收者必须先验证 magic、version、header length、payload length 与实际帧边界,再访问后续字段。不能因为以太网帧“看起来够长”就假定里面一定是合法 SPP。

51. 三个身份字段不能相互替代

51.1 task_id

表示这份数据属于哪一次计算编排。相同图片同时进入两个不同 DAG 时,task_id 不同,缓存也必须分开。

51.2 object_id

表示任务内的哪一个逻辑对象,例如第 42 张图。一个 task 可连续处理许多 object。

51.3 object_epoch

表示同一个 object 的哪一版。对象被重新采集、重传或更新时 epoch 增加。旧 epoch 迟到,不能污染新 epoch 的窗口。

因此正确缓存键是:

(task_id, object_id, object_epoch)

只用 task 会把整条业务的所有图片混在一起;只用 object 会把不同任务和版本混在一起;用五元组也不够,因为路径变化后五元组可能变化,而业务身份没有变化。

52. Morton 编码

Morton Code(莫顿码,又称 Z-order curve,Z 序曲线)把二维坐标的二进制位交错成一个 整数,使空间相近的 Tile 通常仍有接近的编号。

若 x 和 y 的低位分别为:

x = ... x2 x1 x0
y = ... y2 y1 y0

则 Morton 码交错为:

... y2 x2 y1 x1 y0 x0

例如 x=2 即二进制 10,y=1 即 01:

x位:x1=1, x0=0
y位:y1=0, y0=1
交错:y1 x1 y0 x0 = 0 1 1 0 = 6

算子不能把 tile_id+1 简单理解成“右边一块”。必须先 Morton decode(解码)得到 (x,y),检查 grid_columns/grid_rows,再计算邻域。

53. 包、Tile、窗口和任务不是同一个成功单位

这四层需要分别计数:

  • 包成功:某个网络包到达下一处理点;
  • Tile 成功:某个 Tile 完成要求的算子链并到达目的端;
  • 对象窗口完整:某个有状态算子收到其计算所需的 Tile 集合;
  • 任务结果:任务观察期内所有预期 Tile 的完成比例。

若预期 100 个 Tile,最终有 90 个完成,则该任务是 90% 成功,不是“任务失败”。公式为:

task_success_ratio = completed_expected_tiles / total_expected_tiles

只有协议或实验定义明确要求 all-or-nothing(全有或全无)时,才可把任一 Tile 丢失折算成整个task 失败。本项目对 SPP 采用可量化的部分成功语义。

这也解释了为什么“不完整窗口被丢弃”是局部损失证据,而不是自动宣判整条任务为 0。

54. SPP 与 Anycast 的根本张力

无状态算子使用 Anycast 很自然:每个 Tile 无论落到哪个同类型实例,都得到相同结果。

有状态算子不同。假设一个 2×2 group 的四个 Tile 经逻辑 Anycast 服务转发:

tile A、B → Mean@node-20
tile C、D → Mean@node-44

两个实例都只看见半个 group,都会等待并最终超时。网络没有丢包,但应用状态被拆散了。这不是“Anycast 把一个包复制到五个容器”,而是不同包在不同时刻根据当时 FIB 选择了不同provider。

可以引入会话粘性、共享状态或一致性哈希,但这些都形成新的系统机制和研究问题。当前不应为了某个测试结果临时写“同 task 永远绑死某节点”的补丁。教材中的正确结论是:

  • SPP 可以与 Exact 或 Resilient 结合;
  • 有状态算子在 provider 漂移时天然可能产生窗口损失;
  • 该损失按 Tile 完成比例计入可靠性;
  • 更高层的状态安置理论留给后续研究;
  • 观测必须保留完整身份,才能量化损失来自何处。

< 返回技术专栏