TCP 连接极限在哪里
2024-08-26
今早,同事遇到一个关于网络连接数的问题,咨询我。
我看他在看 dperf🔗,一个高性能的网络压测工具。
他指着其中一个数字问:几十亿的 HTTP 并发连接数?一台电脑一共才几个端口?
他这个问题把我问住了。虽然我也学过计算机网络,知道 TCP 是一种基于连接的传输层协议,但似乎没有深入思考过,一条 TCP 连接究竟意味着什么?
今天这篇文章,就是想通过寻找单台机器 TCP 连接数的极限,顺便讲清楚 TCP 连接这个东西。
1. TCP 概述
根据 维基百科🔗 维基百科定义,TCP (传输控制协议, Transmission Control Protocol) 是一种面向连接的、可靠的、基于字节流的传输层通信协议。
TCP 是传输层协议,在五层网络划分中属于第四层。下层的网络层是 IP 协议,上层的应用层,使用最广泛的,是 HTTP,不过最新的 HTTP/3 已经开始使用基于 UDP 的 QUIC 实现。
得益于互联网的快速发展,TCP 被广泛使用。在面试中,TCP 经常是重点考察的部分,这也侧面说明了它的重要性。
我们都知道,网络两端的发送者和接收者,可以在这个星球的任意角落。双向的通信,要做到低延迟和高可靠,几乎是不可能完成的任务。为了实现这些功能,TCP 采取了一系列复杂而精妙的设计,结果就是概念众多,实现复杂。
其中连接,就是 TCP 最主要的一个特征。不过与直觉不同,这里的连接,是逻辑层面上的,并非真实的物理连接。这是可以理解的,网络中设备众多,不可能任意两台设备间都直接相连,否则可扩展性就太差了。
那么 TCP 中的连接,究竟意味着什么?
2. TCP 连接含义
TCP 协议承载的功能是可靠的信息传递,可靠意味着,数据不会丢失,不会乱序,不会存在不准确的问题。
TCP 连接就是这样一条可靠的信息通道。像是管道(pipe),连接起通信双方,信息像水一样在管道里双向流淌。
这么说可能还是有点抽象。
简单来说,连接,本质上是关于一次通信过程的状态记录和维护。
举个简单的例子。
张三和李四需要写信交流。张三和李四各自都要记下对方的地址,同时也要记录上次写信写到哪里,这次从什么地方继续,否则交流就会混乱。如果长时间没有收到对方来信,可能中间邮递员在递送过程中出了差错,还需要重新发一次。
对于 TCP 连接同样如此。
TCP 协议栈通过“三次握手”建立起连接后,操作系统就会维护一系列状态:对端 IP、对端端口、本地 IP、本地端口、序列号、确认号、窗口大小等。伴随双方信息交换,这些状态也会随之变化。因此可以这么说,管理好状态,即控制了连接。
而 UDP 协议里就没有连接的概念,每一个数据包发出去就忘记,不需要维护状态,实现起来自然简单,只不过不能保证“可靠”罢了。
既然 TCP 连接需要维护状态,自然会耗费一定的计算和内存资源,因而 TCP 连接的数量不会是无限的。
3. TCP 连接极限
回到最初的问题上。
TCP 连接的极限在哪里?
通常来说,这取决于多个因素,包括操作系统限制、可用资源、网络条件和程序设计等。
3.1 端口数量
TCP 中,每个连接由一个四元组构成,即(客户端 IP、客户端端口、服务端 IP、服务端端口)。
客户端可以使用的端口通常在 1024-65535 之间。因此理论上,一个客户端可以同时建立 6 万多条连接。
服务端通常监听一个特定端口,但可以处理多个来自客户端的连接,理论上等同于(客户端 IP 数 * 客户端端口数),大概是 2^48。
3.2 文件描述符
在 Linux 系统中,每个 TCP 连接都需要一个文件描述符(File Descriptor),而最大描述符数量是有限制的。Linux 通常默认为 1024,这对服务器来说远远不够,好在这个数字可以调整,如 ulimit -n
命令。
全局的文件描述符限制同样影响单机能建立的最大连接数,这个可以借助 /proc/sys/fs/file-max
查看。
3.3 内存和资源限制
上文提到,连接就是一系列状态记录。状态维护就需要内存和计算资源,因此最大连接数同样受到内存和 CPU 性能的约束。
3.4 网络带宽
网络带宽决定的是数据吞吐量,连接数过大,会影响数据传递的效率。因此带宽小的机器,能支撑的最大连接数也较小。
3.5 操作系统 TPC/IP 栈
Linux 的网络栈对于总的 TCP 连接数也有限制,但可以通过内核参数调整。例如 /proc/sys/net/ipv4/ip_local_port_range
可以配置本地端口范围,/proc/sys/net/core/somaxconn
可以配置服务端最大连接数。
这就涉及比较深层次的网络栈优化了。
3.6 应用程序设计
程序设计本身要支持高并发,否则 TCP 连接很容易遇到瓶颈。
现在主流的架构是事件驱动(event-driven),Linux 下通常采用 epoll。
3.7 小结
上述分析,都是基于 Linux 系统自带的 TCP/IP 协议栈。
那么,dperf 如何实现单机几十亿的并发连接?
答案在 DPDK (Data Plane Development Kit) 上。
DPDK 绕过了操作系统内核的 TCP/IP 协议栈,直接在用户态处理网卡驱动接收到的数据包。也就是说,DPDK 是用户自己维护连接的状态,而不是委托系统内核,因此技术难度和想象空间都更大。
于是传统的经验失效了。
4. 总结
简单总结下,一条 TCP 连接,就是一组状态,连接的极限,取决于系统究竟能同时处理好多少个这样的状态集合。
起初我也觉得,单机几十亿的并发连接是不可能的。如果基于传统的 TCP/IP 协议栈的确如此,因为系统内核难以维护如此多的状态。
但所有的经验和结论都是有条件的,极限就是用来被打破的。
理论和工程的边界究竟在哪里?
答案也许是,没有边界。
(完)
参考
- 本文作者:Plantree
- 本文链接:https://plantree.me/blog/2024/tcp-connection-limit/
- 版权声明:所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明出处!
最后更新于: 2024-11-20T09:44:17+08:00