13.linux网络的相关问题记录

13.linux网络的相关问题记录

1
> 本文笔记来自:「极客时间  Linux 性能优化实战」,原文链接:https://time.geekbang.org/column/article/80898

问题 1:网络收发过程中缓冲区的位置

之前文章介绍过 Linux 网络的收发流程。涉及到了多个队列和缓冲区,包括:

  • 网卡收发网络包时,通过 DMA 方式交互的 环形缓冲区

  • 网卡中断处理程序为网络帧分配的,内核数据结构 sk_buff 缓冲区

  • 应用程序通过套接字接口,与网络协议栈交互时的 套接字缓冲区。

不过相应的,就会有两个问题。

首先,这些缓冲区的位置在哪儿?是在网卡硬件中,还是在内存中?这个问题其实仔细想一下,就很容易明白——这些缓冲区都处于内核管理的内存中。

其中, 环形缓冲区,由于需要 DMA 与网卡交互,理应属于网卡设备驱动的范围。

sk_buff 缓冲区,是一个维护网络帧结构的双向链表,链表中的每一个元素都是一个网络帧(Packet)。虽然 TCP/IP 协议栈分了好几层,但上下不同层之间的传递,实际上只需要操作这个数据结构中的指针,而无需进行数据复制。

套接字缓冲区,则允许应用程序,给每个套接字配置不同大小的接收或发送缓冲区。应用程序发送数据,实际上就是将数据写入缓冲区;而接收数据,其实就是从缓冲区中读取。至于缓冲区中数据的进一步处理,则由传输层的 TCP 或 UDP 协议来完成。

其次,这些缓冲区,跟 Buffer 和 Cache 有什么关联吗?

内存中的 Buffer ,都跟块设备直接相关;而其他的都是 Cache。

实际上,sk_buff、套接字缓冲、连接跟踪等,都通过 slab 分配器来管理。可以直接通过 /proc/slabinfo,来查看它们占用的内存大小。

问题 2:内核协议栈,是通过一个内核线程的方式来运行的吗

第二个问题,内核协议栈的运行,是按照一个内核线程的方式吗?在内核中,又是如何执行网络协议栈的呢?

说到网络收发,在中断处理文章中我曾讲过,其中的软中断处理,就有专门的内核线程 ksoftirqd。每个 CPU 都会绑定一个 ksoftirqd 内核线程,比如, 2 个CPU 时,就会有 ksoftirqd/0 和 ksoftirqd/1 这两个内核线程。

不过要注意,并非所有网络功能,都在软中断内核线程中处理。内核中还有很多其他机制(比如硬中断、kworker、slab 等),这些机制一起协同工作,才能保证整个网络协议栈的正常运行。

问题 3:最大连接数是不是受限于 65535 个端口

我们知道,无论 TCP 还是 UDP,端口号都只占 16 位,也就说其最大值也只有 65535。那是不是说,如果使用 TCP 协议,在单台机器、单个 IP 地址时,并发连接数最大也只有 65535 呢?

对于这个问题,首先要知道,Linux 协议栈,通过五元组来标志一个连接(即协议,源IP、源端口、目的IP、目的端口)。

明白了这一点,这个问题其实就有了思路。我们应该分客户端和服务器端,这两种场景来分析。

对客户端来说,每次发起 TCP 连接请求时,都需要分配一个空闲的本地端口,去连接远端的服务器。由于这个本地端口是独占的,所以客户端最多只能发起 65535 个连接。

对服务器端来说,其通常监听在固定端口上(比如 80 端口),等待客户端的连接。根据五元组结构,我们知道,客户端的IP和端口都是可变的。如果不考虑 IP 地址分类以及资源限制,服务器端的理论最大连接数,可以达到 2 的 48 次方(IP 为 32 位,端口号为 16 位),远大于65535。

所以,综合来看,客户端最大支持65535个连接,而服务器端可支持的连接数是海量的。当然,由于 Linux 协议栈本身的性能,以及各种物理和软件的资源限制等,这么大的连接数,还是远远达不到的(实际上,C10M 就已经很难了)。


13.linux网络的相关问题记录
https://blog.longpi1.com/2022/11/16/13-linux网络的相关问题记录/