ビデオの配布。 待ち伏せ:nginxまたはphp?

ビデオコンテンツの配信の実装における私の小さな経験を共有したいと思います。



だから



視聴用にビデオコンテンツ配信するサービスがあります(つまり、ダウンロードは提供されません)。 同時に、すべてのコンテンツは2つのカテゴリに分けられます。



1-完全な形(フルファイル)/一時停止、巻き戻し。

2-[最初のファイルの終わり] + [完全にいくつかの数のファイル] + [最後のファイルの始まり]という形式の1つの「仮想ファイル」が与えられます。 形式はmpegtsで、各セットは同じ方法でエンコードされるため、パーツを接着するだけです。



これら2つのカテゴリは論理的に異なり(完全に異なるもの)、明確に異なるURIを持ち、物理的に異なる場所にあります。



当初提案されたように



nginx + apacheの束。



最初のカテゴリーは、少し調整したnginxのコンテンツの平凡な分布です。

2番目の部分-ループを使用したapache-phpスクリプト



while(!feof($fp)){ ... echo fread($fp, $buf) ... }
      
      





ここで、$ fpは、必要な場所で実行されたfseek()を持つファイルへのポインターです。



好きではなかったもの



判明したように、nginxは、多数の範囲バイトのリクエストを持つ静的変数の配布にはあまり適していません(つまり、そのようなリクエストは主にオンライン表示中に取得されます)。 AIOを使用してこのような要求を処理する方法はありません。 その結果、ディスクへの長いキューが形成され、ビデオを視聴している顧客には「ブレーキ」が伴うことがよくあります。 多数のバッファを設定することは無意味です-ただメモリを浪費します。



最新バージョンのnginx(現時点では1.12.2)、-with-file-aio、-with-threadsなど、さまざまなものを試しました。 効果は受けられません。



さて、PHPの "echo fread()"の束も非常に疑わしいです。 freadの出力は中間phpバッファーに送られるため、スクリプトはこのバッファー以上のメモリを消費します。 ファイルを少しずつ読み込むと、CPUの負荷が増加し、アップロード速度が低下します。 大きなチャンクで読み取る場合、各リクエストは大量のメモリを消費します。



最終的に何が起こったのか



まあ、まず第一に私はApacheを拒否した。 代わりにphp5-fpm。 これにより、速度(応答速度)が大幅に向上し、メモリ消費が削減されました。



最初のカテゴリー



内容は、実験のために、スクリプトで配布することにしました。



nginxの場合:



  location ~* /media/.*\..* { fastcgi_pass unix:/var/run/php5-fpm.sock; include /etc/nginx/sites-available/fastcgi_params; fastcgi_param SCRIPT_FILENAME /var/www/m_download.php; root /var/www; send_timeout 1h; }
      
      





m_download.phpを完全には提供しません。 主な機能:



 fpassthru($fd);
      
      





ここで、$ fdはファイルポインターです。 もちろん、最初にHTTP_RANGEヘッダーを解析し、ファイルを開いてオフセットを設定する必要があります。



fpassthru()は、「現在から最後まで」ファイルを提供します。 この状況では、非常に適しています。 すべてのプレイヤーが正しくプレイします。



驚いたことに、この特定の返品方法により、必要な結果が得られました。 ディスク用のキューはありません(より正確には、システムが使用されますが、SAS-3 12Gb /秒で、10ms未満の待機で一般に良好です)。 したがって、要求処理を待つ必要はありません。 ファイルのアップロード速度(ダウンロードされた場合)-約250メガビット/秒。 顧客の「ブレーキ」は完全になくなりました。



同時に、メモリ使用量が大幅に削減されるため、ファイルキャッシュの残りが増えます。 スクリプト自体は、実行中に約0.5 MBのプライベートメモリを消費します。 実行可能コードはまだメモリ内に1つのコピーで存在するため、サイズは重要ではありません。



第二のカテゴリー



(これは、いくつかの異なるファイルを成形する必要がある場所です)も変更されました。



「echo fread()」の束を拒否しました。



残念ながら、phpにはファイルの任意の部分を直接出力する機能はありません。 fpassthru()には「出力する量」というパラメーターはなく、常に「最後まで」と表示されます。



システムddをpassthru()で呼び出してみました。

すなわち:



 passthru('/bin/dd status=none if='.$fffilename.' iflag="skip_bytes,count_bytes" skip='.$ffseek.' count='.$buf_size);
      
      





そして...ああ奇跡! スクリプトのメモリ消費量は0.5 MBをわずかに超えています。任意のバッファサイズを設定できます(メモリには影響しません)。 戻り率(4 MBのバッファーを使用)...ホイッスル(同じ250 Mbit / s)。



ここに物語があります。 その結果、nginxのみのコンテンツの配信を放棄しなければなりませんでした。 これは、リクエストをphp5-fpmにリダイレクトするためにのみ使用されます。



手短に言えば、私のIMHO:nginxは良い統計情報を提供しますが、ディスクからの読み取りは不十分です。



PHPスクリプトを使用してファイルを配布する方が効率的であるとは思いもしませんでした。

さて、「すぐに使える」範囲のバイト数のリクエストに対して、AIOでhttpdを探していたことを付け加えます。 2番目のバージョンのlighttpdはできるようですが、バージョンはまだ不安定です...他に適切なものは見つかりませんでした。



All Articles