nginx + Jetty - 數千個連線陷入 LAST_ACK

nginx + Jetty - 數千個連線陷入 LAST_ACK

我有一台帶有監獄的 FreeBSD 機器——特別是兩個,一個運行 nginx,另一個運行通過 Jetty 接受請求的 Java 程式(嵌入模式)

Jetty 不斷收到每秒 500 個以上的請求,最近出現了一個問題,我會不斷收到超過 500 個請求/秒的請求。60,000nginx 和 jetty 之間處於 LAST_ACK 狀態的連線。

所有連接的分佈(包括一些其他服務,特別是 php-fpm)

root@host:/root # netstat -an > conns.txt
root@host:/root # cat conns.txt | awk '{print $6}' | sort | uniq -c | sort -n
18 LISTEN
112 CLOSING
485 ESTABLISHED
650 FIN_WAIT_2
1425 FIN_WAIT_1
3301 TIME_WAIT
64215 LAST_ACK

nginx -> jetty 連線分佈

root@host:/root # cat conns.txt | grep '10.10.1.57' | awk '{print $6}' | sort | uniq -c | sort -n
1 
3 CLOSE_WAIT
3 LISTEN
18 FIN_WAIT_2
125 ESTABLISHED
64193 LAST_ACK

我希望每個請求都完全關閉連線。客戶端請求彼此相隔約 10 分鐘,因此必須關閉連線。

一些連接,

tcp4       0      0 10.10.1.50.46809       10.10.1.57.9050        LAST_ACK
tcp4       0      0 10.10.1.50.46805       10.10.1.57.9050        LAST_ACK
tcp4       0      0 10.10.1.50.46797       10.10.1.57.9050        LAST_ACK
tcp4       0      0 10.10.1.50.46794       10.10.1.57.9050        LAST_ACK
tcp4       0      0 10.10.1.50.46790       10.10.1.57.9050        LAST_ACK
tcp4       0      0 10.10.1.50.46789       10.10.1.57.9050        LAST_ACK
tcp4       0      0 10.10.1.50.46771       10.10.1.57.9050        LAST_ACK
etc..
  • 在 Jetty 端,我設定maxIdleTime為 2000——在此之前所有連接都已連接,ESTABLISHED但現在已連接LAST_ACK
  • 在碼頭的一端我已經設置了Connection: close(即response.setHeader(HttpHeaders.CONNECTION, HttpHeaderValues.CLOSE);
  • Jetty 從來不會報告大量的開放連接——總是很少。
  • PF/IPFW 目前未使用
  • nginx -reset_timedout_connection已開啟

我不知道如何讓 nginx 或 jetty 強制關閉連接,這是否只是需要在 Jetty 中修復,以便在請求完成後完全關閉套接字?

預先非常感謝

編輯:忘記了代理設定的 nginx 設定 -

    proxy_pass              http://10.10.1.57:9050;
    proxy_set_header        HTTP_X_GEOIP $http_x_geoip;
    proxy_set_header        GEOIP_COUNTRY_CODE $geoip_country_code;
    proxy_set_header        X-Real-IP $remote_addr;
    proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header        Host $http_host;
    proxy_set_header        Connection "";
    proxy_http_version      1.1;

編輯2:強制 Jetty 通過 關閉連接request.getConnection().getEndPoint().close()不會執行任何操作 - 很明顯連接已關閉(如 中所示LAST_ACK),但為什麼它沒有超越這一點? Nginx 是否因為某些原因保持對後端的連線開放?

答案1

好吧,我終於能夠說服 Jetty 打得很好了。

回顧一下,這是我現在機器範圍內的連結:

24 LAST_ACK
36 CLOSING
117 FIN_WAIT_2
175 ESTABLISHED
351 FIN_WAIT_1
4725 TIME_WAIT

以及 nginx 和 Jetty 之間

1 FIN_WAIT_2
3 LISTEN
14 ESTABLISHED

我已經使用這種方便的方法關閉了整個連接並EndPoint(調用close()關閉EndPoint底層SocketChannel):

private void finishRequest(String message, Request baseRequest, HttpServletResponse response) throws IOException {
    ByteArrayISO8859Writer writer = new ByteArrayISO8859Writer(1500);
    writer.write(message);
    writer.flush();

    // set the content length
    response.setContentLength(writer.size());

    // write the response
    OutputStream outputStream = response.getOutputStream();
    writer.writeTo(outputStream);

    // close the streams
    outputStream.close();
    writer.close();
    baseRequest.getConnection().getEndPoint().close();
}

(我只向客戶端發送最多一行,所以不需要任何花哨的東西)

然而,這仍然導致整個伺服器充滿了 LAST_ACK ...使這些最終消失的是啟用SO_LINGER(並使其立即強制關閉套接字,沒有超時)

connector.setSoLingerTime(0);

相關內容