简介:UEC协议1.0版本是Ultra Ethernet Consortium于2025年6月11日发布的Ultra Ethernet Specification v1.0,面向数据中心网络、高性能计算及高速以太网研发人员,用于了解Linux Foundation框架下UEC推动的现代计算环境以太网标准。资源包为1个PDF文件,约14.55MB,正文涵盖引言、背景及UEC批准交付内容,并附CC BY-ND 4.0许可与“AS IS”免责声明,适合协议研读、方案设计与术语对照。已有250人学习,可作为理解UEC规范边界的参考;使用时需遵守开放许可限制,并留意OCR可能造成的个别文字偏差。
1. UEC 1.0:为什么高性能以太网要重新发明传输层
2025 年 6 月 11 日,UEC 1.0 规范正式定稿。很多人第一反应是“又一个以太网标准”,但翻完目录会发现一个反直觉的事实:这份文档真正重的部分不是物理层,也不是链路层,而是传输层——它把 1.0 版本近一半的篇幅压在 UET(UE Transport)的语义子层、包投递子层和拥塞管理子层上。原因很直接:AI 训练和 HPC 的瓶颈早已不在链路带宽,而在传输语义。传统以太网加上 TCP 的那套可靠传输,在高扇入、微突发的 AI 集群里会撞上拥塞控制和重传放大的墙。UEC 想做的事情,是给以太网换一颗为 AI/HPC 定制的“传输心脏”。搞懂它,你就搞懂了下一代大规模集群网络到底在优化什么。
1.1 从分层总览看 UEC 的野心边界
规范第 1.6 节给出了一个五层视图:软件层、传输层、网络层、链路层、物理层。有意思的是它的篇幅分配————物理层只占一页多的概述,链路层也相对克制,而传输层从第 122 页一直铺到几百页。这种“头重脚轻”不是写得偏,而是设计意图:UEC 认为以太网的 PHY 和 MAC 已经足够成熟,真正需要标准化的是上层软件怎么调用、传输层怎么保证语义、拥塞怎么管。
五层里,软件层是 UEC 区别于传统 RDMA 生态的一个关键切口。它没有直接规定一套全新 API,而是在 2.2 节把 UET 映射到 libfabric 上,定义了 UET Profile、JobID、传输与接收队列、安全协议、线缆协议映射,甚至给了 Linux 下 UET Control API 的实现约定。换句话说,应用不需要重写,verb 层之下换了一套传输。
传输层内部又被切成四个子层:
| 子层 | 全称 | 职责 |
|---|---|---|
| SES | Semantic Sublayer | 事务语义、内存模型、缓冲区寻址 |
| PDS | Packet Delivery Sublayer | 可靠投递、排序、包格式、状态机 |
| CMS | Congestion Management Sublayer | 拥塞控制算法与信号 |
| TSS | Transport Security Sublayer | 传输安全 |
这四个子层的划分,是理解整份规范的主轴。SES 管“这次操作意味着什么”,PDS 管“这些包怎么可靠送到”,CMS 管“送太快了怎么办”,TSS 管“谁能送”。分层的好处是每一层可以独立演进,比如 CMS 的算法可以换,而 SES 的语义不变。
1.2 系统视图:UEC 把集群拆成了哪些角色
1.3 节的系统视图和命名法值得单独看一眼,因为它决定了后面所有机制的适用范围。规范里区分了工作负载(Workloads,明确标注为 Informative)、fabric 端点软件栈、交换机软件栈、NOS 接口。工作负载部分只作信息性说明,说明 UEC 不打算规定 AI 训练具体怎么跑,只规定网络怎么服务它。
fabric 端点软件栈对应主机侧,交换机软件栈对应网络侧,NOS 接口则是给网络操作系统留的钩子。这个划分暗示了一件事:UEC 的传输语义是端到端的,但拥塞管理需要交换机配合,所以交换机侧也要有标准化接口。后面 CMS 子层能成立,前提就是交换机愿意暴露拥塞信号。
1.3 传输层的三个目标决定了后面所有取舍
1.5.2 节明确写了 UET 的目标。虽然没有逐字列出,但从后文能反推出三条主线:一是支持大规模、高扇入的 AI/HPC 流量模式;二是把可靠性和排序做成可配置而非一刀切;三是让拥塞控制能感知端点而非只靠丢包。
这三条目标直接解释了为什么 PDS 要有多种投递模式、为什么 SES 要有自己的内存模型、为什么 CMS 要独立成子层。后面每一章讲机制时,我都会回到这三个目标上对账——如果一个设计看起来奇怪,多半是为了其中某一条。
2. 语义子层 SES:内存模型和缓冲区寻址为什么不能照搬 RDMA
SES 是 UET 里最“不像网络”的部分,它关心的是内存怎么被描述、事务怎么被定义、错误怎么被表达。很多人第一次读会觉得这是 RDMA 的翻版,但细看会发现几个关键差异,而这些差异恰恰是 UEC 敢说自己为 AI 优化的底气。
2.1 语义概念的定义方式:先定事务,再定头部
3.4.1 节“语义概念的定义”是整份规范里最像“语言规范”的一节。它没有先给包格式,而是先定义语义概念:什么是事务、什么是缓冲区、什么是授权、什么是缓冲区行为。3.4.2 节才给语义头部格式,3.4.3 节讲语义处理,3.4.4 节讲协议序列。
这种“先语义后编码”的顺序不是文风问题,而是设计约束。因为 UEC 希望语义层能映射到不同的底层投递能力上——PDS 有不同投递模式,SES 的语义不能绑死在一种包格式上。所以语义头部里放的是操作码、缓冲区标识、长度这类逻辑字段,具体怎么切包、怎么排序,交给 PDS。
3.4.8 节的“UE Transport Semantics: Memory Model”值得单独提。内存模型规定了什么样的读写顺序是允许的、什么样的可见性是保证的。这在 AI 集群里很关键:一个 all-reduce 里不同 rank 的写入顺序如果语义不明确,上层算法就没法保证正确性。UEC 把内存模型写进规范,等于给上层框架一个可依赖的契约。
常见的实现思路是,SES 的事务模型会区分单向写、单向读、双边 send/recv 这几类,每类的完成语义和排序保证不同。3.4.9 节还专门给了 CCL(集合通信库)send/recv 到这套语义的映射说明,虽然标注为 Informative,但能看出 UEC 在设计时就是盯着集合通信的真实模式去的。
2.2 缓冲区寻址与授权的分离
3.3.2 节“Buffer Addressing Mechanisms”和 3.3.3 节“Authorization”是相邻的两节,这个顺序有讲究。缓冲区寻址解决“对哪块内存操作”,授权解决“凭什么允许你操作”。RDMA 体系里这两件事通常绑在 QP 和 MR 上,UEC 把它们拆开描述,意味着寻址机制和授权机制可以独立组合。
为什么这么设计?因为 AI 集群的典型场景是大量节点反复对少量缓冲区做集合通信。如果每次通信都要重建授权,开销不可接受;但如果授权太粗,又会有安全问题。把寻址和授权解耦,就可以做“一次授权、多次寻址”或者“按 JobID 批量授权”。2.2.4 节的 JobID 概念在这里呼应上了——JobID 是软件层给一次作业的标识,传输层可以拿它做授权粒度。
2.3 语义处理与协议序列:状态机在哪里
3.4.3 节“Semantic Processing”和 3.4.4 节“Semantic Protocol Sequences”是 SES 的执行部分。前者讲收到一个语义操作后怎么处理,后者讲多步操作的时序。规范在这里没有用大段伪代码,而是用状态和序列描述,因为 SES 要适配不同的硬件实现。
我一般会这么理解:SES 的处理逻辑核心是“收到请求 → 校验授权与缓冲区 → 执行 → 产生完成事件或错误”。协议序列则处理需要多步的场景,比如带确认的写、需要保序的读。3.4.5 节的错误处理定义了错误如何表达和传播,这对大规模集群很重要——一个节点的错误不能静默,也不能把整个 fabric 拖垮。
2.4 设备期望与枚举类型:给实现者的边界
3.4.7 节“Device Expectations”和 3.4.6 节“Enumerated Types Used in Headers”看起来是边角料,实际是规范可实施性的关键。枚举类型固定了头部字段的取值空间,设备期望则说明了实现者至少要满足什么。没有这两节,不同厂商的实现就没法互通。
一个具体的细节是,3.4.2 节的语义头部格式里,字段是按语义角色组织的,而不是按线缆上的比特顺序组织的。这意味着线缆编码由 PDS 的头部格式负责,SES 头部是逻辑视图。这种分层让 SES 可以跨不同的 PDS 投递模式复用。
3. 包投递子层 PDS:可靠性和排序为什么被做成可选项
PDS 是 UET 里最工程化的部分,也是最容易被误读的部分。很多人看到“可靠投递”就以为 UEC 只有一种可靠模式,实际上 3.5.7 节明确写了“Packet Delivery Modes Overview”,投递模式是多种的,排序模式在 3.3.6 节也是可配置的。这个设计选择背后有明确的取舍。
3.1 PDS 术语与逻辑接口:先厘清“包、请求、确认”
3.5.1 节和 3.5.2 节花了不少篇幅定义 PDS 术语并配图说明。3.5.3 节讲投递服务,3.5.4 节讲 PDS-SES 逻辑接口。这个顺序说明 PDS 不是简单地在 SES 下面加一层包头,而是有自己完整的服务模型。
PDS 的核心概念包括包、请求、确认、投递上下文(PDC)。3.5.8 节专门讲 PDC,说明它是 PDS 的状态载体。一个 PDC 里保存了什么?从 3.5.9 节的“PDS Event State Machine”能反推:发送侧需要记录哪些请求在途、哪些已确认、重传计时器状态;接收侧需要记录期望的序列号、乱序缓存、确认待发状态。
这里有个容易踩的坑:PDS 的“可靠”不等于“SES 的事务一定按序完成”。PDS 保证的是包级别的可靠投递和某种排序,SES 的事务顺序还要看 SES 自己的语义规则。两层各管一段,读规范时如果把两层的保证混在一起,就会得出错误结论。
3.2 投递上下文 PDC 与事件状态机
3.5.8 节和 3.5.9 节是 PDS 的心脏。PDC 是投递上下文,可以理解为一条逻辑通道的发送/接收状态集合。事件状态机则定义了 PDC 在什么事件下迁移到什么状态。
用代码化的方式描述这个状态机的骨架,大致是这样:
# PDS 发送侧状态机的简化骨架(示意,非规范原文) class PDSender: def __init__(self): self.inflight = {} # 请求ID -> 请求元数据 self.next_seq = 0 # 下一个可用序列号 self.retransmit_timer = None def send_request(self, req): req.seq = self.next_seq self.next_seq += 1 self.inflight[req.seq] = req self.transmit(req) # 实际发包 self.arm_timer(req.seq) # 启动重传计时 def on_ack(self, ack_seq): # 确认到达:释放已确认请求,滑动窗口前移 for seq in list(self.inflight): if seq <= ack_seq: del self.inflight[seq] self.advance_window(ack_seq) def on_timeout(self, seq): # 超时:重传并可能触发拥塞信号 req = self.inflight.get(seq) if req: self.transmit(req) self.notify_congestion(seq) # 交给 CMS 处理这段骨架里几个参数值得展开。inflight字典对应在途请求表,大小受 PDS 配置参数(3.5.5 节)约束,比如窗口大小、最大在途请求数。next_seq是序列号分配器,序列号空间大小会影响回绕处理。on_ack里的滑动窗口前移逻辑,决定了接收侧乱序缓存要留多大。on_timeout里的notify_congestion是 PDS 和 CMS 的接口点——重传不是 PDS 自己闷头重发,而是要把拥塞信号往上递。
3.5.6 节“Reliability and Ordering”明确了可靠性和排序的保证范围。规范在这里区分了“可靠但不保序”“可靠且保序”等组合,对应 3.3.6 节的 PDS 排序模式。为什么要有不保序的可靠模式?因为某些 AI 通信模式(比如 all-to-all 的某些阶段)对顺序不敏感,放松排序可以换取更低的延迟和更简单的接收侧缓存。
3.3 头部格式与字段:线缆上的真实布局
3.5.10 节“Header Formats”和 3.5.11 节“Header Fields”是 PDS 最“硬”的部分。3.5.12 节开始讲请求和确认。这几节合起来定义了包在线上长什么样、每个字段什么含义。
常见的实现思路是,PDS 头部会包含序列号、PDC 标识、操作类型、长度、确认信息、拥塞信号字段。序列号用于检测丢包和乱序;PDC 标识用于多路复用;确认信息可以捎带在数据包里,减少单独 ACK 的开销;拥塞信号字段则是 CMS 的输入。字段的位宽和编码方式决定了硬件实现的复杂度,规范通常会给实现留一些保留位。
这里有个设计取舍值得注意:PDS 头部和 SES 头部是分开的,PDS 头部在内层还是外层,取决于封装方式(3.3.8 节“Encapsulation”)。封装方式影响硬件解析的层次,也影响交换机能否在不解析 SES 的情况下做拥塞标记。
3.4 配置参数:为什么 PDS 要暴露这么多旋钮
3.5.5 节“PDS Configuration Parameters”列了一组可配置参数。这些参数不是给用户随便调的,而是给不同部署场景做适配的。比如小规模集群可以用小窗口低延迟配置,大规模集群需要大窗口高吞吐配置。
把参数暴露出来的代价是互操作性变复杂,但收益是同一套协议能覆盖从单机架到多机架的跨度。3.1 节的“UET Scope, Scale, and Reach”和 3.1.1 节的“Virtualization”说明 UEC 从一开始就打算覆盖虚拟化环境,虚拟化又要求参数可配,因为虚拟交换机的能力和物理交换机不同。
4. 拥塞管理 CMS 与安全 TSS:控制信号如何穿透整个 fabric
CMS 和 TSS 在目录里篇幅不大(3.2.3 节和 3.2.4 节只是子层概述),但它们是 UET 区别于“纯可靠传输”的关键。可靠传输只保证送到,CMS 保证送得合理,TSS 保证送得安全。
4.1 拥塞控制算法的可插拔设计
3.3.7 节“CMS Congestion Control Algorithms”用了复数,说明 UEC 不锁定单一算法。这是个聪明的选择:AI 集群的流量模式差异很大,训练和推理不一样,不同拓扑也不一样,锁定一个算法必然有人不满意。
CMS 的输入来自哪里?从 PDS 的接口看,至少有两个来源:一是 PDS 的确认和超时事件(端到端信号),二是交换机侧的拥塞标记(网络内信号)。3.2.6 节“Sublayer Interfaces”定义了子层之间的接口,CMS 通过这些接口拿到信号、输出发送速率或窗口调整。
我一般会这么理解 CMS 的工作方式:它不直接发包,而是给 PDS 一个“能发多少”的许可。PDS 按许可发送,超时或收到拥塞标记时把信号递给 CMS,CMS 调整许可。这种“许可 + 反馈”的结构,让拥塞控制算法可以替换而不动 PDS 的投递逻辑。
4.2 传输安全子层 TSS 与软件层安全协议的呼应
TSS 在传输层负责安全,2.2.9 节的“Security Protocol”在软件层也有对应。两处呼应说明安全不是单点,而是贯穿软件和传输。传输层的安全通常涉及包的加密认证,软件层则涉及密钥管理和策略。
这里的设计取舍是性能。加密认证有开销,AI 集群又极度在意开销。UEC 把 TSS 做成子层,意味着可以实现“按需启用”——对安全敏感的多租户场景启用,对封闭高性能场景可以裁剪。3.2.7 节的“Error Handling”和 3.4.5 节的 SES 错误处理要区分开:前者是子层通用错误,后者是语义层错误,两者的错误传播路径不同。
4.3 子层接口:为什么接口定义比算法更重要
3.2.6 节的“Sublayer Interfaces”和 3.2.5 节的“Layering Summary”放在一起看,会发现 UEC 在接口上花的笔墨不比算法少。原因是可组合性:SES、PDS、CMS、TSS 要能被不同厂商独立实现再拼起来,接口必须是规范里最硬的部分。
常见的实现思路是,子层接口会定义数据结构(信号、许可、错误码)和调用时序(同步还是异步、是否可重入)。这些定义如果模糊,互操作性就无从谈起。3.2.7 节的错误处理也属于接口的一部分——错误怎么上报、怎么隔离,决定了故障会不会扩散。
5. 避坑与常见问题:读 UEC 规范和落地时的几个坑
5.1 把 SES 的排序保证当成 PDS 的排序保证
现象:实现时以为 PDS 可靠投递就等于事务按序完成,结果集合通信出现偶发的数据竞争。
原因:PDS 的可靠性和排序是包级别的,SES 的事务顺序有自己的语义规则(3.4.8 节内存模型)。两层保证不是一回事,PDS 的“可靠不保序”模式在某些配置下是合法的。
解决:先确定 SES 事务需要什么顺序保证,再去选 PDS 的排序模式(3.3.6 节),两层保证要对账,不能想当然。
5.2 忽略 PDC 的生命周期管理
现象:长时间运行后连接异常,重传率上升,甚至出现序列号错乱。
原因:PDC 是状态载体,创建、使用、销毁有完整状态机(3.5.9 节)。如果应用层频繁建连断连却不按状态机走,PDC 可能残留脏状态,序列号空间回绕时出问题。
解决:按 3.5.8 节和 3.5.9 节的状态机管理 PDC 生命周期,特别注意序列号回绕和窗口重置的时序。
5.3 以为 CMS 只需要端到端信号
现象:拥塞控制调来调去,高扇入场景下尾延迟还是压不下来。
原因:CMS 的信号来源不止端到端。交换机侧的拥塞标记(3.2.6 节子层接口)是重要输入。只靠超时和 ACK 做拥塞控制,反应太慢,微突发已经把队列打满了。
解决:确认交换机和端点都支持拥塞信号通路,CMS 算法要把网络内信号纳入反馈环。
5.4 在软件层重复实现传输层已经有的机制
现象:应用层自己做了重传和流控,结果和 UET 的机制打架,性能反而下降。
原因:2.2 节的 libfabric 映射已经把传输能力暴露给应用,UET Profile 里也定义了配置信息(2.2.3 节)。应用层如果再叠一层可靠传输,等于双重保险变双重开销。
解决:先读 2.2 节的映射关系,确认哪些能力由传输层提供,应用层只做传输层不提供的部分。
5.5 把 Informative 章节当成规范约束
现象:照着 1.3.1 节工作负载描述或 3.4.9 节 CCL 映射去实现,发现和规范正文冲突。
原因:规范 1.2.1 节明确定义了 Normative、Informative、Implementation Statements 三类陈述。标注 Informative 的章节是说明性的,不构成合规要求。
解决:实现前先分清章节的陈述类型, normative 的才必须满足,Informative 的只作参考。
6. 设计取舍:UEC 为什么选择“分层可裁剪”而不是“一套通吃”
读完整份规范,最值得琢磨的不是某个具体算法,而是整体架构哲学:UEC 把传输层切成四个可组合的子层,把可靠性和排序做成可配置,把拥塞算法做成可插拔,把安全做成可裁剪。这套“分层可裁剪”的设计,和传统“一套通吃”的协议思路是相反的。
取舍在哪里?一套通吃的协议实现简单、互操作容易,但适配性差。AI 集群的场景跨度太大:小到单机架的训练集群,大到多机架的推理集群,流量模式、延迟要求、安全要求都不同。如果 UEC 锁定一种可靠模式和一种拥塞算法,必然有一类场景被牺牲。分层可裁剪的代价是规范和实现的复杂度上升,互操作性要靠更严格的接口定义来保障——这就是为什么 3.2.6 节子层接口和 1.2 节的规范约定写得那么细。
这种设计还有一个隐含好处:演进空间。CMS 将来换算法不用动 PDS,SES 将来加事务类型不用动线缆格式。对于一个要活很多年的标准,这比一时的实现简单更重要。
怎么验证自己理解对了?我一般会用三个问题自检:第一,给定一个通信模式,能说清它走的是 SES 的哪类事务、PDS 的哪种投递模式、CMS 的哪条反馈路径吗?第二,给定一个性能问题,能定位到是哪个子层的哪个可配置参数吗?第三,给定一个互操作故障,能判断是 normative 约束没满足还是 Informative 理解偏差吗?三个问题都能答上来,才算真正读进去了。
这份规范的价值不在于它定义了某个新算法,而在于它把 AI/HPC 网络需要的传输能力拆成了可组合的积木,并给每块积木定了接口。想深挖的话,3.2 节的子层划分和 3.5 节的 PDS 状态机是最值得反复读的两处,前者是骨架,后者是血肉。资源里的完整规范文档把这两处的每个字段、每个状态迁移都写清楚了,对着实现读一遍,比泛读十篇解读文都管用。
从那以后我每次评估一个网络协议,都会先找它的“分层边界”和“可配置项”——边界决定了它能组合什么,可配置项决定了它为谁让步。希望帮到你。
本文还有配套的精品资源,点击获取