web-dev-qa-db-ja.com

Nginx proxy_read_timeoutとproxy_connect_timeoutの比較

Nginxを、ある種のサービスを提供する一連のサーバーのリバースプロキシとして使用し始めました。

サービスは時々かなり遅くなる可能性があります(Javaで実行され、JVMが数秒かかる「フルガベージコレクション」でスタックする場合があります)。したがって、proxy_connect_timeoutを2秒にすると、NginxはサービスがGCでスタックし、時間内に応答しないことを理解するのに十分な時間が与えられ、リクエストを別のサーバーに渡す必要があります。

また、proxy_read_timeoutを設定して、サービス自体が応答を計算するのに時間がかかりすぎた場合にリバースプロキシがスタックしないようにしています-もう一度、要求を別のサーバーに移動して、タイムリーに返すのに十分な空きがある必要があります応答。

いくつかのベンチマークを実行しましたが、サービスがスタックして着信接続を受け入れないため、一部のリクエストは接続タイムアウトに指定された時間に正確に戻るため、proxy_connect_timeoutが正しく機能していることがはっきりとわかります(サービスはJettyを埋め込みサーブレットコンテナとして使用する)。 proxy_read_timeoutも機能します。そこで指定されたタイムアウト後にリクエストが返されることがわかります。

問題は、サービスがスタックしていて、Nginxがアクセスを試みたときにNginxがアクセスできるようになる前に接続を受け入れない場合、proxy_read_timeout + proxy_connect_timeoutまたはほぼその時間後にタイムアウトするいくつかの要求が表示されると予想していたことです。タイムアウト-解放されて処理を開始しますが、速度が遅すぎるため、読み取りタイムアウトのためにNginxが異常終了します。サービスにはそのようなケースがあると思いますが、いくつかのベンチマークを実行した後、合計で数百万のリクエストが発生しました。proxy_read_timeout(タイムアウトが長い)を超えるものを返す単一のリクエストを確認できませんでした。

この問題についてコメントをいただければ幸いですが、接続後にタイムアウトカウンターがリセットされないというNginxのバグが原因である可能性があります(まだコードを確認していないため、これは単なる前提です)。 Nginxがアップストリームサーバーから何も読み取らなかった場合、成功します。

16
Guss

私はこれを実際に再現することができませんでした:

2011/08/20 20:08:43 [notice] 8925#0: nginx/0.8.53
2011/08/20 20:08:43 [notice] 8925#0: built by gcc 4.1.2 20080704 (Red Hat 4.1.2-48)
2011/08/20 20:08:43 [notice] 8925#0: OS: Linux 2.6.39.1-x86_64-linode19

私はこれを私のnginx.confに設定しました:

proxy_connect_timeout   10;
proxy_send_timeout      15;
proxy_read_timeout      20;

次に、2つのテストサーバーをセットアップします。 1つはSYNでタイムアウトし、もう1つは接続を受け入れるが応答しないものです。

upstream dev_Edge {
  server 127.0.0.1:2280 max_fails=0 fail_timeout=0s; # SYN timeout
  server 10.4.1.1:22 max_fails=0 fail_timeout=0s; # accept but never responds
}

次に、1つのテスト接続を送信しました。

[m4@ben conf]$ telnet localhost 2480
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
GET / HTTP/1.1
Host: localhost

HTTP/1.1 504 Gateway Time-out
Server: nginx
Date: Sun, 21 Aug 2011 03:12:03 GMT
Content-Type: text/html
Content-Length: 176
Connection: keep-alive

次に、これを示すerror_logを監視しました:

2011/08/20 20:11:43 [error] 8927#0: *1 upstream timed out (110: Connection timed out) while connecting to upstream, client: 127.0.0.1, server: ben.dev.b0.lt, request: "GET / HTTP/1.1", upstream: "http://10.4.1.1:22/", Host: "localhost"

次に:

2011/08/20 20:12:03 [error] 8927#0: *1 upstream timed out (110: Connection timed out) while reading response header from upstream, client: 127.0.0.1, server: ben.dev.b0.lt, request: "GET / HTTP/1.1", upstream: "http://127.0.0.1:2280/", Host: "localhost"

そして、予想される30秒のタイムアウト(10 + 20)を持つaccess.log:

504:32.931:10.003, 20.008:.:176 1 127.0.0.1 localrhost - [20/Aug/2011:20:12:03 -0700] "GET / HTTP/1.1" "-" "-" "-" dev_Edge 10.4.1.1:22, 127.0.0.1:2280 -

これは私が使用しているログ形式で、個々のアップストリームタイムアウトが含まれています。

log_format  Edge  '$status:$request_time:$upstream_response_time:$pipe:$body_bytes_sent $connection $remote_addr $Host $remote_user [$time_local] "$request" "$http_referer" "$http_user_agent" "$http_x_forwarded_for" $Edge $upstream_addr $upstream_cache_status';
19
polynomial

問題は、サービスがスタックしていて、NginxがアクセスしようとしたときにNginxがタイムアウトする前に接続を受け入れない場合、proxy_read_timeout + proxy_connect_timeoutまたはほぼその時間の後にタイムアウトするいくつかのリクエストが表示されると予想していたことです。それは解放されて処理を開始しますが、遅すぎて、読み取りタイムアウトのためにNginxが異常終了します。

接続タイムアウトは、TCPハンドシェイク時にストールする(たとえば、SYN_ACKがなかった)ことを意味します。)TCPは、SYNの送信を再試行しますが、別のサーバーを使用するためにNginxに2秒かかるため、SYN​​を再送信する時間はありません。

PD。:ドキュメントで見つかりませんでしたが、tcpdumpは秒があることを示しています。最初に送信されたSYNと2回目のSYN送信の試行の間の遅延。

3
poige