读《Uno:数据中心间和数据中心内拥塞控制与可靠连接的一站式解决方案》

今天要来读《Uno: A One-Stop Solution for Inter- and Intra-Data Center Congestion Control and Reliable Connectivity》这篇论文。本文是阅读过程中的杂记。

现有问题

云计算与AI推理既需要数据中心内通信又需要跨数据中心通信,但是数据中心内和跨数据中心网络的延迟差异巨大,让两者的通信瓶颈为带宽而不是路由(我们更希望让带宽被打满)所需的消息大小也不同。当前,数据中心内与跨数据中心的拥塞控制都是分别的模块在负责,Uno提出了一个统一系统处理这两种情况下的拥塞控制及路由。

挑战

intra是DC内,inter是DC间

阻塞反馈

inter流延迟高,拥塞信息传回慢,intra流相反,难以知道实际情况

BDP(带宽延迟积)异构

BDP表示在飞的数据包,intra更小,inter更大。这对于缓存区浅的交换机来说是个挑战,因为它的缓存队列不足以容纳突发流量。

丢包处理

丢包信息需要一个RTT才能传回来,重传代价很高。BBR为WAN设计,没有考虑数据中心内的网络,Gemini用同一套滑动窗口处理inter和intra收敛慢

Uno

“Uno, a system that tightly integrates congestion control, load balancing, and loss resiliency to create a unified solution for both intra- and inter-DC communication” Uno,一个紧密集成了拥塞控制、负载平衡和损失恢复能力的系统,为数据中心内部和数据中心之间的通信提供统一的解决方案

Uno由UnoCC和UnoRC组成。

UnoCC的设计很巧妙,主要用在大消息,带宽为瓶颈的情况下。使用了幽灵队列实现用ECN统一控制inter和intra流量

UnoRC在“大部分瓶颈是延迟”的设定上,用纠错包以额外带宽开销为代价减少重传,并使用UnoLB故意把一个流拆成几个子流分散到不同的路径,因为有冗余包,可以在接收端恢复。无法恢复再发NACK

这一块的关键设计有以下的ai总结:

1. 幽灵队列

  • 定义与机制:幽灵队列是交换机内部维护的一个虚拟计数器,它与物理队列同步累积到达的数据量,但以一个略低于物理链路带宽的速率(如95%线速)持续“排水”。ECN标记的阈值基于这个虚拟水位,而非物理队列水位。
  • 解决的问题:跨数据中心BDP(带宽延迟积)极大(可达500MB),而交换机物理缓冲区极浅(仅几MB),传统拥塞控制算法所需的缓冲区容量远超物理现实。
  • 核心效果:
    • 提前预警:虚拟水位上升速度快于物理水位,在物理队列满之前就触发ECN,给发送方充分的反应时间。
    • 吸收突发:虚拟计数器容量可任意设定,能匹配跨域大BDP,平滑吸收流量突发。
    • 物理队列近零排队:稳定状态下物理队列基本为空,为延迟敏感的小流提供畅通的快速通道。
    • 带宽高效利用:将总吞吐量稳定锁定在略低于线速的水平,避免“过山车式”的震荡和丢包。

2. 统一ECN信号

  • 含义:无论是数据中心内部(intra-DC)还是跨数据中心(inter-DC)流量,UnoCC仅使用ECN一种信号来做速率调节决策,并以相同的反应粒度(统一的epoch周期,基于较小的intra-DC RTT设定)执行AIMD调整。
  • 为什么必须这么做:
    • 原有方案的问题:Gemini等方案对内用ECN、对跨域用延迟作为拥塞信号,导致两类流对拥塞的反应粒度差异巨大(跨域流反应极慢),造成收敛到公平带宽分配的速度极慢,且网络利用率不足。
    • 统一信号的必要性:只有使用同一种信号、在同一节奏下做出反应,intra-DC和inter-DC流才能在同一瓶颈链路上快速、公平地收敛到带宽份额,避免一种流被另一种流持续压制。
  • 如何做到:幽灵队列消除了跨域流量因BDP过大而需要特殊拥塞信号(如延迟)的必要性,使得ECN信号在两种场景下都可用、有效,为统一控制逻辑提供了先决条件。

