web-dev-qa-db-ja.com

部分的に閉じられた接続に上流にデータを送信しようとした後にプロキシによって生成されたHTTP 502応答(リセットパケット)

プロキシサーバーから散発的な502が返されます。パケットフローを調べると、nginxがPOSTリクエストをソケットに送信しており、Originサーバーがすでに[FIN、ACK]を送信している)リクエストを確認しています。それはオリジン(応答を送信してから5秒後にのみFIN、ACKを送信します)またはプロキシの問題ですか?

これは問題を説明するPCAPのスクリーンショットです: enter image description here

私の理解:

  • オリジンからの応答は[PSH、ACK]です。
  • プロキシは、その[P.]で受信したデータに対して[ACK]を送信します(wiresharkは、次の[ACK]が以前に受信した[PSH-ACK]に対するものであることを確認します)。
  • 7秒経過しました(タイムスタンプbtw/[FIN、ACK]と私たちのPOST([PSH、ACK]))に注意してください);
  • Originは[FIN、ACK]を送信します。最初の[FIN、ACK]が送信されると、Origin TCP=状態マシンはFIN_WAIT_1状態でなければなりません。
  • 次に、Originが[PSH、ACK]を期待していなかったので、別のPOSTを引き起こして[RST]を返します。

質問:

  • この場合の考えられる説明は何ですか?
  • プロキシ(nginx)がすでにFINを受信し、実際にそれを確認しているのに、なぜ別のリクエストを送信するのですか? (POST [PSH、ACK]パケットのACK番号は、実際には[FIN、ACK]のSEQ_NUMBER + 1であるため、ファントムビットFINを確認しています。
  • Originがすぐにではなく5秒後にのみ[FIN、ACK]を返す可能性のある理由は何ですか?読み取りタイムアウト/アイドルタイムアウト?

私はオリジンを所有していないので、そこでキャプチャすることはできません。

追加の詳細:

プロキシのエラーログ(nginxエラーログ):

2017/04/17 06:51:07 [error] 123091#0: *225010841 upstream prematurely closed connection while reading response header from upstream, client: X.90.10, server: www.example.com, request: "POST /web/?a=b HTTP/1.1", upstream: "http://X.32.238:80/web/?a=b", Host: "www.example.com"

このスクリーンショットでは、最後のリクエストのSEQ番号とACK番号が示されています。

enter image description here

この場合の考えられる説明は何ですか?

オリジンの約5秒のアイドルカウンターと、さまざまなクライアント側のアクティビティの間の競合状態。 3番目に関係する変数は、もちろんネットワーク遅延です。

Originには〜5秒のアイドルタイマーがあるようですが、クライアントがNginxプロキシ経由で2番目のリクエスト(POST)を行うのに〜5秒かかります。前者が後者よりも長い場合(ネットワーク遅延を含む)、問題はありません。クライアントリクエストが送信されるまでに少し時間がかかる場合は、問題があります。

POSTとNginxからのFIN、ACKの両方がどのようにほぼ一緒に送信されるかを確認できます:OriginのFIN、ACKのそれぞれ2.4msと2.6ms後。これはあなたを先延ばしにする可能性がありますPOSTは、OriginのFIN、ACKに対する応答です。OriginのFIN、ACKの2.4ms後に送信されるため、ここで追跡します。

プロキシ(nginx)がすでにFINを受信し、実際にそれを確認しているのに、なぜ別のリクエストを送信するのですか? (POST [PSH、ACK]パケットのACK番号は、実際には[FIN、ACK]のSEQ_NUMBER + 1であるため、ファントムビットFINを確認しています。

POSTパケットのACK番号は、おそらく「200 OK」パケット用です。そのHTTP応答の後にサーバー側から来る余分なデータはないため、クライアントからのACKはすべてACKします同じ数。

更新:POSTパケットのACK番号が1増加していることがわかったので、Nginxは[ FIN、ACK]。さらに調査すると、これは問題ないことがわかります。マシンは、送信する予定だったリモート側からの応答を受信した後、接続を続行する予定がない場合、要求を送信して[FIN、ACK]で終了する場合があります。データを要求し、[FIN、ACK]プロセスを続行して終了しました。

これは、Originがアイドル状態の5秒後に接続を閉じることを決定したため、POST直後に来るパケット(およびRSTを送り返すことさえ) -ただし、このRSTが送信されたかどうかは不明です)。

Originがすぐにではなく5秒後にのみ[FIN、ACK]を返す可能性のある理由は何ですか?読み取りタイムアウト/アイドルタイムアウト?

特にHTTP 1.1と永続的な接続の導入以来、FIN、ACKをすぐに返す必要はありません。これらの約5秒は、Originのアイドルタイマーのようです。

両方のことがここで確認されています: https://en.wikipedia.org/wiki/HTTP_persistent_connection -Apache2.2以降のデフォルトの5秒のアイドルタイムアウトを含みます。

推奨されるソリューション

インフラストラクチャについての知識がなければ、実際にソリューションを提案することはできませんが、大まかに言うと、いくつかのオプションがあります。

  • クライアントが2番目の要求を送信するのに5秒かかる理由を調査します。欠点:時間がかかり、おそらくアプリケーションの変更を意味します。
  • Originの(Apache?)タイムアウトをおそらく10秒に増やします。欠点:より多くのリソースをアイドル状態に保つと、スケーリングの問題が発生します。接続をできるだけ早く破棄するには、アプリケーションの変更が必要になる場合があります。
  • "Connection:Close"ヘッダーを発行して、2番目のHTTPリクエストでTCP接続を再利用しないでください。欠点:新しいTCPセッション。すべてのリクエストでヘッダーを発行するためのアプリケーションの変更またはNginxでの変更が必要になる可能性があるため、デフォルトの構成から逸脱します(管理コストの増加)。
  • アップストリーム構成内のNginxで「キープアライブ」オプションを使用して、キープアライブを5秒未満に設定します。欠点:多くの余分なトラフィック/ノイズ。

お役に立てれば :)

3
Pedro Perez

これは、アップストリームサーバーのソケットキープアライブタイムアウトが原因であると思います。ソケットは閉じられ、デフォルトのsocket.setsolingerは開きません。

Nginxアップストリームサーバーのキープアライブタイムアウトを許可できると思います。別の作成者が解決しました。 this を参照してください。

0
sdcuike