web-dev-qa-db-ja.com

Nginxリバースプロキシにより、ファイルのダウンロードの開始に時間がかかりすぎる

概要概要

私のWebアプリを使用すると、ユーザーはサーバーを介してs3に保存されているファイルをアップロードできます。ユーザーがファイルを要求すると、私のWebサーバーはs3からファイルを取得し、クライアントに送信します。

最近、ロードバランサーをデプロイして、現在のセットアップを次のようにしています。

Web app Server setup

現在、デバッグを簡素化するためにWebサーバーが1つしかないことに注意してください。

初期の問題

ロードバランサーをデプロイした後、大きなファイル(約4 MBより大きいもの)のダウンロードが失敗し、60秒後に504ゲートウェイがタイムアウトすることに気付きました。

サイトのロードバランサーのnginxエラーログを確認したところ、次のようなエントリがいくつか表示されていました。

[error] 11770#11770: *40 upstream timed out (110: Connection timed out) while reading response header from upstream, client: XXXX, ...

サイトのWebサーバーnginxエラーログを見ると、同様のエントリが見つかりました。

[error] 6632#6632: *41 upstream timed out (110: Connection timed out) while reading response header from upstream, client: ...
[error] 6632#6632: *85 upstream timed out (110: Connection timed out) while reading response header from upstream, client: ...
[error] 7163#7163: *41 recv() failed (104: Connection reset by peer) while reading response header from upstream, client: ...
[error] 7505#7505: *41 recv() failed (104: Connection reset by peer) while reading response header from upstream, client: ...
[error] 7505#7505: *91 recv() failed (104: Connection reset by peer) while reading response header from upstream, client: ....

そして、私が持っていたWebサーバー上のphp-fpmエラーログを見てください。

WARNING: [pool www] child 3011, script '/home/forge/XXX.com/public/index.php' (request: "GET /index.php") execution timed out (64.950545 sec), terminating
WARNING: [pool www] child 3011 exited on signal 15 (SIGTERM) after 1140.059968 seconds from start
WARNING: [pool www] server reached pm.max_children setting (5), consider raising it
WARNING: [pool www] child 4260, script '/home/forge/XXX.com/public/index.php' (request: "GET /index.php") execution timed out (68.171099 sec), terminating
WARNING: [pool www] child 4260 exited on signal 15 (SIGTERM) after 160.005837 seconds from start
NOTICE: [pool www] child 4271 started

私はこれをphp実行タイムアウトとnginx接続タイムアウトが低すぎないようにしたので、次のようにしてそれらを増やしました:

  • ロードバランサーの場合:
    • proxy_read_timeout 600s;を/etc/nginx/nginx.confに追加します
  • Webサーバー上:
    • Nginxサイト構成で、.phpロケーションブロックにfastcgi_read_timeout 600;を追加しました。
    • Php-fpm構成にmax_execution_time = 600default_socket_timeout = 600を追加しました。
    • /etc/php/7.0/fpm/pool.d/www.confにrequest_terminate_timeout = 300を追加しました

これにより、最初の問題がある程度修正され、より大きなファイルをダウンロードできるようになりました(最大25 MBでテスト済み)。

次の問題-ダウンロードが遅い

上記の構成変更後、タイムアウトなしでファイルをダウンロードできますが、ダウンロードの開始に過度の時間がかかり(〜300秒)、実際のダウンロード自体が遅くなります(軽微な懸念)。

ファイルをダウンロードするためのフローは次のとおりです。

  • クライアントがサーバーにアクセスするURIリンクをクリックする
  • 私のWebサーバーはデータベースにアクセスし、ハッシュファイル名やdbサーバーのパスなどの情報を取得します。
  • 次に、WebサーバーはS3からファイルを取得します。
  • Webサーバーは、最初の要求に対するダウンロードとしてファイルで応答します。

参考までに、これを行うためにWebサーバーで実行されている関数は次のとおりです。

public function show($projectID, $documentID, $revisionID, $fileID)
{
    $fileEntry = File::find($fileID);

    $path = $fileEntry->path();
    $file = Storage::get($path);
    $size = Storage::size($path);

    return Response::make($file, 200)
            ->header('Content-Type', $fileEntry->mime)
            ->header('Content-Disposition', 'attachment; filename="' . $fileEntry->original_filename . '"')
            ->header('Content-Length:', $size);
}

私はファイルを二重に処理しており、将来的に署名されたs3 URLリダイレクトに切り替えることを理解していますが、これが実用的ではないアプリケーションの他の部分があります(ファイルのコレクションを取得し、圧縮してクライアントに送信します)。ある程度の理解を得るのが好きです。

この問題の原因は何でしょうか?ロードバランサーをデプロイする前にこの問題が発生したことはないと思います。

S3から直接ファイルをダウンロードする場合、ダウンロード時間はサーバー経由でアクセスするときの全体的な時間のほんの一部であるため、二重処理が問題になるとは思われません。バッファまたはメモリサイズに関連している可能性がありますか?

追加情報:

  • プロビジョニングとサーバーに使用されるLaravelフォージ。
  • ロードバランサーでのSSLターミネーション
  • Laravelウェブアプリ
  • Linodeはすべてシンガポールのデータセンターでホストされています
  • S3リージョンはシドニーです
  • 非常に低いトラフィック(1クライアントまで)で問題が観察されました
2
cubiclewar

素敵な編集、物事ははるかに明確です。

これはPHPのアプリケーションタイムアウトのようです。私の推測では、PHPは、大きなファイルを直接ストリーミングするのではなく、一時的な場所に完全にダウンロードしてから返すことです。これは遅延の原因ですが、速度が遅いことはそれほど多くありません。 。直接ストリーミングがS3からスタックを介して直接実用的であるかどうかさえわかりません-必要に応じて調査してください(あなたが)。PHP5が違いを生むかどうかも確認します。PHP7の信頼性が低いことがいくつかあります。エッジケース。

リクエストが届き、各サーバーにヒットし、各サーバーから応答が返される正確なタイミングを追跡して、リクエストを完全に追跡できるようにします。これは特にPHPレイヤーで、アプリサーバーがリクエストを受信したとき、S3からフェッチしたとき、クライアントに送り返し始めたときのログを追加します。

ダウンロード速度は少し不可解です。 PHPサーバーとS3の間の速度をテストする方法を見つけます-カールか何かをします-それは単純な帯域幅の問題、または利用可能な帯域幅を減らす待ち時間である可能性があります。回避策は次のとおりです。 CloudFrontを使用しますが、おそらく使用しないでください。これにより、ダウンロードが最初ではなく2回要求されたときにのみ加速されます。

これをすべて行った後、うまくいかなかった場合は、発見した情報を投稿してください。特に、いくつかのリクエストが各レイヤーにヒットした正確な時間と、応答が返される時間です。

1
Tim