3. 纠删码

  • 定义与机制:一种前向纠错技术。将原始数据分成 (k) 个数据块,编码生成 (m) 个校验块,共发 (n = k+m) 个块。只要接收方收到其中任意 (k) 个块,即可完整重建原始数据,无需重传。论文中采用 ((8,2)) 方案,即8个数据包加2个校验包。
  • 解决的问题:跨数据中心网络RTT极大,丢包后依靠传统重传会引入至少一个RTT的额外延迟,对延迟受限的消息造成显著性能损失。
  • 核心效果:
    • 避免重传延迟:少量丢包可通过冗余校验包直接恢复,无需等待重传,大幅降低尾部延迟。
    • 容忍突发丢包:能有效应对多条路径上呈现相关性的连续丢包。
    • 代价:引入固定的带宽开销(如20%),但在延迟主导的跨域场景下,用可控的带宽代价换取确定性的延迟保障是可行的。

4. 子流级负载均衡

  • 定义与机制:在发送端,将同一纠删码块内的数据包,通过轮转改写UDP源端口号的方式,人为使它们被网络(通过ECMP哈希)分发到不同的物理路径上。当检测到某条路径故障或严重拥塞(通过NACK或超时),则将该子流自适应地重路由到其他健康的路径。
  • 与纠删码的集成逻辑:
    • 分散风险:同一编码块的不同包走不同路径,即使整条路径故障,该块仍有足够多的包从其他路径到达,配合纠删码即可解码恢复。
    • 互补增强:纠删码提供对零星丢包的冗余容忍,多路径分发提供对整条链路故障的规避能力。两者结合,无需重传即可应对单点链路故障。
  • 子流粒度的优势:相比逐包喷洒(严重乱序)和单流绑定(哈希碰撞、易受故障影响),子流级多路径在负载均衡效果与控制乱序程度之间取得了平衡。

实现

UnoCC

UnoCC将网络情况区分为三种:

  1. 不拥塞(论文定义为AI状态)AI — Additive Increase(加性增加)
  2. 拥塞 (论文定义为MD状态)MD — Multiplicative Decrease(乘性减少)
  3. 极度拥塞 (论文定义为QA状态)QA — Quick Adapt(快速适应)

不拥塞

AIMD(加性增,乘性减),需要注意的是公式如下:

$$cwnd = cwnd + \alpha \times \frac{bytes\_acked}{cwnd}$$

也就是说不是像tcp那样一个rtt增加一个mss,而是把一个mss切成了很多份。

包是连续发的,所以对于一个rtt内那个窗口发的包,其对应的ack会在相邻时间内传回来,每收一个ack,窗口增大一点。

$\alpha$ 应被设定为BDP的一部分,比如$0.001\times BDP$ $\alpha$ 应随队列长度和网络能支持的incast程度而缩放

拥塞

MD阶段,每个epoch最多触发一次,这是为了防止一看到ECN就减速

AI(加性增)是每收到一个ACK就立即执行一次小额窗口增长的。但MD不能这样——不能一看到带ECN标记的ACK就立刻砍窗口。原因有二:

  1. 瞬时噪声:网络中可能存在极短暂的流量脉冲,导致个别包被标记ECN,但瞬间就恢复了。如果每看到一个ECN就降速,会导致窗口剧烈震荡。
  2. 信息不完整:单个ECN只告诉你"有一个包经历了拥塞",但无法反映整个网络在这一小段时间里的整体拥塞程度。

因此,UnoCC引入Epoch(纪元)机制:在一个Epoch持续期间,只收集所有ACK中的ECN信息,不做任何降速决策;等到Epoch结束时,再根据整个Epoch内的汇总信息,做最多一次MD降速。

Epoch的边界由两个关键时间戳定义:

  • $T_{epoch}$:当前Epoch的起点时间(激活时间)
  • $T_{pkt}$:每个数据包被发送/重发时记录的时间戳

