web-dev-qa-db-ja.com

nginx + Jetty-何千もの接続がLAST_ACKでスタックしています

私はjailを備えたFreeBSDマシンを持っています-特に2つはnginxを実行し、もう1つはJetty(組み込みモード)を介してリクエストを受け入れるJavaプログラムを実行します

Jettyは常に500リクエスト/秒以上を受信しますが、最近、nginxとjettyの間のLAST_ACK状態で常に接続が60,0を超えるという問題が発生しています。

すべての接続の配布(他のいくつかのサービス、特に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の分布->桟橋接続

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になっています。
  • Jettyの側では、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;

EDIT2: Jettyにrequest.getConnection().getEndPoint().close()を介して接続を強制的に閉じることは何もしません-接続ISが閉じられていることは明らかです(LAST_ACKにあるため)がなぜこれを超えないのですか?Nginxは何らかの理由でバックエンドへの接続を開いたままにしていますか?

2
virulence

さて、私はついに桟橋に上手にプレーするよう説得することができました。

要約すると、マシン全体での接続は次のようになります。

_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
_

私はすでに接続全体を閉じており、次の便利なメソッドを使用してEndPointEndPointclose()を呼び出すと、基になる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();
}
_

(私はクライアントに最大1行しか送信しないので、特別なことは何も必要ありません)

ただし、これでもサーバー全体がLAST_ACKでいっぱいになりました...これらが最終的に消えたのは、_SO_LINGER_を有効にすることでした(そして、タイムアウトなしですぐにソケットを強制的に閉じるようにしました)

_connector.setSoLingerTime(0);
_
0
virulence