最后更新:2022-06-23 19:52:17 手机定位技术交流文章

本文主要论述了如何在Linux操作系统下优化TCP的三步握手过程,提高握手速度。
TCP是一个完全双重协议,可以双向传输。所以需要三个手来建立联系。HTTP请求中三个握手的平均时间超过10%,在网络状况不佳、频率高、或遇到SYN洪水攻击等情况下,如果三个手的参数不正确调整,它将对业绩产生巨大的影响。
TCP协议由操作系统实现,并且必须通过操作系统提供的接口和工具对TCP进行调整,这需要理解Linux如何向我们展示三手状态,并使用哪些工具找到最佳基础,以及哪些接口修改参数。
因此,本文将介绍各状态在TCP握手过程中的意义,并以状态变化为主线,探讨如何调整Linux参数来提高握手性能。
客户端和服务器可以优化三个握手的性能。相对而言,主动启动的连接的客户端优化相对简单,服务器需要在听话端口上被动等待连接,把许多手放在中间,优化方法比较复杂.我们首先研究如何优化客户.
三手连接的主要目的是同步序列数目。只有同步序列数能提供可靠的传输。TCP协议的许多特性取决于序列数的实现。例如, 交通控制, 消息丢失后重现等.这就是为什么这三手报告叫做SYN。因为SYN的正式名称是 Synchronize SequenceNumbers。

尽管操作系统实现了三个手,但它通过连接向我们揭示了这一过程。让我们更仔细地看一下下面的三个状态的意义。客户发送SYN打开三个握手,在此点,使用netstat命令(用于随后查看连接状态)可以看到客户端的连接状态,即SYN_SENT。它只是发送SYN。
tcp 0 1172.16.20.227:39198 129.28.56.36:81 SYN_SENT
客户端正在等待服务器对ACK消息作出答复。正常情况下,服务器将在几毫秒内返回ACK,但是如果客户没有收到ACK迟到怎么办?客户将取得SYN,重新尝试的频率由tcp_syn_retries参数控制,默认是 6 次:
net.ipv4.tcp_syn_retries = 6
第一次试演在一秒内进行,又在第二、第四、第八、十六、和第三十二秒、六次重演。最后一次尝试将等待64秒,如果ACK仍未归还,才会终止三次握手。所以,总时间是1+2+4+8+16+32+64=127秒,超过 2 分钟。
如果这是一个具有明确任务的服务器,您可以根据网络稳定性和目标服务器的繁忙度修改重新测试的数量来调整客户端的三手时间限制。

当服务器收到SYN消息时,服务器立即响应SYN+ACK消息,确认客户端的序列编号和发送其序列编号给另一方。 此时,服务器端出现一个新的连接,状态是
SYN_RCV (RCV是接收的缩写) 在这种状态下,服务器必须创建一个SYN半连接队列来维护未完成的握手信息,并且当这个队列溢出时,服务器无法再创建一个新的连接。

新的连接失败有很多原因,如何得到队列被填满导致的失败的数目? 这可以在netstat -s命令给出的统计结果中找到。
# netstat -s | grep "SYNstoLISTEN"
1192450 SYNs to LISTEN sockets dropped
这里是导致SYN被丢弃的队列溢出数目。注意这是累积值,如果人数不断增加,SYN半连接队列应该增加规模。修改队列的大小,这是Linux的tcp_max_syn_backlog参数设置:
net.ipv4.tcp_max_syn_backlog = 1024
如果SYN半连接队列满了,只能丢弃连接吗?并不是这样,打开同步cookies功能将允许您成功地建立连接,而不使用SYN队列。方法如下:服务器根据当前状态计算一个值,发送由您发送的SYN+ACK消息,当客户端返回ACK消息时,取出该值验证,如果合法,考虑到连接成功,如下图所示。