Epoch生命周期:

  1. 首次激活:流的第一个ACK到达时,记下该时刻作为初始$T_{epoch}$,激活第一个Epoch。
  2. 运行期间:所有数据包发出时记录$T_{pkt}$。发送方正常收集ACK,统计其中被ECN标记的比例,但不执行降速。
  3. 终止条件:当收到一个ACK,它确认的数据包的$T_{pkt} \ge T_{epoch}$时,说明在当前Epoch激活之后发出的包,其反馈已经回来了,我们有了关于这段时间网络状况的完整信息。此时Epoch终止。
  4. 滚动前进:终止后立即将$T_{epoch}$增加一个$epoch\_period$(与流的RTT成正比),激活下一个Epoch。

直觉理解:$epoch\_period$约等于一个RTT。设计保证了每个Epoch大致覆盖一个"发送-反馈"的完整周期,有足够多的包被确认,从而能做出有统计意义的拥塞判断。

判定规则非常直接:

如果在一个Epoch中,有任何一个ACK携带了ECN标记,这个Epoch就被判定为"拥塞的"。

这意味着UnoCC对拥塞信号足够敏感——哪怕只有少量包被标记,也认为网络有压力,应该考虑减速。

当Epoch被判定为拥塞后,核心是计算降速比例。UnoCC不是简单地砍半,而是用了一个与环境适配的多因子公式。

降速执行: $cwnd = cwnd \times (1 - MD_{ECN})$

$MD_{ECN}$的计算:

$$MD_{ECN} = \mathcal{E} \times \left(\frac{4 \times K}{K + BDP}\right)$$

其中两个关键变量:

① $\mathcal{E}$:拥塞热度的指数加权移动平均(EWMA)

$\mathcal{E}$是UnoCC的"拥塞体温计"。它不是看当前这一个Epoch的ECN比例,而是对**横跨多个Epoch的ECN标记比例**做了平滑处理。

更新规则(每个Epoch结束时执行一次):

$$\mathcal{E}_{new} = (1 - g) \times \mathcal{E}_{old} + g \times F_{current}$$

其中:

  • $F_{current}$:当前Epoch中被ECN标记的包的比例
  • $g$:EWMA的增益因子(通常取较小值如$0.125$或$1/8$)

为什么需要$\mathcal{E}$?

  • 偶发瞬态拥塞:当前Epoch的$F_{current}$突然飙高,但$\mathcal{E}$只会上涨一点点,不会触发大幅降速
  • 持续重度拥塞:$F_{current}$连续多个Epoch保持高位,$\mathcal{E}$稳步攀升至高位,$MD_{ECN}$随之增大,降速力度与持续性匹配

② $\left(\frac{4 \times K}{K + BDP}\right)$:网络规模适配因子

  • $K$:用户设定的常数,控制对拥塞epoch的反应激进程度
  • $BDP$:带宽延迟积,代表网络的"大小"

自适应效果:

  • 当$BDP$很大(跨数据中心长肥管道):分母增大,该因子变小 → 降速更保守,避免在长管道上过度反应导致带宽浪费
  • 当$BDP$很小(数据中心内部):分母减小,该因子变大 → 降速更果断,适配小缓存交换机的需求

幽灵队列的ECN信号可能来自虚拟水位而非真实物理排队。如果物理队列实际是空的,大幅降速会造成不必要的带宽浪费。

UnoCC通过测量相对延迟来区分:

$$delay = RTT - RTT_{base}$$

  • $RTT$:当前包的实测往返时间
  • $RTT_{base}$:无拥塞网络中的最小RTT

判断逻辑:

1
2
3
4
5
6
7
在每个Epoch结束时:
if delay == 0 (即RTT没有额外增加):
→ 物理队列空,仅幽灵队列拥塞
→ MDscale = MDscale × 0.3
else (delay > 0):
→ 物理队列确实有排队
→ MDscale = 1

执行真正的降速:

