最大化Linux中的TCP吞吐量:理解和调优发送和接收缓冲区

Photo by  Zac Harris on  Unsplash

        对于运行在Linux上的分布式系统,一个标准的性能调优建议是调整tcp_rmem和tcp_wmem内核可调参数。但是这些是什么呢?为什么它们很重要?它们是如何工作的?

        在今天的文章中,我们将探讨tcp_rmem(接收缓冲区)和tcp_wmem(发送缓冲区)的工作方式,以及如何调整它们以提高应用程序性能。

理解TCP缓冲区

        为了更好地理解TCP缓冲区是如何工作的,让我们研究这样一个场景:“应用程序A”(客户端)希望通过TCP将数据发送给“应用程序B”(服务器)(如下所示)。

发送方

        在上图中,我们可以看到应用程序A想要向应用程序B发送4000字节的数据。要做到这一点,应用程序A将使用write()或send()系统调用将数据附加到套接字(socket)。从应用程序的角度来看,数据已经被写入套接字,但实际上数据首先被追加到该套接字的Send Buffer中。一旦数据在发送缓冲区中可用,内核将把数据分解成一个或多个TCP包。通常,Linux系统上一个包的默认大小是1500字节,前24字节(包含扩展选项)是TCP包头;这意味着单个数据包可以容纳1476字节的应用程序数据。要发送4000字节的应用程序数据,内核需要发送三个包。

        作为一个应用程序,我们不关心一个数据包中包含多少数据。应用程序将数据写入缓冲区。内核从缓冲区中获取数据并将其发送到目标系统,不管这个过程中需要多少数据包。

        内核还会将应用程序数据保存在发送缓冲区中,直到服务器确认发送的数据包。它这样做是为了在包丢失的情况下需要重新传输包。

接收方

        在服务器上,存在另一个称为接收缓冲区的缓冲区。当内核接收并处理数据包时,来自这些数据包的数据被写入接收缓冲区。

        正如应用程序不关心发送缓冲区一样,应用程序也不会和接收缓冲区进行交互。通常,应用程序将使用recv()系统调用从套接字读取数据。但实际上,应用程序是从套接字的接收缓冲区读取可用数据。

增加缓冲区大小

        发送和接收缓冲区的大小是可调的; 它们可以在Linux中通过修改/etc/sysctl.conf文件进行调整。要查看当前值,我们将使用sysctl命令。

$ sysctl net.ipv4.tcp_wmem
net.ipv4.tcp_wmem = 4096 16384 4194304

从上面的命令输出中,我们可以看到当前存在三个值。

        第一个4096 (4KB)是最小缓冲区大小。默认情况下,这个最小值设置为与系统页大小相同的大小。设置这个最小值是为了确保即便在低内存机器上或者存在内存压力情况下也有缓存。

        第二个值16384 (16KB)是默认大小。系统上的所有TCP套接字缓冲区默认大小。值得注意的注意是net.ipv4.tcp_wmem将覆盖net.core.wmem_default, net.core.wmem_default是所有网络协议(TCP, UDP等)的默认发送缓冲区大小。

        第三个值4194304 (4MB)是最大缓冲区大小。与默认大小不同,该值不能覆盖net.core.wmem_max。

        当建立新的TCP连接时,将使用默认值(16KB)创建一个发送缓冲区; 然后,缓冲区大小将根据需要和使用情况自动在最大和最小边界内进行调整。

        对于大多数情况,调整最大值就足够了,很少需要更改默认值或最小值。

调整发送缓冲区

        要更改发送缓冲区大小,可以再次使用sysctl命令。

$ sysctl -w net.ipv4.tcp_wmem="4096 16384 8388608"

        上面的命令将发送缓冲区调整为8 MB; 但是,在重新启动后,更改会丢失。要使此更改持久化,我们可以将更改添加到/etc/sysctl.conf文件中。

调整接收缓冲区

        接收缓冲区也是可调的,就像发送缓冲区一样。要查看当前值,可以使用sysctl命令。

$ sysctl net.ipv4.tcp_rmem
net.ipv4.tcp_rmem = 4096 131072 6291456

        与前面的发送缓冲区参数一样,这三个值表示TCP的最小、默认和最大接收缓冲区大小。同样,TCP接收缓冲区的最大值不能超过net.core.rmem_max,net.core.rmem_max定义所有网络协议的最大接收缓冲区大小。

        在上面的例子中,最大缓冲区大小设置为6 MB; 我们可以使用sysctl命令将其调整为12mb。

$ sysctl -w net.ipv4.tcp_rmem="4096 131072 12582912"

         与前面的示例一样,要使此更改永久生效,必须将设置添加到/etc/sysctl.conf文件中。

何时调整缓冲区大小 

        既然我们知道了如何调整发送和接收缓冲区,那么什么时候应该更改它们呢? 对于大多数系统,默认值都比较大。然而,在某些情况下,调整这些缓冲区是有必要的。

        一个主要的例子是TCP客户端通过不可靠的网络发送数据。由于发送缓冲区必须为未被确认的数据包保留数据,因此高丢包率的连接可能会导致发送缓冲区满。当发送缓冲区已满时,应用程序不能再向缓冲区添加数据,并且通常会阻塞(等待)尝试添加数据。

        这种情况在物联网领域很普遍,设备更有可能利用不可靠的网络。然而,不可靠的网络只是这些缓冲区大小可能需要调整的情况之一。

        正如本文开头所述,服务器应用程序不断地从接收缓冲区读取数据。但是,如果程序读取速度不能跟上输入数据的速度,Receive Buffer可能会满。当这种情况发生时,服务器将开始通过减少TCP数据包中的“窗口”大小字段来通知客户端降低数据发送。当应用程序从缓冲区读取数据时,TCP首部中的窗口大小和报文确认号将增加。从而通知客户端它可以恢复发送数据。

查看缓冲区利用率

        当应用程序性能变坏(写入缓冲区时大量阻塞)或者通过某些TCP窗口变更监控,我们怀疑可能需要调整TCP缓冲区的时候,可以使用netstat命令验证缓冲区的使用情况。

$ netstat -n
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State      
tcp        0      0 10.0.2.15:22            10.0.2.2:60570          ESTABLISHED

        在netstat命令的输出中,有两列表示缓冲区利用率。Recv-Q列表示接收缓冲区中等待接收应用程序读取的字节数。Send- Q列表示发送缓冲区中等待远程系统发送和确认的字节数。

        典型的健康应用程序应该具有较低的发送和接收缓冲区利用率。如果应用程序持续显示不正常,则需要具体调查下。

总结


        在本文中,我们探讨了Linux如何为基于tcp的通信使用tcp_wmem(发送)和tcp_rmem(接收)缓冲区,如何使用sysctl命令调整这些缓冲区,以及如何使用netstat命令确定当前的利用率。

        虽然在本文中,我描述了从客户机到服务器的单向通信,但必须记住TCP套接字是双向的。客户端和服务器都有一个发送缓冲区和接收缓冲区分配给连接。

         每个应用程序都是独一无二的,但根据我的经验,每当我不得不更改接收缓冲区时,我还需要调整系统上的发送缓冲区大小。

原文链接:https://madflojo.medium.com/maximizing-tcp-throughput-in-linux-understanding-and-tuning-send-and-receive-buffers-92df654c415f 

 

  • 5
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值