Network Layer & End To End System Design
这一节我们会介绍网络的分层(老熟人了)和 End To End System Design. 计算机网络以分组的方式来提供对物理等层面的抽象。各层的所有协议被称为协议栈(protocol stack),而 internet 提供了 物理层、链路层、网络层、运输层和应用层:
- 对于应用层而言,数据是 message
- 对于运输层而言,它们在应用 endpoint 中传输上层的 message。我们把这一层的分组叫做 segment。这一层的协议包括 TCP 和 UDP
- 网络层负责将 datagram 移动到另一边。这一层包括著名的 IP 协议,同时它包含一些路由选择协议, 给运输层运输 packet
- 链路层依靠链路层的服务(还记得我们前两讲介绍的吗)讲消息传给下一个节点,链路层的分组称为 frame / packet.
- 物理层中,我们完成了对物理信号等对程序员来说没啥影响,但是必要的电路等信息。这一层向上一层提供了光纤、铜线等提供的物理信号,给上层提供 0/1。
应当说明的是,上面是 Internet 的网络分层,实际上你可能还听说过 OSI 7层模型等分层。
在分层的网络中,对于上层而言,下层类似 api,下层提供一些封装过后的保证,上层用一定的方式和一定的保证来获得下一层的数据。
链路层和网络层
1/2/5 实际上相对来说好理解,大部分人都或多或少有印象。但是 4-5 之间有什么区别呢?我们知道网络层包括 IP 协议,实际上,情况类似下面:
We’ll divide the world into switches and routers
- Switches will route on your, Link Layer (L2) Addresses
- Routers will operate on IP (L3) Addresses
这两层使用的 Route 方式不同,这一点我们即将介绍 IP,就会了解了。
实际上,IP 这个抽象相对来说相当重要,它提供了一个比较独立的网络的抽象,同时,对于异质性的网络,网络层也需要作出一定的协调和妥协:
- 网络的带宽更大,发送的数据更快,而满的网络来不及接受,IP 需要丢弃来自生产快的网络的包
- IP 层不能保证 loss-free 和消息传递的 order (This is called best effort service.)
- 有些网络有着更大的 packet,这个时候需要支持 fragementation 来拆分 packet
下面继续丢图:
同时,对于上层的应用而言,我们也有不同层次的信息(正如我们一开始介绍的):
每层的信息有不同的 header, 来表示这一层承载的信息。
End To End arguments in system design
这是 84 年的一篇文章,介绍了那个时候互联网应用设计的一些思考。作者认为应该合理的抽象,在底层实现一些语意以优化性能,在高层实现高层真正想要的语义,因为在底层做抽象是很昂贵的,并且它们提供的语意也不一定真正可靠(当然你是金融公司或者很有钱啥的,都能自己搭海底光缆搞高频交易了,你大概也有钱在下层做优化了)。
文章最开始举了个简单的例子:文件传输程序。
用户从 fs 中读取一个文件,然后经过程序一定处理,发送给网络另一端,另一个用户接收并写入 fs。
这个事件本身各个层次都可能出现错误。我们不仅需要底层各种保证和错误处理,实际上我们需要端到端的确认,即应用确认文件写入完成,并且 checksum 等一致。
同时,我们虽然有 tcp 之类的协议能保证 order 和内容可靠,但是可靠的内容不一定被处理了,从这个角度来看,仅仅 tcp 是不可靠的。但是相对更底层的协议,或者 UDP 而言,底层实现对应的语义能保证性能上的 bonus. 我们可能需要下列的方案来保证应用层次的可靠:
- Encryption
- First-in-first-out ordering
- Duplicate message surpression
- Multi-message transactions
slide 给出了总结,我就不献丑翻译了:
Basic argument: If you can implement functionality correctly and completely at endpoints, do it there and not at a lower layer.
- It saves on redundant work in the system, and avoids confusion later. Exceptions okay for performance optimizations.
Strong argument: Avoid putting unneeded functionality at lower layers of your system altogether because it’s harmful!
- Extra functionality at low layers constrains how applications are designed at higher layers.