Networking

代理嘗試向上游發送數據到部分關閉的連接(重置數據包)後生成的 HTTP 502 響應

  • August 12, 2019

我收到代理伺服器返回的零星 502。檢查數據包流時,我看到 nginx 向原始伺服器已發送的套接字發送 POST 請求

$$ FIN,ACK $$. 我想了解這怎麼可能以及任何潛在的解決方案。是源的問題(它僅在發送響應後 5 秒後才發送 FIN、ACK)還是代理的問題? 這是說明問題的 PCAP 螢幕截圖: 在此處輸入圖像描述

我的理解:

  • 來自原點的響應是$$ PSH, ACK $$;
  • 代理髮送一個$$ ACK $$對於接收到的數據$$ P. $$(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 $$數據包實際上是 SEQ_NUMBER + 1 的$$ FIN,ACK $$- 所以它正在確認幻位 FIN。
  • origin返回a的可能原因是什麼$$ FIN,ACK $$僅在 5 秒後而不是立即?讀取超時/空閒超時?

我不擁有原產地 - 所以無法在那裡擷取。

額外細節:

代理上的錯誤日誌(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 秒的空閒計數器與可變的客戶端活動之間的競爭條件。第三個涉及的變數當然是網路延遲。

源站上似乎有一個約 5 秒的空閒計時器,而您的客戶端需要約 5 秒的時間通過 Nginx 代理髮出第二個請求(POST)。如果前者比後者長(包括網路延遲),那麼您就沒有問題。如果發送客戶端請求只需要一點點時間,那麼您就有問題了。

你可以看到來自 Nginx 的 POST 和 FIN,ACK 是如何一起發送的:分別在源的 FIN,ACK 之後 2.4 毫秒和 2.6 毫秒。這可能會讓您偏離正軌,因為我認為 POST 根本不是對來源的 FIN,ACK 的響應。因為它是在源端的 FIN,ACK 之後 2.4ms 發送的

如果代理 (nginx) 已經收到 FIN 並且實際上正在確認它,為什麼還要發送另一個請求!(POST 中的確認號

$$ PSH, ACK $$數據包實際上是 SEQ_NUMBER + 1 的$$ FIN,ACK $$- 所以它正在確認幻位 FIN。

POST 數據包上的 ACK 號很可能是針對“200 OK”數據包的。在 HTTP 響應之後沒有來自伺服器端的額外數據,因此來自客戶端的任何 ACK 都將 ACK 相同的數字。

**更新:**我們現在知道 POST 數據包的 ACK 號增加了 1,所以 Nginx 知道

$$ FIN,ACK $$. 進一步的調查表明這很好:一台機器可能會發送一個請求並以$$ FIN,ACK $$如果它在收到遠端端的響應後不打算繼續連接,誰將發送回請求的數據並以繼續$$ FIN,ACK $$過程。 這並沒有改變這樣一個事實,即源端決定在空閒 5 秒後關閉連接,從而忽略之後不久出現的 POST 數據包(甚至發回 RST - 儘管不清楚這個 RST 是否會’無論如何都已發送)。

origin返回a的可能原因是什麼

$$ FIN,ACK $$僅在 5 秒後而不是立即?讀取超時/空閒超時?

您不必立即返回 FIN,ACK,尤其是在 HTTP 1.1 和持久連接的引入之後。這約 5 秒似乎是原點上的空閒計時器。

這兩件事都在此處得到確認:https ://en.wikipedia.org/wiki/HTTP_persistent_connection - 包括 Apache 2.2 或更高版本中預設的 5 秒空閒超時。

建議的解決方案

在不了解您的基礎架構的情況下,我無法真正提出解決方案,但粗略地說,您有幾個選擇:

  • 調查為什麼客戶端需要 5 秒來發送第二個請求。缺點:耗時且可能意味著應用程序更改。
  • 將原點(Apache?)的超時時間增加到 10 秒。缺點:當您保持更多資源閒置時,問題會擴展。可能需要更改應用程序以盡快處理連接。
  • 不要通過發出“Connection: Close”標頭來為第二個 HTTP 請求重用 TCP 連接。缺點:每個請求的成本較高,因為您必須建立一個新的 TCP 會話。可能需要應用程序更改以發布所有請求的標頭或 Nginx 上的更改,從而偏離您的預設配置(增加管理成本)。
  • 在上游配置中使用 Nginx 上的“keepalive”選項將 keepalive 設置為低於 5 秒。缺點:很多額外的交通/噪音。

希望這可以幫助 :)

引用自:https://serverfault.com/questions/845171