在Linux下如何打开syncookie功能?您可以修改tcp_syncookie参数,如果值为0,则意味着函数是关闭的。2表示无条件的开源**电源,而且1只表示SYN半连接队列不能离开时,再启用它。因为syncookie仅用于响应SYN洪灾攻击(攻击者恶意构造大量SYN消息发送到服务器),导致SYN半连接队列溢出,与正常客户端的连接无法建立),这样建立的联系,许多TCP功能不可用。所以,设置tcp_syncookie为1,只有在队列满时才重新启用。
net.ipv4.tcp_syncookies = 1
当客户端收到服务器发送的SYN+ACK消息时,会回复ACK通知服务器,同时将自连接状态从SYN_SENT转换为 ESTABLISHED,表示连接建立成功。成功建立服务器端连接所需的时间是后退的。直到它收到ACK, 这个国家是建立的.
如果服务器不接收ACK,SYN+ACK消息会不断重复。当网络繁忙和不稳定时,那张纸的丢失会变得严重,在此阶段,应增加复发的频率。否则,重复数可以减少。修改重复频率的方法是,调整tcp_synack_retries参数:
net.ipv4.tcp_synack_retries = 5
tcp_synack_retries的默认重试率是5次,类似于SYN的客户端重复,它的重试需要1、2、4、8、16秒。最后一次尝试后等32秒,如果仍未收到ACK,才会关闭连接,全长63秒。
服务器收到ACK后, 连接成功地建立.此时,内核将从SYN半连接队列中删除连接,迁移接受队列,在等待进程调用接受函数时,删除连接。如果进程不能及时调用接受函数,这将使接受队列溢出,最终, 一个好的TCP连接被丢失.
事实上,放弃连接只是Linux的默认行为,而且我们也可以选择向客户端发送一个RST迁移消息,告诉客户端连接未能建立。 打开这个函数需要设置tcp_abort_on_overflow参数为1。
net.ipv4.tcp_abort_on_overflow = 0
通常情况下,tcp_abort_on_overflow应该设置为0,因为处理突然的流动是更有益的。举个例子,当接受队列满时,服务器丢失ACK,与此同时,客户端的连接状态已建立,该过程将请求发送到一个已建立的连接上。只要服务器不响应ACK请求,请求多次重复。如果服务器上的进程只是短暂忙,导致接受队列满了,所以当接受队列空的时候,检索请求消息,因为它包含ACK,它仍然会在服务器端启动一个成功的连接。所以,tcp_abort_on_overflow设置为0以增加连接创建的成功率,只有当你确信队列将长期过载时,可以设置为1,以便尽快通知客户端。
那么,如何调整接受队列的长度?听力函数的后队参数可以设置接受队列的大小。事实上,后队参数也限制在Linux系统级别的队列长度限制,当然, 这个限度阈值也可以通过索马克斯康参数修改.
net.core.somaxconn = 128
现在可以通过ss-ltn命令查看每个听力端口的接收队列长度,但是否需要调整接受队列的长度?或由netstat -s命令给出的统计结果,你可以看到有多少连接被丢弃,因为队列溢出。
# netstat -s | grep "listenqueue"
14 times the listen queue of a socket overflowed
如果由于接受队列溢出被丢弃而存在连续连接,则应放大后队和索马克斯康参数。
我们只是优化上面的三个握手的过程。 接下来,让我们看看如何绕过三个手来发送数据。
三个握手创造联系的后果是,HTTP请求必须在一个RTT(Round Trip Time,从客户端到服务器的24小时时间)不能发送,根据谷歌的统计数据,握手的时间是三次,完成HTTP请求所需的时间从10%到30%。

因此,Google引入了TCP快速开放程序(TFO),用户可以在第一个SYN消息中载入请求,节省了一个RTT时间。
接下来,让我们看看TFO如何实际实施。
为客户在SYN消息中携带请求数据,必须解决服务器的信任问题。因为服务器的SYN消息尚未向客户端发送,客户端是否能正常地建立连接是未知的,但此时,服务器需要假设连接已经成功地建立,并向处理程序提交请求,因此服务器必须能够信任客户端。
TFO如何实现这一目标?它将交流分为两个阶段,第一阶段是建立联系的第一阶段,这时走路通常是三个握手,但客户端的SYN消息将明确告诉服务器它想要使用TFO函数,然后,服务器将客户端的IP地址只用它知道的钥匙加密(例如AES加密算法),作为返回的SYN+ACK消息中所载的cookie,客户在接收Cookie后将局部延迟Cookie。
之后,如果客户端重新连接到服务器,您可以在第一个SYN消息中载入请求数据,还有一个缓存的cookie。很显然,在这种通信方法下,不再使用经典的“连接和写请求”编程方法,这可以通过替换 sendmsg函数以geto函数实现。
服务器收到后,使用自己的钥匙来验证Cookie的合法性,验证仅在连接成功建立后才进行。要求程序再次处理请求,同时返回SYN+ACK到客户端。尽管客户在收到ACK后将返回ACK,但是服务器可以发送HTTP响应而不等待ACK接收。这减少了由于震动而花费的时间。

当然,为了防止SYN的洪水攻击,服务器的TFO实现必须能够自动更新键。
在Linux下如何打开FO函数?这通过tcp_fastopen参数进行。因为只有客户端和服务器同时支持,没有TFO函数,因此tcp_fastopen参数由bit-tipe控制。其中,第一部分是1小时,表示作为客户端的TFO支持;第二位是1,支持TFO作为服务器,因此,当tcp_fastopen的值为3(bit为0x11),这意味着它完全支持TFO函数。
net.ipv4.tcp_fastopen = 3
本文介绍了三个握手过程的Linux系统优化方法。
当客户通过发送SYN来引发震动时,重复数可以用tcp_syn_retries来控制。当服务器的SYN半连接队列溢出时,SYN消息将丢失,导致连接失败。我们可以根据netstat-s提供的统计结果判断队列长度是否适当,然后由tcp_max_syn_backlog参数调整队列的长度。服务器响应SYN+ACK消息的重试次数由tcp_synack_retries参数控制。当网络稳定时,它可以降低。为了应对SYN的洪水袭击,设置tcp_syncookie参数为1,它仅在SYN队列满后才打开同步cookie函数,保证连接成功建立。
服务器收到客户端返回的ACK后,将将连接转移到接受队列中,等待进程调用接受函数来提取连接.如果接受队列溢出,默认系统将丢弃ACK,您可以通过RCT使用tcp_abort_on_overflow参数通知客户端未能建立连接。如果显示Netstat统计数据,大量ACK被丢弃后,收听函数的后队参数和索马克斯康系统参数可以用于增加队列限制。
TFO技术绕过三个握手,减少HTTP请求的一次RTT时间。 在Linux中,该函数可以通过tcp_fastopen参数打开。
从本文中可以看出,虽然TCP由操作系统实现,但Linux提供了多种方式修改TCP函数的接口,使我们能够优化TCP的性能。
本文由 在线网速测试 整理编辑,转载请注明出处。