4. 链路层流控原理:基于信用的流控机制(Credit-Based Flow Control)
好,咱们今天聊聊 InfiniBand 链路层最核心的机制之一——基于信用的流控。说实话,这个机制我当年刚接触时也觉得有点绕,但搞懂了之后,你会发现它其实非常巧妙。
4.1 为什么需要流控?
先问个问题:发送端拼命发数据,接收端来不及处理,会发生什么?
答案很简单——丢包。但在 InfiniBand 这种高性能网络中,丢包是绝对不能接受的。为什么呢?因为一旦丢包,就要重传,重传就会引入延迟抖动,整个集群的性能就崩了。
所以,InfiniBand 设计了一套基于信用的流控机制。说白了,就是让接收端告诉发送端:「我还有多少缓冲区,你看着发。」
4.2 信用流控的基本原理
这个机制的核心思想其实很朴素。我打个比方:
你手里有 10 张饭票,每张饭票对应食堂的一份饭。你每吃一份饭,就消耗一张饭票。食堂阿姨看你手里还有饭票,就继续给你打饭。饭票用完了,你就得等着。
在 InfiniBand 里,这个「饭票」就是信用(Credit)。
- 发送端:每发送一个数据包,就消耗一个信用
- 接收端:每处理完一个数据包,就归还一个信用
- 信用额度:接收端初始告诉发送端「我最多能收多少个包」
发送端手里有信用,才能发数据。没信用了,就得乖乖等着。这就是「基于信用」的含义。
关键点:信用流控是逐跳(hop-by-hop)的,不是端到端的。每个链路段的发送端和接收端之间都要做流控。
4.3 信用类型:VL 与 VL15
InfiniBand 里把链路分成多个虚拟通道(VL,Virtual Lane)。每个 VL 都有自己的信用池。我记得在 Mellanox 的早期交换机上,VL 的配置就经常让人头疼。
具体来说,信用分为两类:
| 信用类型 | 作用范围 | 说明 |
|---|---|---|
| VL 信用 | 数据 VL(VL0~VL14) | 每个数据 VL 独立管理自己的信用 |
| VL15 信用 | 管理 VL(VL15) | 专门用于管理包,优先级最高 |
为什么要分 VL?因为不同的流量类型需要不同的服务质量。比如,HPC 计算流量和存储流量混在一起,如果不隔离,计算流量可能会被存储流量堵死。
我的经验:在实际项目中,我建议把 MPI 流量放在 VL0,存储流量放在 VL1。这样即使存储链路有拥塞,也不会影响计算节点的通信。我曾经在一个超算项目里吃过这个亏,后来改了 VL 映射,性能直接提升了 15%。
4.4 信用更新机制
信用不是一次性给完的。接收端会动态地更新信用。具体流程是这样的:
- 初始化时,接收端通过链路层初始化包告诉发送端:「我的接收缓冲区大小是 N 个包」
- 发送端每发一个包,本地信用计数减 1
- 接收端每处理完一个包,通过流控包(Flow Control Packet)把信用归还给发送端
- 发送端收到信用更新后,本地信用计数加回来
你想想看,这个机制保证了什么?保证了发送端永远不会超过接收端的处理能力。这就是「无损网络」的基础。
注意:信用更新包本身也需要带宽。如果信用更新太频繁,会占用链路带宽。如果更新太慢,发送端可能因为等信用而闲置。这个平衡需要根据实际流量来调优。
4.5 信用计算的细节
嗯,这里要稍微深入一点。信用不是按「字节」算的,而是按「数据包」算的。每个数据包消耗一个信用,不管这个包是 64 字节还是 4KB。
为什么这样设计?因为接收端的缓冲区是按「包」来管理的,不是按「字节」。每个包在接收端占用一个缓冲区条目。
举个例子:
接收端缓冲区大小:1024 个包
初始信用:1024
发送端发送了 500 个 4KB 的大包
→ 剩余信用:1024 - 500 = 524
接收端处理完 200 个包,归还信用
→ 发送端信用:524 + 200 = 724
这里有个坑:如果发送端发了很多小包,信用消耗得很快。但接收端处理小包的速度通常也快,所以信用归还也快。实际项目中,我见过有人把小包和大包混在一起,导致信用管理变得复杂。
4.6 信用死锁与避免
说到坑,就不得不提信用死锁。这是个经典问题。
假设有两个节点 A 和 B,互相发送数据。A 的信用用完了,等着 B 归还信用。但 B 也在等 A 归还信用。两边都等,谁也不让谁——死锁了。
InfiniBand 怎么解决?靠 VL 和独立的信用池。每个 VL 的信用是独立的,不会互相影响。而且 VL15 是专门用于管理包的,永远有信用可用。
我曾经在一个测试环境里遇到过类似的问题。当时两个节点之间只有一条链路,配置了多个 VL,但某个 VL 的信用池配得太小了,导致高负载下频繁出现信用耗尽。后来我把那个 VL 的信用池调大了两倍,问题就解决了。
避坑指南:我曾经在调试一个 200Gbps HDR 链路时,发现吞吐量上不去。查了半天,发现是信用池配置太小,导致发送端频繁等待信用。调大信用池后,吞吐量直接拉满。所以,信用池的大小不是随便设的,要根据链路带宽和延迟来算。
4.7 信用流控的性能影响
信用流控虽然保证了无损,但也不是没有代价的。主要影响有两点:
- 延迟:发送端等信用时,数据包会排队,增加延迟
- 带宽利用率:如果信用更新不及时,链路可能闲置
但说实话,在 InfiniBand 这种设计里,这些代价是值得的。因为丢包重传的代价远大于等信用的代价。你想想看,丢一个包重传要几微秒,而等信用可能只需要几十纳秒。
4.8 小结
基于信用的流控,说白了就是让接收端掌握主动权。你有多大的处理能力,我就发多少数据。这种设计保证了 InfiniBand 网络的无损特性,也是它能在 HPC 和 AI 集群中称霸的原因之一。
下一章我们会讲拥塞控制,那是比流控更上层的机制。到时候你会看到,流控和拥塞控制是怎么配合的。