GridFS vs SQL Server vsローカル

細心の注意を払って



最近、サーバーアプリケーション開発者の間で、ファイルをより適切に管理する方法と、ファイルの読み取り/書き込みを高速化する技術について議論が行われています。 ローカルファイルシステムとGridFSのパフォーマンスの比較に関する記事や記事がネットワークに登場し始めました。 または、ファイルをBLOBとしてリレーショナルデータベースに保存することと、ファイルシステムのハードディスクに保存することについて。 そこで、私はこの対立に参加することにしました。 今日は、MongoDB 2.6.7 x64 GridFSとMS SQL Server Express 2012 v11.0.5058.0 x64とNTFSのパフォーマンスとオーバーヘッドを比較します。 実験には、AMD Athlon(tm)II X2 250プロセッサー3.00 GHz、4GB RAM 1033 MHzおよび600 GB HDD SATA 6Gb / s Western Digital VelociRaptor 10000rpm 32Mb上のWindows 7 x64 SP1プラットフォームを使用しました。 各テストの後、コンピューターが再起動し、ベースがリセットされます。 コードが記事に添付されているC#for .NET 4.5のファイルサーバーの例のパフォーマンスを検討します。



要点をつかむ



テスト中、10,000,000バイトのファイルを1000個保存しようとします。 ダウンロードされた各ファイルは「Files」テーブルに登録されます。「Hash」はそのようなファイルがすでにダウンロードされているかどうかを確認するために使用され、「NewName」は「FileMapping」テーブルでファイル情報をサーバー上のビットイメージに関連付けます ファイルサーバーデータベーススキーマ:



画像








これに加えて、公式のMongoDBドライバーを使用してGridFSにファイルを保存し、.NETクラスライブラリのFileInfoクラスを使用してハードディスクにファイルを保存しようとします。 LINQテクノロジとラムダ式を使用してSQL Serverへの「人間が読み取れる」クエリを簡単に作成できるように、Entity Framework 6.0を使用します。



画像








シングルスレッド録音



まず、ファイルをシングルスレッドモードでロードすることにより、ディスクへの保存をテストします。 5回の打ち上げの結果によると、操作は164751、165095、164461、165937、166296ミリ秒でした。 結果の最大差は約1%でした。 したがって、平均して、プロセスは165338ミリ秒で動作し、そのうち52966-ファイルを登録する時間、12685-ファイルを書き込む時間:



画像








部品のランタイムを測定し、測定せずにプログラムを実行しても、異なる結果にはなりませんでした。 スレッドブラウザでプログラムを実行すると、最大占有RAMサイズが59796 KBであることが示されました。 使用ディスク容量:約9.3 GB。 簡単にするために、すぐに実行時間の平均結果を秒単位で示します。



次に、SQL Serverデータベースへのファイルの書き込みをテストします。 ディスク上の結果のデータベースのサイズは約9.8 GBでした。 ピーク時には、プログラムは233432 KB、DBMS-1627048 KBを消費しました。 プログラムは平均998秒で機能しました。 これらのうち、ファイル登録に34秒、録音に823秒:



画像








次に、GridFSラインナップが登場しました。 使用されるディスク容量は約12 GBです。 取得したすべてのRAMをMongoDBで使い果たしました。 同時に、SQL Serverとサーバーのメモリ消費量は通常の値のままでしたが、この状況では無視できます。 すべてが約921秒で完了しました。 登録の場合-60秒、記録の場合-766秒:



画像








マルチスレッド記録



ここで最初の困難に直面しました。複数のスレッドが同時にDBMSとの接続を確立しようとすると、エラーが発生します。 そして、MongoDBでの作業が「確認なし」になった場合-ドライバーはエラーを出さずに動作を続け、すべてがスムーズに実行され、「CreateIfNotExists」を呼び出している間にEFは多数のデバッグ情報を表示し、try-catchを使用してキャッチされず、プロセスを終了します間違い。 この場合、開発環境からデバッガーと一緒にコンパイルして実行しても、エラーは表示されません。 この問題は、フローを同期し、DBMSとの接続を順番に確立することで解決しました。



記録用にそれぞれ50ファイルの20ストリームを使用して書き込み操作を実行します。 GridFSのテストでは、716259、623205、675829、583331、および739815ミリ秒の平均値が668秒の強いばらつきが示されました。 ご覧のとおり、同じオーバーヘッドコストで、完了するまでの時間が短縮されました。 これは、CPUコアの使用のグラフ上の並列化ビジュアライザーによって示されるダウンタイムの短縮によって説明されます(ビジュアライザーを使用した並列化のビジュアライゼーションははるかに時間がかかりました)。



画像








ファイルをファイルシステムに直接書き込む場合、受信したテスト値の広がりは大きくなく、平均値は170秒でした。 ご覧のとおり、ディスクへのシングルスレッドとマルチスレッドの記録の違いは3%未満でした。 したがって、この場合はCPU使用率のスケジュールを省略するのが適切だと思います。



マルチスレッドファイル書き込みSQL Serverデータベースは、追加の問題を引き起こしました。ロード中に、タイムアウト出力のために一部のスレッドでエラーが発生しました。 その結果、接続が中断され、プロセスはエラーで終了し、データベースは一貫性のない状態になりました。 1000件のリクエストの場合、最初の試行は約40件で失敗しました。 これらのうち、約2つは2回目の試行で失敗しました。 この問題は、タイムアウトを30秒に増やし、失敗した場合に接続を再試行することで解決しました。



マルチスレッドSQL Serverを使用して1,000個のファイルを保存した場合、時間の広がりは5%未満で、結果は平均840秒でした。 これは、シングルスレッドモードよりもほぼ16%高速です。



画像








ファイルを読む



次に、さまざまなリポジトリからのファイルの読み取りをテストします。 シングルスレッドモードでは、すべてのファイルを連続してカウントし、マルチスレッドモードでは、それぞれ50のランダムファイルの20ストリームでカウントします。 従来、各タイプの5回の試行:



画像








SQL Serverデータベースからのファイルの読み取りは、最初はスムーズに進みませんでした。 Entity Frameworkは、データサンプリングのためにデータベースへの各クエリとともにクライアントアプリケーション側で結果をキャッシュします。 また、CLRは自動「ガベージコレクション」を意味しますが、メモリはすぐに消費されるため、「OutOfMemory」エラーが発生し、プロセスが異常終了します。 これは、EFがこの種類の例外を単独で処理せず、すべてのメモリが使い果たされた場合でもキャッシュからデータを削除しないためです。 そして、ファイルを保存するテーブルをクエリすることにより、これは重要になります。 この問題は、「AsNoTracking」インストールを使用して「FileMapping」エンティティコレクションのキャッシュを無効にすることで解決しました。



合計



レイプされたハードドライブと次のピボットテーブルがあります。



画像








ボーナス



可能性のある批判を予測し、以前に未回答の質問に事前に回答しようとすると、少し後で、記事に興味深い(私は)役に立つコメントを追加します。 最初:新しいテストの前にデータベースをリセットしなければ、パフォーマンスは大きく変わりません。 少なくとも、2回目でも3回目でも、繰り返し(合理的な通路で)繰り返し実行しても、結果の違いは得られませんでした。 したがって、最も退屈なため、作業のこの部分の詳細な説明は省略します。



2番目:ソケットを介してDBMSを操作する場合、送信用のデータはプロトコルスタック全体を往復する必要があると多くの人が言うでしょう。 したがって、別のオプションを検討します。 実際、FileInfoクラスと同じオプションで、意味を理解できれば、.NET Remoutingを使用してアクセスするだけです。



画像







All Articles