Nginx で proxy_send_timeout は実際に何を行うのでしょうか?

Nginx で proxy_send_timeout は実際に何を行うのでしょうか?

Nginx のドキュメントには、次のように「バックエンド」サーバーに対して設定できる 3 つの異なるタイムアウトに関するディレクティブがあります。

proxy_connect_timeoutプロキシ サーバーとの接続を確立するためのタイムアウトを定義します。このタイムアウトは通常 75 秒を超えることはできないことに注意してください。

これは簡単に理解できます。Nginx は上流の「バックエンド」サーバーに接続しようとしていますが、X 時間内に接続できない場合は接続を中止してエラーを返します。サーバーが到達不能、接続数が多すぎる、などです。

proxy_read_timeoutプロキシされたサーバーからの応答を読み取るためのタイムアウトを定義します。タイムアウトは、応答全体の送信に対してではなく、2 つの連続した読み取り操作の間にのみ設定されます。プロキシされたサーバーがこの時間内に何も送信しない場合、接続は閉じられます。

これも理にかなっています。Nginx はすでに「バックエンド」サーバーとの TCP 接続を確立しており、実際にリクエストを送信しようとしていますが、サーバーの処理に時間がかかっており、X 時間以上かかる場合は接続を閉じてユーザーに戻ります。

実際、Nginx が接続を閉じることに驚きました。接続は維持されるものの、ユーザーにエラーが返されると思っていました。何かがタイムアウトするたびに、これらの「バックエンド」TCP 接続を再確立するのはコストがかかりそうです。

proxy_send_timeoutプロキシ サーバーにリクエストを送信するためのタイムアウトを設定します。タイムアウトは、リクエスト全体の送信に対してではなく、連続する 2 つの書き込み操作の間にのみ設定されます。プロキシ サーバーがこの時間内に何も受信しない場合は、接続が閉じられます。

これはよくわかりません。理論はありますが、誰かに確認してもらいたいです。このタイムアウトの唯一の値は、リクエスト ペイロードが大きい場合 (JSON を含む大きな POST リクエスト、またはユーザーが保存したいドキュメントなど) です。リクエストを「バックエンド」に送信するには、リクエストをより小さな MTU TCP セグメントに分割し、それらを元のリクエストの「チャンク」として送信する必要があります。したがって、技術的には、すべてのチャンクをサーバーに正常に送信するまで、リクエストは実際には送信されません。Nginx はリクエストの各チャンク間の時間を測定していますか? それがドキュメントの「書き込み」の意味ですか? リクエストが実際に送信されると、Nginx は測定を開始しますかproxy_read_timeout?

答え1

TCP/IP はいわゆる「ストリーミング」データ伝送プロトコルです。TCP/IP 接続を介してデータを読み取る側が「セグメント」やパケットのサイズを気にしなくてもよいように設計されています。これは、実際には、ピアがリモート ピアから送信されたデータを取得するために従来の「読み取り」操作を呼び出す状況に相当します (例:readLinux の場合、リモート側が 1 回の「書き込み」操作で提供したデータと同じ量のデータを一度に読み取るとは限りません。TCP/IP プロトコルの実装では、一度に「書き込み」操作に渡されたデータから適切なサイズの IP パケットを作成し、相手側の実装ではそれらのパケットからデータを組み立てますが、必ず同じデータ境界を持つ「読み取り」クライアント アプリケーションに渡す必要があります。

例: A は、外部システム イベントごとに 50Kb のデータを送信する必要があり、一度に RAM に収まらないため、送信バッファーのサイズである 16Kb のチャンクで送信します。最初に 16Kb、次にさらに 16Kb、さらにさらに 16Kb、最後に 2Kb を送信します。TCP/IP 実装は、これらの 50Kb を送信し、内部で 128Kb バッファー (カーネル バッファーなど) にバッファーしてから、ネットワーク経由で送信します。ネットワークにも独自の条件があります。送信アプリケーションが認識できない方法で断片化されたこれらのデータの一部は、ネットワーク条件により、最初に相手側に到着し、TCP/IP 実装によって組み立てられ、再びカーネル バッファーに入れられます。カーネルは、データを読み取ろうとするプロセスを起動し、30Kb すべてを読み取ります。受信側は、さらにデータを期待するかどうか、さらにどのくらい期待するかを判断する必要があります。フォーマット「メッセージ」またはデータの転送は、TCP/IP が考慮するものではありません。

readつまり、たとえば、Nginx は Linux ベースのシステムで実行される呼び出しごとに、クライアントのリクエストを一度にどれだけ読み取るかを知ることができません。

ただし、のドキュメントにproxy_send_timeoutは、それが何のためにあるのかが少しだけヒントとして示されています (強調は私によるものです)。

プロキシ サーバーにリクエストを送信するためのタイムアウトを設定します。タイムアウトは、リクエスト全体の送信に対してではなく、連続する 2 つの書き込み操作の間にのみ設定されます。プロキシサーバーがこの時間内に何も受信しない場合、接続は閉じられます。

問題は、Nginxプロキシリクエスト - つまり、リクエストは起源これにより、アップストリーム接続を介して転送 (書き込み) する前に、「ダウンストリーム」クライアント (Nginx にリクエストを送信した接続のリモート エンド。Nginx は「プロキシ」としての役割で、そのリクエストをアップストリームに転送することを期待しています) がリクエストのデータを送信するのを待機します。

私の理解では、[タイムアウト期間中に] ダウンストリームから何も受信されない場合、プロキシ サーバーも何も受信せず、接続が閉じられます。

言い換えると、ダウンストリームが で指定された時間内に何も送信しない場合proxy_send_timeout、Nginx はアップストリームとの接続を閉じます。

たとえば、Web ブラウザが Nginx にリクエストを送信するとします。最初の部分は、時刻 A に Nginx によって読み取られます。リクエストをアップストリームにプロキシすると仮定すると、Nginx はそのアップストリームへの接続を開き、ブラウザから受信したものをアップストリーム接続ソケット経由で送信 (書き込み) します。その後、リクエスト データの次の部分がブラウザから読み取られるのを待機します。時刻 A を基準としたタイムアウト X が経過しても次の部分が到着しない場合は、アップストリームへの接続が閉じられます。

これは必ずしも Web ブラウザへの接続を閉じることを意味するわけではないことに注意してください。リクエストに対して何らかの HTTP エラー ステータス コードが返されることは確かですが、Web ブラウザの接続の有効期間は、後者とは異なる一連の条件によって制御されますproxy_send_timeout。後者は、アップストリームへの Nginx の接続にのみ関係します。

関連情報