Nginx proxy_read_timeout vs.proxy_connect_timeout


15

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

サービスは時々かなり遅くなる場合があります(JavaとJVMでの実行は「フルガベージコレクション」でスタックすることがあり、数秒かかる場合があります)proxy_connect_timeout。2秒に設定しました。サービスがGCでスタックし、時間内に応答しないため、別のサーバーに要求を渡す必要があることを確認します。

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

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

問題はproxy_read_timeout + proxy_connect_timeout、サービスがスタックし、Nginxがアクセスしようとしたときに接続を受け入れない場合、Nginxがタイムアウトする前にタイムアウトする、またはほぼその時間のタイムアウトが発生するリクエストがあることです。処理を開始しますが、速度が遅すぎるため、読み取りのタイムアウトのためにNginxが中断します。サービスにはそのような場合があると思いますが、いくつかのベンチマークを実行して、合計数百万のリクエストがあります-上記のいずれかで返される単一のリクエストを見ることはできませんでしたproxy_read_timeout(タイムアウトが大きい)。

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


1
NGINXのバージョンは何ですか?私は古いバージョン(おそらく約0.6 / 7)で似たようなことを覚えていると思いますが、より新しいバージョン(最新の安定バージョンは1.0.5)で修正されましたが、それは間違っているかもしれません。それでもバージョンが役立つとわかっている場合
11

docs proxy_read_timeoutは「グローバルタイムアウト」ではなく、2つの読み取り操作の間にあることに注意してください。
poige

@Sam:Nginx 1.0.0を使用しています。@poige-はい、私はそれを知っていますproxy_read_timeout + proxy_connect_timeout。だからこそ、合計タイムアウトがになると思っています。
ガス

1
サイドノートとして、おそらくJVMの同時ガベージコレクションチューニングを調査する必要があります。en.wikipedia.org/ wiki
多項式

@polynomial:私たちはやったが、私たちのベンチマークに応じてより多くのCPU時間の同時ガベージコレクション機能の結果は、「世界を停止する」GC、それゆえ我々はnginxのチューニングに投資することを好む:-)と比較して、全体的なGCに失われた
GUSS

回答:


18

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

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つのテストサーバーをセットアップしました。SYNでタイムアウトするものと、接続を受け入れるが応答しないものがあります。

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';

1
あなたのシナリオにおける上記の私の質問はもっと似ています:0から20秒の間のランダムな時間の後に接続を受け入れ、応答する前に19秒から21秒の間のランダムな時間を待つテストサーバーを想定します。次に、単純なベンチマークを実行します。リクエストの約50%が10秒のタイムアウトで、25%が20〜30秒のタイムアウトで、25%が正常な応答を受け取ると予想しています。このような場合、成功するリクエストの完了には20秒以上かかりますか?私のベンチマークでは、どれもそうではありません-それが私を悩ませています。
ガス

私は、SYNでランダムな損失を設定し、約50秒間本当にゆっくりとラインを吐き出すCGIをテストしました。両方のタイムアウトを合わせたものよりもはるかに長い時間がかかるリクエストを確認できましたが、それでも成功しています:box.access.log 200:69.814:67.100:。:1579 33 127.0.0.1 test.host-[21 / Aug / 2011:20: 30:52 -0700] "GET / huugs HTTP / 1.1" " - " " - " " - " dev_edge 127.0.0.1:2280 -
多項式

わかりました、それはまったく異なるレベルで奇妙です:-)。考えられる説明の1つは、Nginxがリクエスト(proxy_send_timeout)を書くのに時間がかかることです、そしてそれをより高く設定したのでproxy_connection_timeout、それは実際に20秒以上の遅延を説明できますproxy_read_timeout。「本当にゆっくりとラインを吐き出しなさい」と言うとき、あなたはどういう意味ですか?
ガス

応答の本文でHTMLの行を印刷する間、sleep 1。proxy_read_timeoutが読み取り全体ではなく読み取りの間である方法を公開するだけです。
多項式

1
ああ、分かった。まあ、これは間違いなく私の場合ではなく、私のOPでそれを明確にしないでごめんなさい。私の場合、アプリケーションサーバーは、あらゆる種類の応答を返す前に処理全体を完了し、すべてを一度に返します。したがってproxy_read_timeout、リクエストは完全に失敗するか、完全に許可されます。これは、表示される動作と表示される動作の違いについても説明しています。
ガス

3

問題は、proxy_read_timeout + proxy_connect_timeoutの後、またはNginxがアクセスしようとしたときに接続を受け入れないがNginxがタイムアウトする前に接続を受け入れない場合、ほぼその時間の長さでタイムアウトするリクエストが表示されることです。解放されて処理を開始しますが、速度が遅すぎるため、読み取りタイムアウトのためにNginxが中断します。

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

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


私はこれが私が尋ねていることとまったく同じではないと思います-質問は次のとおりです。アップストリームがスタックし、1.999秒後にSYN_ACKを返す場合、なぜnginxは現在のアップストリームでプロセスを続行しないのですか
ガス

正確に確認したい場合は、スニファーを使用できます。2秒未満でACKがまったくないことが判明する場合があります。
poige

スニファーを実際に使用することはできません。これは、システムに高負荷がかかる場合にこの動作が発生することを期待しているためです。数百万のリクエストを考慮したとしても、いくつかのXの後にACKがなく、2秒よりも前にACKがないという説明は信じがたいようです。
GUSS
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.