撰文 | 乔晶、姚迟
1
OneFlow 中的流控
OneFlow 团队此前发布的《仅此一文让您掌握OneFlow框架的系统设计》介绍了 OneFlow 是通过背压机制解决流控问题的。文中给出了两张流水线的示意图:
图:当训练是瓶颈时的时间线
图:当数据加载是瓶颈时的时间线
如上面两张图所示,虽然 DataLoading 的时间很短,但并不会无节制加载数据,而是当它的两个Regst被填满之后就会等待。
-
当 Training 是瓶颈时,Batch 3的数据在训练时,DataLoading 提前准备了 Batch 7 和 Batch 8 的数据,然后就等着。
-
当 Preprocessing 是瓶颈时,DataLoading 永远都比 Preprocessing 提前处理了两个 Batch 的数据。
这两张图简单地说明了,在去中心化、异步执行设计的 OneFlow 系统中,通过背压机制,系统会自动地照顾好处理速度最慢的那个单元,使得各个执行单元(我们称之为 Actor),都能够随之调节好运行节奏。
仔细思考一下,你会发现,这里的背压机制,似乎和大家熟知的 TCP 滑动窗口有异曲同工之妙。
确实,背压(Backpressure)机制,又叫 Credit-based Flow Control,是网络通信中解决流控问题的一种经典方案,它的前身就源于 TCP 滑动窗口。
这个思路特别简洁有效,后面我们会看到,基于相同原理,这个思路适用于任何流量控制方案,在很多硬件系统和软件系统的设计中,都有它的身影。
但是,你可能想象不到,这个简洁思路背后却有着不简单的身世。甚至,还引发过一场激烈的学术论战,并且在论战中还输了。虽然输了,Credit-based Flow Control 思想却在论战中得到了完善,后来在多个领域大放异彩。
今天,我们就来讲一讲它背后的原理,以及其跌宕起伏的故事。
2
什么是流控
网络流控(Network Flow Control)是网络中的一个基本功能,其目的是防止网络在拥塞的情况下出现丢帧。
在上面这张图中,假设在一对网络通信节点之间:
-
Sender 生产数据的速率是 2MB/s,Receiver 消费数据的速率是 1MB/s,数据在网络中传输的速率是 2MB/s。
-
两个节点各有一个数据缓冲区(Send Buffer/Receive Buffer),大小均为 5MB。
可以推演出,由于 Sender 生产数据的速度比 Receiver 消费数据的速度快, 5s 后 Receive Buffer 就被装满了,这时会面临两种情况:
-
如果 Receive Buffer 是有界的,那么新到达的数据就只能被丢弃掉了。
-
如果 Receive Buffer 是无界的,那么 Receive Buffer 会持续扩张,最终会导致 Receiver 端内存耗尽。
简单总结一下,所谓流控,就是解决端到端的发送方和接收方速度不匹配的问题。或者更明确一点,就是解决 “Fast Sender Slow Receiver ” 的问题。
那么,流控方案有哪些?所谓流控方案,就是提供一套速度匹配措施,通过遏制 Sender 较快的发送速率,与 Receiver 较慢的读取速率相适应。
问题就转换成了,以怎样的方式遏制 Sender 的发送速率呢?常见的解决思路有两种。
思路一:简单粗暴地限速
Sender 以预先确定的速率发送数据。比如在 Sender 端实现一个限速器,将 Sender 的发送速率降到 1MB/s ,这样的话, Sender 端的发送速率跟 Receiver 端的处理速率就可以匹配起来了。
思路二:授权发送
Sender 不能直接发送,除非它已经从 Receiver 接收到一个关于可接受通信量的指示。这种量化方案保护了 Receiver 端不会内存溢出。
注意,这里的可接受通信量,常常被称为授权(Credit),它到底是什么呢?又和我们所说的 Credit-based Flow Control 有什么关系呢?
先卖一个关子。接下来我们将按照时间顺序,讲述 Credit-based Flow Control 的身世。实际上,这两种思路,正是我们将要看到的一场论战中冲突对战的两派。问题的答案,也将在故事中揭晓。
2
Credit-based Flow Control 的故事
TCP 滑动窗口
1974年,TCP/IP 协议的设计者,被称作互联网之父之一的 Vinton G. Cerf,发表了 TCP/IP 协议的奠基论文