1、背景
nginx 作為 nexus 的反向代理,maven 配置的 nexus 地址指向的是 nginx
2、問題
mvn 編譯構建時候出現個別的包或 pom 文件下載返回 502 導致編譯失敗,在同一個 VPC 內的 mvn 客户端不會出現該問題,跨雲賬號通過雲企業網組網訪問的 mvn客户端會出現 502,10 次構建有 8-9 次出現,復現率很高,如果跳過 nginx直接訪問 nexus就沒問題
3、排查過程
nginx日誌如下
{"method":"GET","uri":"/nexus/content/groups/lkb-public/org/codehaus/plexus/plexus-component-annotations/1.5.5/plexus-component-annotations-1.5.5.pom.sha1",
"status":"502",
"X-Forwarded-For":"-",
"response_time":"7.012",
"request_time":"7.009",
"upstream_connect_time":"-",
"upstream_header_time":"-",
"userAgent":"Apache-Maven/3.6.3 (Java 1.8.0_333; Linux 5.15.0-142-generic)","request_length":"370","bodySize":"150","authorization":"-","x-auth-token":"-","EagleEye-TraceID":"-"}
nexus 查看 TCP 連接
netstat -anptu
有 500 多個連接,其中 200 多個 CLOSE_WAITE,其餘是ESTABLISHED
4、故障分析
由於 nginx之前未開啓長連接,默認都是短連接,mvn下載的每一個文件都會創建一個新的 TCP 連接,多個下載不會複用同一個連接,mvn編譯過程有幾百個 pom jar下載就會導致有幾百個 TCP 連接建立,這個數值對於 linux系統而已未達瓶頸,但是對 nexus而言已經到了它連接池的上線了,滿了之後新的請求過來只在等待隊列裏面,不會處理請求,nginx會對於這種建立 TCP 連接後無響應的連接在過了幾秒鐘後判斷為連接不可用或異常遂返回 502
5、解決
nginx增加如下配置參數
upstream repo{
;
# 新增:長連接複用配置(解決偶發連接中斷)
個空閒長連接
keepalive_timeout 60s; # 空閒連接超時(與 Nexus 適配)
; # 單個長連接最大處理請求數
}
...location / {
proxy_pass http://repo;
# 新增:啓用 HTTP/1.1 長連接(核心修復偶 502)
proxy_http_version 1.1;
proxy_set_header Connection ""; # 清空 Connection 頭,啓用 keepalive
}...
相關配置解釋
proxy_http_version 1.1; proxy_set_header Connection ""; 為了開啓長連接,可以理解為開關,但是僅僅如此還不夠,只是每次連接後 TCP 不會關閉,不會讓多個請求複用同一個 TCP 連接
keepalive 32; 是關鍵,永遠有 32 空閒 TCP 長連接存在,請求進來都複用這 32個,如果單個最大處理 100 個(keepalive_requests 100;)打滿後可以在 32 基礎上新增連接,沒有上限。如果沒有請求了,也不會釋放所以連接會保留 32 個,避免頻繁新建 TCP,較少三次握手等開銷
6、相關擴展
502 與 504 區別
502 和 504 是 Nginx 反向代理場景下最常見的兩個錯誤碼,核心區別在於 錯誤觸發的階段和原因:
- 502 = 上游服務器「連接失敗 / 處理異常」(網關能連但上游 “壞了”);
- 504 = 上游服務器「連接成功但響應超時」(網關連得上但上游 “太慢 / 沒回應”)。
結合你的 Nexus 代理場景(跨 VPC、長連接 / 短連接、超時配置),用「通俗類比 + 技術拆解 + 場景對應」的方式,把兩者的區別講透:
核心區別總表(一目瞭然)
TCP 中的 CLOSE_WAIT 、TIME_WAIT 存在場景
TCP 連接的建立(三次握手)和關閉(四次揮手)過程中,客户端與服務端會經歷一系列明確的狀態變遷。這張圖能清晰展示完整流程與對應狀態:
TCP 三次握手(建立連接)
- 客户端:從
CLOSED發起連接,發送SYN包後進入SYN_SENT狀態,等待服務器確認。 - 服務端:在
LISTEN狀態下收到SYN包,回覆SYN+ACK包後進入SYN_RCVD狀態。 - 客户端:收到
SYN+ACK後,發送ACK包並立即進入ESTABLISHED狀態。 - 服務端:收到最終的
ACK包後,也進入ESTABLISHED狀態,雙方開始傳輸數據。
TCP 四次揮手(關閉連接)
- 主動關閉方(如客户端):發送
FIN包,進入FIN_WAIT_1狀態,等待對方的ACK。 - 被動關閉方(如服務端):收到
FIN包後發送ACK確認,進入CLOSE_WAIT狀態(此時仍可發送剩餘數據)。 - 主動關閉方:收到
ACK後進入FIN_WAIT_2狀態,等待對方的FIN包。 - 被動關閉方:完成數據發送後,發送自己的
FIN包,進入LAST_ACK狀態,等待最後的ACK。 - 主動關閉方:收到
FIN包後發送ACK確認,並進入TIME_WAIT狀態(等待 2MSL 時間,確保對方收到ACK)。 - 被動關閉方:收到最終的
ACK後,立即進入CLOSED狀態。 - 主動關閉方:
TIME_WAIT超時後,進入CLOSED狀態,連接徹底關閉。
核心狀態速查表
根據上述分析,time_wait屬於正常情況,如果有大量短鏈接的話由於有釋放時長(2MSL)短期內會有大量的此種狀態
close_wait如果大量存在屬於異常狀況,説明被動關閉接收方沒有進行後續的回包