Elea Notes.

词条 · 系统与工程 · 入门

中继

一个只负责复制转发的中间点。它让发送方不必自己承担扇出。

也称:中继、relay、Relay、中继服务器

下面从”一个人要把同一份东西同时发给一万个人”这个具体困境出发,看它为什么必然需要一个中间层,以及那个中间层为什么最好什么都不懂。

先看一个麻烦:你的上行带宽不够

你在自己家里做一场直播。摄像头出来的画面,每秒需要 3 兆比特才能看清。

一个观众,你往外发 3 Mbps。家里宽带的上传是 30 Mbps,没问题。

十个观众。你得往十个不同的地址各发一份同样的数据——同一帧画面复制十遍,发十次。需要 30 Mbps。刚好顶满。

第十一个观众连上来,所有人的画面都开始卡。

停下来看看卡在哪。问题不是你的网速慢,是「同时发给 N 个人」这件事的成本随 N 线性增长,而增长的那部分全压在发送方身上。你换一条一百兆的线路,也只是把墙从 11 个观众推到 33 个。观众数量翻十倍,你的带宽也得翻十倍。

这不是直播独有的。一个交易所要把最新价格同时推给所有交易终端,一个协作编辑器要把某人的一次按键同时送到所有协作者屏幕上,都是同一个形状。

朴素尝试为什么都不够

招数一:让观众互相转发。 第一个观众收到画面之后转给第二个,第二个转给第三个。发送方只发一份。听起来很妙,但延迟会沿着链条累加——排在第五十位的人看到的画面比第一位晚几秒,而且他的画面质量取决于前面 49 个人的网络和善意。任何一个人关掉浏览器,他后面所有人都断了。

招数二:买一台带宽很大的服务器,让所有人连它。 这可行,也是正确方向的第一步。但当观众来自全球时,一台机器解决不了物理距离——从新加坡到弗吉尼亚的一个来回就是两百多毫秒,光速给的下限,加钱不能改。

招数三:在每个地区放一台,发送方往每台各发一份。 延迟解决了。但发送方的负担又回来了:五个地区就要发五份。地区越多越贵,而这正是你想摆脱的那个线性增长。

招数四:让这些机器之间自己串起来。 发送方只往最近的那台发一份,那台复制给别的地区,别的地区再复制给自己的观众。这一招成了。

四次失败给出的要求:中间那层必须能复制(一份进多份出)、能级联(自己之间能串成树)、并且发送方只需要发一份。满足这三条的东西就叫中继。

机制:一进多出,且不理解内容

中继做的事可以用一句话说完:收到一份带名字的数据,把它复制给所有要这个名字的人

   发布者                                              订阅者

     │  一份                ┌──────────┐   复制    ┌─── 新加坡的观众
     ├─────────────────────>│  中继 A  ├──────────┼─── 新加坡的观众
     │   name="game-1"      └────┬─────┘          └─── 新加坡的观众
     │                           │
     │                           │ 一份(级联)
     │                           ▼
     │                      ┌──────────┐          ┌─── 法兰克福的观众
     │                      │  中继 B  ├──────────┼─── 法兰克福的观众
     │                      └──────────┘          └─── 法兰克福的观众

     └── 发布者始终只发一份,不管观众有多少 ──────────────────

关键性质在于中继不需要知道那些字节是什么意思。它不解码视频、不解析消息、不关心里面装的是画面还是价格还是键盘输入。它只做两件事:按名字建立对应关系,然后复制。

这一条不是偷懒,而是三个能力的来源:

通用。 因为不理解内容,同一套中继能同时承载直播、语音通话、实时消息。这些场景原本各需要一套专用服务器。

可端到端加密。 发布者可以在发送前加密,订阅者收到后解密,中继全程只搬运密文——它本来就不需要看内容,所以看不到也不影响它工作。

可级联成树。 中继给下游中继发数据和给订阅者发数据是同一个动作,所以它们能自然串成任意深的树。数据在树上每一层才分叉一次,总的复制量因此被摊到整棵树上,而不是压在根节点

代价也在这里:中继看不到内容,就没法根据内容做决策。它不能为了适应某个观众的慢网络而重新编码视频,也不能优先丢弃不重要的帧——那些都需要理解载荷。要做这类事,就得在中继之外另开一层。

为什么值得知道:它是「扇出」这个词的具体形状

扇出(fan-out)指一份数据变成多份送往多处。它在系统设计里到处出现,而中继是它最纯粹的实现。认出这个形状之后,几个判断会变得直接:

发送方的成本应该和接收方数量无关。 如果你发现自己的发送端在按接收者数量循环发送,那么中继这一层缺失了。这是最常见的可扩展性瓶颈之一,而且它在小规模测试时完全看不出来。

延迟的下限由拓扑决定,不由带宽决定。 加带宽治不了跨洲的延迟。要降延迟只能缩短路径,也就是把中继放得离用户更近。这解释了为什么 CDN 厂商比拼的是城市数量而不是机器性能。

「不理解内容」是一个可以主动选择的约束。 它换来通用性和可加密性。反过来,任何需要看内容的功能(转码、按内容路由、内容审查)都必须放在中继之外——这个边界一旦在设计时想清楚,后面就不会反复纠缠。

收束

回到第二节那三条要求:能复制、能级联、发送方只发一份。中继全部满足,靠的是一个刻意的自我限制——它不去理解自己搬运的东西

一万个观众和十个观众,对发布者来说是同一个动作。差别被吸收进了中继这棵树里,而树能长多大,取决于你愿意在多少个城市放机器。