私はjailを備えたFreeBSDマシンを持っています。具体的には、1つはnginxを実行し、もう1つはJetty(埋め込みモード)経由でリクエストを受け入れるJavaプログラムを実行します。
Jettyは常に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
- 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;
編集2:Jetty に 経由で接続を閉じるように強制してもrequest.getConnection().getEndPoint().close()
何も起こりません。接続が閉じられていることは明らかです ( にあるようにLAST_ACK
) が、なぜこれを超えないのでしょうか。何らかの理由で Nginx がバックエンドへの接続を開いたままにしているのでしょうか。
答え1
さて、ついにジェティを説得して優しく遊ばせることができました。
要約すると、マシン全体の接続は現在次のようになります。
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();
}
( クライアントに送信するのは最大 1 行だけなので、特別な処理は必要ありません )
しかし、それでもサーバー全体がLAST_ACKでいっぱいになってしまうのです...これらを最終的に消すことができたのは、有効にすることでしたSO_LINGER
(そしてタイムアウトなしでソケットを強制的にすぐに閉じるようにしました)
connector.setSoLingerTime(0);