$$cwnd = cwnd \times (1 - MD_{ECN} \times MDscale)$$

  • 物理拥塞时:$MDscale = 1$,执行完整MD降速
  • 仅幽灵拥塞时:$MDscale$被逐渐衰减至很小,发送方只轻微减速,因为物理链路仍通畅
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

procedure ON_EPOCH_TERMINATION:
if ecn_fraction > 0:

E = (1 - g) * E + g * ecn_fraction


if delay == 0:
MDscale = MDscale * 0.3
else:
MDscale = 1


MD_ECN = E * (4 * K / (K + BDP))


cwnd = cwnd * (1 - MD_ECN * MDscale)

极度拥塞

QA — Quick Adapt(快速适应),应对MD反应过慢的极端拥塞场景。

MD(乘性减少)虽然能根据拥塞热度平滑降速,但有一个根本局限:当网络遭遇急剧的容量塌陷时,MD的反应速度跟不上。

典型触发场景包括:

  • 新流突然加入:多条大流同时启动(incast),瞬间将瓶颈链路塞满。
  • 链路或路径故障后的流量转移:大量流量被重路由到同一瓶颈。

在这些事件中,物理队列或幽灵队列的水位瞬间飙升,丢包风险极高。如果仍让MD每个Epoch平滑地砍一点窗口,等到窗口降到安全水平时,网络可能已经经历了长时间的严重拥塞和大幅延迟增加。

QA的设计目标就是:一旦检测到这类网络容量的断崖式下跌,立即将发送窗口砍到当前网络实际能承受的水平,然后给网络一个冷静期。

UnoCC每隔一个RTT执行一次QA检查。判断依据非常直观:

如果在这个RTT内,被确认的字节数远低于预期,说明网络极度拥塞。

形式化:

$$bytes\_acked\_in\_qa < cwnd \times \beta$$

  • $bytes\_acked\_in\_qa$:在这个QA评估周期(一个RTT)内,接收到的所有ACK所确认的总字节数
  • $cwnd$:当前的拥塞窗口大小(即发送方可发出的最大在途数据量)
  • $\beta$:用户设定的QA比例阈值

直觉理解:在无拥塞的正常情况下,一个RTT内应该能确认大约一整个窗口的数据量(因为窗口大小等于链路上的在途数据)。如果实际只确认了很少,这意味着包在路上遭遇了严重排队或丢包,网络已经远超轻度拥塞。

一旦触发QA,UnoCC直接执行"紧急刹车":

$$cwnd = bytes\_acked\_in\_qa$$

  • 不再使用任何渐变因子(不乘任何系数)。
  • 窗口直接被重置到这个RTT中网络实际完成交付的数据量。
  • 这意味着:发送方的发送能力立刻缩减到网络此刻的现实瓶颈带宽。

为什么这样做合理?

  • 如果极度拥塞是因为物理队列被塞满、大量包丢失,bytes_acked_in_qa就代表了网络此刻真实能消化的数据量。
  • 直接将窗口与之对齐,可以瞬间解除对瓶颈的压迫,让队列开始排空,避免长时间的延迟飙升。

QA是非常激进的操作。为了防止对短时波动过度反应,导致窗口刚砍下去又被AI慢速爬坡拖累,UnoCC在QA触发后引入一个强制冷却期:

触发QA之后,跳过接下来的一个完整RTT,在此期间不触发任何QA或MD。

这个设计的效果:

  • 给网络一个RTT的时间去消化QA的效果(队列排空、丢包恢复)。
  • 防止在QA后的RTT内,因为仍在恢复期中、bytes_acked依然偏低而再次触发QA,造成窗口连续被踩到底。
  • 一个RTT后,恢复正常的AIMD循环,开始从新的、更低的窗口水平进行加性增长。
1
2
3
4
5
6
7
8
9
10
11

procedure ON_QA_CHECK:
if bytes_acked_in_qa < cwnd * beta:

cwnd = bytes_acked_in_qa


skip_next_QA = true
skip_next_MD = true
else:

