4

一時的なログストアとしてMongoDBを使用しています。コレクションは、1時間に最大400,000の新しい行を受け取ります。各行には、UNIXタイムスタンプとJSON文字列が含まれています。

定期的にコレクションの内容をS3のファイルにコピーして、1時間ごとに最大400,000行を含むファイルを作成したいと思います(たとえば、today_10_11.logには、午前10時から午前11時の間に受信したすべての行が含まれます)。コレクションが挿入物を受け取っている間に、このコピーを行う必要があります。

私の質問:400,000時間ごとの挿入のタイムスタンプ列にインデックスを付けることによるパフォーマンスへの影響と、1時間に相当する行のクエリにかかる追加の時間との違いは何ですか。

問題のアプリケーションは、Herokuで実行されているRubyで記述され、MongoHQプラグインを使用しています。

4

4 に答える 4

4

私はあなたのようなアプリケーションを持っています、そして現在それは1億5000万のログレコードを持っています。1時間あたり400kで、このDBは急速に大きくなります。400kは、タイムスタンプにインデックスを付けて1時間挿入しますが、インデックスなしのクエリを実行するよりもはるかに価値があります。インデックス付きのタイムスタンプを使用して1時間に数千万のレコードを挿入することに問題はありませんが、タイムスタンプに対してインデックスなしのクエリを実行すると、4サーバーシャ​​ード(CPUバインド)で数分かかります。インデックス付きのクエリがすぐに表示されます。したがって、間違いなくインデックスを作成します。インデックス作成の書き込みオーバーヘッドはそれほど高くなく、1時間あたり40万レコードはmongoにとってそれほど多くありません。

ただし、注意しなければならないことの1つは、メモリサイズです。1時間あたり40万レコードで、1日1,000万を実行しています。そのインデックスをメモリに保持するには、1日に約350MBのメモリを消費します。したがって、これがしばらく続くと、インデックスがメモリよりも速く大きくなる可能性があります。

また、removeを使用して一定期間後にレコードを切り捨てている場合、removeによってディスクに大量のIOが作成され、ディスクにバインドされていることがわかりました。

于 2011-02-09T02:09:30.763 に答える
4

Mongoはデフォルトで_idフィールドにインデックスを付け、ObjectIdはすでにタイムスタンプで開始しているため、基本的に、Mongoは挿入時間によってコレクションにインデックスを付けています。したがって、Mongoのデフォルトを使用している場合は、2番目のタイムスタンプフィールドにインデックスを付ける必要はありません(または追加する必要もありません)。

rubyでオブジェクトIDの作成時間を取得するには、次のようにします。

ruby-1.9.2-p136 :001 > id = BSON::ObjectId.new
 => BSON::ObjectId('4d5205ed0de0696c7b000001') 
ruby-1.9.2-p136 :002 > id.generation_time
 => 2011-02-09 03:11:41 UTC 

特定の時間のオブジェクトIDを生成するには:

ruby-1.9.2-p136 :003 > past_id = BSON::ObjectId.from_time(1.week.ago)
 => BSON::ObjectId('4d48cb970000000000000000') 

したがって、たとえば、過去1週間に挿入されたすべてのドキュメントをロードする場合は、past_idより大きくidより小さい_idを検索するだけです。したがって、Rubyドライバーを介して:

collection.find({:_id => {:$gt => past_id, :$lt => id}}).to_a
 => #... a big array of hashes.

もちろん、タイムスタンプ用に別のフィールドを追加してインデックスを作成することもできますが、Mongoがデフォルトの_idフィールドを使用して必要な作業をすでに行っている場合は、パフォーマンスが低下しても意味がありません。

オブジェクトIDの詳細。

于 2011-02-09T03:17:21.723 に答える
1

確かに、すべての書き込みで、インデックスデータを更新する必要があります。データに対して大規模なクエリを実行する場合は、必ずインデックスが必要になります。

MongoDBObjectIdではなく_idフィールドにタイムスタンプを保存することを検討してください。一意のタイムスタンプを保存している限り、ここで問題ありません。_idはObjectIDである必要はありませんが、_idに自動インデックスがあります。インデックスの負担を追加しないので、これが最善の策かもしれません。

于 2011-02-09T00:31:18.777 に答える
1

スラッシュを可能にするために、たとえば600k行のスペースがある、インデックス付けされていないキャップ付きコレクションを使用します。1時間に1回、コレクションをテキストファイルにダンプしてから、grepを使用して、ターゲットの日付以外の行を除外します。これでは、DBの優れた部分を活用することはできませんが、コレクションインデックス、フラッシュ、またはそのナンセンスについて心配する必要がないことを意味します。パフォーマンスが重要なのは、コレクションを挿入用に解放することです。したがって、DBのコンテキスト外で「ハード」ビット(日付によるフィルタリング)を実行できる場合は、パフォーマンスに大きな影響を与えることはありません。400〜600k行のテキストは、grepにとっては些細なことであり、おそらく1〜2秒以上かかることはありません。

各ログで少しスラッシュを気にしない場合は、コレクションをダンプしてgzipで圧縮できます。各ダンプで古いデータを取得しますが、ダンプ間に600k行を超える行を挿入しない限り、60万行ずつの連続した一連のログスナップショットが必要です。

于 2011-02-09T00:40:29.440 に答える