除了TCP/IP,我们还有什么?
TCP/IP 的主要缺点
毫无疑问,TCP/IP 网络是当前主流的数据传输技术。传统的 TCP/IP 技术需要将数据从用户应用空间的 Buffer 复制到内核空间的 Socket Buffer 中,并进行头部的封装等操作,通过一系列多层网络协议的数据包处理工作,这些协议包括传输层的传输控制协议(TCP)、用户数据报协议(UDP)、网络层的互联网协议(IP)以及互联网控制消息协议(ICMP)等。数据才被复制到 NIC 网卡中的 Buffer 进行网络传输。在整个过程中,多项处理过程都很容易成为传输的瓶颈,它们包括:
- 两次数据复制操作增加了 CPU 资源的消耗,并且传输带宽容易受到 CPU 处理速度的限制(这是最主要的原因),从用户模式到内核模式也需要进行上下文切换,这也是一个比较大的开销,同时这种冗余的处理增加了传输的延迟;
- 头部的封装操作加大了 CPU 的资源消耗。
基于这些 TCP/IP 的缺点,有多种其他的传输方式可以作为 TCP/IP 的替代来进行高性能传输。
TCP Offloading Engine
主要思想是将 CPU 从繁杂的网络处理过程中解放出来,将专用的处理过程 offload 到专用网卡上进行处理,使主机 CPU 专注于其它应用。这种技术需要特定网络接口——网卡支持这种 offloading 操作。这种特定网卡能够支持封装多层网络协议的数据包,这个功能常见于高速以太网接口上,如吉比特以太网(GbE)或 10 吉比特以太网(10GbE)。相对于使用传统的 TCP/IP 内核网络,这种方法的优点主要有两点:
- 一是减少了数据复制的次数,原先需要复制两次,这次只需要将数据复制到网卡即可。TCP Offloading Engine 是一种 Zero-copy 的协议;
- 二是缓和了 CPU 的资源,也就是将 CPU 从网络处理中解放了出来;
主要缺点有两点:
- 这种网卡需要专门进行设计;
- 作为外设的这种专用网卡访问内存仍旧绕不开 CPU,所以 CPU 访问内存的速度仍旧限制了网络的传输速度。
User-Net Networking(U-Net)
U-Net 的设计目标是将协议处理部分移动到用户空间去处理。这种方式避免了用户空间将数据移动和复制到内核空间的开销。也就是降低了一次复制开销。U-Net 是 RDMA 项目早期的一种设计,相对于 TCP Offloading Engine,U-Net 将网络协议实现在用户端而不是网卡上。U-Net 也是一种 Zero-copy 的协议,
为什么 TCP 协议栈要放在 Linux 内核中呢?
让我们从一个更广泛的问题开始:运行操作系统到底有什么意义?如果计划运行一个应用程序,则必须使用由数百万行代码组成的内核,这似乎是一种负担。
但是实际上,我们大多数人都决定运行某种操作系统,我们这样做有两个原因。
- 首先,操作系统层增加了硬件独立性和易于使用的 API。有了这些,我们可以专注于为任何机器编写代码:不仅是我们目前拥有的专用硬件。
- 其次,操作系统增加了一个时间共享层。这使我们可以一次运行多个应用程序。无论是启动第二个 HTTP 服务器还是只是启动第二个 bash 会话,在多个进程之间共享资源的能力至关重要。内核对外开放的所有资源都可以在多个进程之间共享!
通过使用通用的操作系统网络堆栈,我们能够运行多个网络应用程序。如果我们将网卡硬件专用于单个应用程序以运行用户空间的网络堆栈,则会丢失这种能力。如果网卡被一个进程所声明并使用,那么我们将不能够在运行服务器的同时运行 SSH 会话。
这听起来很不可思议,但这正是大多数现成的用户空间网络堆栈技术所面临的问题。用户空间网络堆栈技术的术语是“完全内核旁路”。其想法是绕过内核,直接从用户空间进程使用网络硬件。
在 Linux 相关的生态环境中,有一些可用的技术,但是并不是所有都是开源的,比如:PF_RING, Snabbswitch, DPDK, Netmap 等等。
所有这些技术都需要将整个网卡移交给一个进程。换句话说:我们完全有可能编写自己的网络堆栈,使其专注于我们所需要的特定功能,并针对性能进行优化。但是这会产生很大的成本:您将被限制为每个网卡最多运行一个进程。
但是即使有所有这些不足之处,我也不能忽略内核旁路的好处。许多人确实运行自定义的网络堆栈,原因是以下两个原因之一:延迟和高性能(更低的 CPU 开销、更高的吞吐率)。
综合来看,我们可以概括为以下两点:
- 如果是小型设备,需求是通用的,那么使用内核协议栈;
- 如果是大型设备/数据中心,需求是固定/特定的,那么使用 DPDK 等用户态协议栈,结合网络虚拟化技术,会获得最适合的性能。