QA只在最恶劣的瞬态冲击下启动。正常情况下网络运行在AI和MD的循环中,只有当MD来不及反应时,QA才介入做一次"硬着陆"。之后经过一个RTT的冷静期,拥塞控制平稳交还给AI/MD,让其从新的实际速率开始重新爬坡。这种分层设计让UnoCC既能保持日常运行的高效和平滑,又能在极端事件中快速自救。

幽灵队列

如§2所分析的,在同时存在intra-DC和inter-DC流量的场景下,高效设置ECN标记阈值面临两难:

  • intra-DC交换机:缓冲区极浅(通常仅几MB),BDP很小
  • inter-DC链路:BDP极大(可达数百MB),所需缓冲区容量远超物理现实

如果按intra-DC的标准设置ECN阈值,inter-DC大流会瞬间撑爆浅缓冲;如果按inter-DC的标准设置,intra-DC的拥塞检测将极度迟钝。若所有地方都使用浅缓冲,又会导致现代拥塞控制算法在面对大BDP时产生剧烈震荡。

幽灵队列的核心思想是:用一个虚拟计数器来替代物理队列做ECN标记决策,从而将拥塞检测与物理缓冲容量解耦。

幽灵队列是一个在交换机上维护的简单计数器,不需要任何实际的包存储空间:

  • 增加规则:每当一个新包进入物理队列时,幽灵队列的计数器增加该包的字节数
  • 减少规则:计数器以一个恒定速率持续减少,该速率是物理链路带宽的一个固定比例(称为排水速率)

论文中建议的排水速率设置为物理队列排水速率(即链路带宽)的约90%,即比物理链路慢约10%。

$$drain\_rate_{phantom} = 0.9 \times drain\_rate_{physical}$$

稳态下的行为:

在正常运行的稳态下,幽灵队列的排水速率低于物理队列。这意味着:

  1. 当流量以接近线速的速率持续到达时,物理队列的"进水"与"出水"基本持平,物理队列水位保持在低位甚至归零。
  2. 但幽灵队列的"出水"比"进水"慢,因此虚拟水位会持续维持在某个正值,甚至可能很高。
  3. ECN标记的阈值被设置在这个虚拟水位上,而非物理水位。

关键效果:

  • 提前预警:幽灵队列的虚拟水位比物理水位更早触及ECN阈值,在物理队列被塞满之前就向发送方发出拥塞信号,给跨域长RTT流量充分的反应时间。
  • 物理队列近零排队:因为发送方在幽灵队列触发ECN时就开始减速,物理队列在稳态下基本保持为空。数据包到达交换机后几乎立即被转发,无额外排队延迟。
  • BDP匹配:幽灵队列的计数器上限可任意设定,能轻松匹配跨域大BDP(数百MB)的需求,不受物理交换机缓冲区物理容量的限制。

由于物理队列在稳态下几乎为空,延迟敏感的intra-DC小流的数据包到达交换机时可以直通,排队延迟接近零。这为小流创造了额外的"带宽净空",使其不受大流突发的挤压。

幽灵队列的提前预警可能让大流过早减速,存在"惩罚"吞吐量密集型大流的风险。论文给出的解决方案是精细调节排水速率:

  • 将排水速率设置为仅比物理队列低约10%
  • 经验结果表明,这10%的差距足以让小流受益于近零排队,同时不会显著牺牲大流的吞吐量
  • 大流仍能维持在接近线速(约90%-95%)的稳定吞吐水平,避免震荡和丢包带来的更严重性能损失

幽灵队列标记ECN,UnoCC在收到ECN信号后,通过MDscale机制(见MD章节)区分拥塞来源:

  • 若$RTT$未增加($delay = 0$)→ 物理队列空,仅幽灵队列拥塞 → 温和减速
  • 若$RTT$增加($delay > 0$)→ 物理队列有排队 → 正常减速

这种双层配合保证了幽灵队列的预警功能不会导致不必要的过度降速。

UnoRC

先不写了,UnoCC急着要完成