代理在尝试将数据上行发送到部分closures的连接(重置数据包)后生成的HTTP 502响应

我正在通过代理服务器返回零星的502s。 当检查数据包stream时,我看到nginx发送POST请求到源服务器已经发送[FIN,ACK]的套接字。 我想了解这是如何可能和任何潜在的解决scheme。 原始问题(发送响应后5秒发送FIN还是ACK)还是代理服务器?

下面是PCAP的屏幕截图,说明问题: 在这里输入图像说明

我的理解:

  • 来自原点的响应是[PSH,ACK];
  • 代理发送一个与[P]一起收到的数据的[ACK](wireshark确认下一个[ACK]用于之前收到的[PSH-ACK])。
  • 7秒过去了(注意时间戳btw / [FIN,ACK]和我们的POST([PSH,ACK]));
  • 原点发送[FIN,ACK]。 当第一个[FIN,ACK]发送时,原始TCP状态机应处于FIN_WAIT_1状态。
  • 然后我们发送另一个POST,导致[RST]作为回报,因为起源不期待[PSH,ACK]。

题:

  • 这种情况可能的解释是什么?
  • 为什么代理(nginx)发送另一个请求,如果它已经收到一个FIN并且实际上是承认它! (POST [PSH,ACK]数据包中的确认号实际上是[FIN,ACK]的SEQ_NUMBER + 1),所以它确认幻像位FIN。
  • 5秒后,原点返回[FIN,ACK]而不是直接返回的可能原因是什么? 读取超时/空闲超时?

我没有自己的起源 – 所以不能在那里捕捉。

额外细节:

代理(nginx错误日志)上的错误日志:

2017/04/17 06:51:07 [error] 123091#0: *225010841 upstream prematurely closed connection while reading response header from upstream, client: X.90.10, server: www.example.com, request: "POST /web/?a=b HTTP/1.1", upstream: "http://X.32.238:80/web/?a=b", host: "www.example.com" 

在此屏幕截图中显示最后一个请求的SEQ和ACK号码:

在这里输入图像说明

这种情况可能的解释是什么?

起始点上约5秒空闲计数器与客户端可变活动之间的竞争条件。 第三个涉及variables当然是networking延迟。

似乎有一个约5秒的空闲计时器在原点,而你的客户端需要约5秒钟通过Nginx代理发出第二个请求(POST)。 如果前者比后者长(包括networking延迟),则没有问题。 如果发送客户请求只需要多一点点,那么你就有问题了。

你可以看到POST和FIN,来自Nginx的ACK如何被发送到一起:分别在源的FIN,ACK之后2.4ms和2.6ms。 这可能会让你失望,因为我不认为POST是原始的FIN,ACK。 因为它在原始的FIN,ACK之后2.4ms被发送

为什么代理(nginx)发送另一个请求,如果它已经收到一个FIN并且实际上是承认它! (POST [PSH,ACK]数据包中的确认号实际上是[FIN,ACK]的SEQ_NUMBER + 1),所以它确认幻像位FIN。

POST数据包的ACK编号最可能是“200 OK”数据包。 在HTTP响应之后没有来自服务器端的额外数据,所以来自客户端的任何ACK都将确认相同的号码。

更新:现在我们知道POST包的ACK数增加了1,所以Nginx知道[FIN,ACK]。 进一步的调查显示,这样做是正确的:如果计算机收到来自远程端的响应,而不是计划继续连接,则机器可能发送一个请求并以[FIN,ACK]结束,谁将发送请求的数据返回和结束继续[FIN,ACK]过程。

这并没有改变这样一个事实,即有一个竞争条件,即原点决定在空闲5秒后closures连接,从而忽略不久之后发送的POST数据包(甚至发送RST返回 – 虽然目前还不清楚这个RST是否会已经被发送不pipe)。

5秒后,原点返回[FIN,ACK]而不是直接返回的可能原因是什么? 读取超时/空闲超时?

您不必立即返回FIN,ACK,特别是自HTTP 1.1和持久连接的引入以来。 这些〜5秒似乎是原点上的一个空闲计时器。

这两件事情都在这里证实: https : //en.wikipedia.org/wiki/HTTP_persistent_connection – 包括在Apache 2.2或更新的默认5秒空闲超时。

build议解决scheme

如果不了解更多有关基础设施的知识,我无法真正提出解决scheme,但粗略地说,您有几个select:

  • 调查为什么客户端需要5秒钟发送第二个请求。 缺点:耗时,可能意味着应用程序的变化。
  • 将原点(Apache?)超时增加到10秒。 缺点:在保持更多资源闲置时需要扩展的问题。 可能需要更改应用程序以尽快处理连接。
  • 不要通过发出“连接:closures”标题来重复使用第二个HTTP请求的TCP连接。 缺点:每个请求的成本较高,因为您必须build立一个新的TCP会话。 可能会导致应用程序更改发出所有请求上的标题或Nginx上的更改,从而偏离您的默认configuration(增加pipe理成本)。
  • 在上游configuration中使用Nginx上的“keepalive”选项来设置keepalive低于5秒。 缺点:很多额外的交通/噪音。

希望这可以帮助 :)