跳转至主要内容

TCP积压捕获是一种效果,它阻止Stratus 模块上的服务器应用程序在X端口上监听,无法成功地与任何试图连接到X端口的客户机建立连接。即使从相同的客户机连接到其他端口也能正常工作。典型的解决方案是关闭并重新启动服务器应用程序。这篇文章将解释为什么会发生积压捕获和其他不那么激烈的解决方案。

TCP backlog是待处理的连接队列,也就是已经收到但尚未被接受的连接请求。在OpenVOS 17.1之前版本编译的应用程序和在OpenVOS 17.1上编译但没有POSIX库的应用程序中,连接请求在被应用程序接受之前不会被发送确认。客户端将以越来越大的间隔重新发送3到10次连接请求数据包。确切的细节将取决于客户机的操作系统和它的配置方式。在某些时候,服务器应用程序接受了连接请求,STCP栈会发送一个确认。只要在客户端放弃之前收到该确认,连接就会完成,并可以开始通信。

积压捕捉方案需要几个条件

  1. 在服务器和客户端之间(但不是客户端和服务器之间)出现了暂时的网络故障。这使得服务器可以接收到客户端的连接请求,但客户端无法接收到服务器的连接确认。

    服务器应用程序由于某种原因延迟调用accept函数。

  2. 客户端继续发送连接请求;即当当前请求超时时,客户端发送新的请求。客户端的超时值必须比服务器的超时值短。
  3. 有状态的防火墙或客户机和服务器之间的其他设备会超时处理客户机的连接请求,并丢弃服务器的连接确认,而不向服务器发送响应。这个超时值必须比服务器的超时值短。

遗憾的是,这种条件的组合并不像表面上看起来那么不可能。

它通常从网络中断开始,阻止服务器的数据包到达客户端,但允许客户端的数据包到达服务器。当客户端的连接请求数据包到达服务器时,它被放在积压队列中。当服务器应用程序对accept代码进行调用时,代码会将连接请求从backlog队列中拉出,并发送一个连接确认。由于服务器没有得到它的数据包的确认,因为网络中断了,所以它重新发送连接确认。客户端的TCP协议栈也会因为没有得到确认而重传连接请求。过了一会儿,客户端的TCP协议栈就会放弃,客户端应用程序会发送一个新的请求。服务器继续响应第一个请求。大约一分半钟后(默认情况下),服务器超时并从backlog队列中提取下一个请求。与此同时,客户端已经重新发送了第二个请求,并可能在第三个请求中。这些请求也在积压队列中。有可能其他客户机会得到一个放在backlog队列中的连接请求,但要成功完成,客户机需要的超时时间大于服务器超时时间乘以连接请求在backlog队列中的位置。一旦网络中断被纠正,有状态的防火墙就会通过默默地丢弃不再有状态的连接确认来延续中断,因为它只保持状态的时间比服务器超时短。

你怎么认识这个?

首先积压已经满了,或者至少是填满了。你可以用这个命令显示一个连接的积压队列。

analyze_system -request_line (string match backlog -or syncnt (byte 3Bx) dump_st +)
cbq -full -lport 7654 -faddr 0x) -quit 
OpenVOS 17.0.2au版,analyze_system 17.0.2au版。 
当前进程为154,第91CC7100页,Noah_Davids.CAC。 
syncnt 6 
积压5 
11:41:19

lport的值是本地端口号,本例中是7654。国外地址(faddr)值为0,限制了输出只限于LISTENING插座。如果backlog值加1等于syncnt值,则backlog已满。如果syncnt大于0并向上,则backlog队列正在填充。回溯日志队列的大小由应用程序在调用listen函数时设置。

其次,你需要查看网络协议跟踪。跟踪会显示,最后一个连接请求没有得到确认,而前一个连接请求有连接确认,这些确认没有得到任何形式的响应。

图1中的跟踪显示了这一点。每个连接都有一个流索引的标签,也有颜色编码。客户端发出的第一个连接请求是在时间0的第1帧,确认是在第2帧发送,然后在第3帧重发。帧4是客户端重传连接请求。由于STCP已经在发送连接确认,所以第4帧触发的只是第5帧的TCP确认。帧6和帧7是重传的连接确认。帧8是客户端重传的连接请求。帧9是重传连接请求触发的TCP确认,帧10是另一个重传连接确认。帧11是客户机发出的另一个连接请求,但是是新的第二个连接。请注意,没有响应,帧12显示了一个重传的连接请求。帧13显示了一个连接确认,但它仍然是针对第一个连接的。帧14是第二个连接请求的重传。帧14是第二连接请求的另一次重传。帧15显示了来自客户端的新的第三连接请求,帧16和17是重传。帧18是对第一连接的连接确认的又一次重传。帧19是又一个连接请求,帧20和21是重传,帧22是第四个新的连接请求。最后在帧23中STCP放弃了第一个连接请求,并在帧24中发送一个复位,然后在帧25中重传第二个连接请求的连接确认。至此,我想你已经明白了。

STCP从第0帧到第23帧超时,共耗时106.9秒。虽然客户端在超时时没有发送复位,但从第二和第三个连接请求开始(第11帧到第15帧)之间的时间是29.152秒,第三和第四(第15帧和第19帧)之间的时间是25.8秒;比STCP快得多。

如何防止这种情况的发生?

最好的解决办法是升级到OpenVOS 17.1,并用POSIX库重新编译应用程序。这样做可以防止问题的发生,因为STCP会立即发送一个连接确认,而不需要等待应用程序调用accept。然而,它可能会改变你的应用程序的其他行为,因此应该对你的应用程序进行仔细的测试。如果升级和重新编译不可能,你可以通过以下方法解决

  1. 重新配置正在丢弃连接确认的有状态网络设备,以响应复位。当STCP收到复位后,它将转到积压队列中的下一个连接请求。其结果是,被有状态设备计时的连接请求将迅速从队列中排出。任何进一步的连接确认将由客户端处理,客户端将发送自己的复位或确认。
  2. 停止客户端的连接请求,直到服务器的后备队列被清空。
  3. 关闭服务器应用程序的监听套接字并重新打开它。通常情况下,应用程序没有被设计成这样做,所以你必须停止并重新启动服务器应用程序。
  4. 将syn_rcvd_abort值配置为比客户端超时值短的值。这个值可以通过 analyze_system 请求 set_stcp_param 来改变。
    analyze_system -request_line 'set_stcp_param syn_rcvd_abort 15' -quit
    OpenVOS 17.0.2au版,analyze_system 17.0.2au版。 
    当前进程为151,第91530AC0步,Noah_Davids.CAC。 
    将tcp SYN_RCVD超时(syn_rcvd_abort)从关闭改为15。 
    准备好了 11:07:44

    在上面的例子中,超时时间被设置为15秒,有效值在1到180之间,0表示使用默认值(约100秒)。有效值在1到180之间,0值表示使用默认值(约100秒)。

    这将防止单个客户机在积压队列中产生大量的积压。这个值应该有多短,取决于很多客户端可能同时访问服务器。这种方法的问题是会影响到所有的客户端和所有的服务器端口,你不能对一组端口使用一个值,而对另一组端口使用另一个值。此外,过低的值可能会导致一些通过高延迟链路的连接失败,而如果定时器更长的话,这些连接可以成功。选择一个最佳值是艺术而不是科学

© 2020 Stratus Technologies.