ホームページ  >  記事  >  運用・保守  >  MongoDB のディスク IO 問題の解決策

MongoDB のディスク IO 問題の解決策

巴扎黑
巴扎黑オリジナル
2017-09-04 14:05:441437ブラウズ

これは少し見出しですが、次の 3 つのヒントは、ロンドン MongoDB ユーザー グループの Conversocial 担当副社長 Colin Howe による共有から得たもので、より実践的です。

アプリケーション: 以下の点は普遍的に適用できるわけではありません。使用できるかどうかは、独自のアプリケーション シナリオとデータの特性によって異なります。

1. 結合された大きなドキュメントを使用する

MongoDB はドキュメント データベースであり、その各レコードは JSON 形式のドキュメントであることがわかっています。たとえば、次の例のように、毎日 1 つの統計データが生成されます:

{ metric: "content_count", client: 5, value: 51, date: ISODate("2012-04-01 13:00") ) }

{ metric: "content_count", client: 5, value: 49, date: ISODate("2012-04-02 13:00") }

そして、結合された大きなドキュメントを使用する場合は、1 つを結合することができますこの方法で月のデータがすべて 1 つのレコードに保存されます:

{ metric: "content_count", client: 5, month: "2012-04", 1: 51, 2: 49, ... }

が保存されます上記の 2 つの方法で、合計約 7GB のデータが事前に保存され (マシンには 1.7GB のメモリしかありません)、テストでは 1 年分の情報が読み取られます。この 2 つの読み取りパフォーマンスの違いは明らかです:

。 1 つ目: 1.6 秒

2 つ目: 0.3 秒

それでは何が問題なのでしょうか?

実際の理由は、ストレージを組み合わせた場合、データを読み取るときに読み取れるドキュメントが少なくなるからです。読み取ったドキュメントを完全にメモリに収めることができない場合、コストは主にディスク シークに費やされ、1 年分のデータを取得する場合、最初の保存方法ではより多くのドキュメントを読み取る必要があるため、ディスク シークの回数も多くなります。とても遅いです。

実際、MongoDB の有名なユーザーである foursquare は、読み取りパフォーマンスを向上させるためにこのメソッドを多用しています。こちらを参照してください

2. 特別なインデックス構造を使用する

MongoDB は、従来のデータベースと同様に、インデックス データ構造として B ツリーを使用することがわかっています。ツリー型インデックスの場合、ホット データの保存に使用されるインデックスのストレージが集中するほど、インデックスによって浪費されるメモリが少なくなります。そこで、次の 2 つのインデックス構造を比較します:

db.metrics.ensureIndex({ metric: 1, client: 1, date: 1})

db.metrics.ensureIndex({ date: 1, metric: 1) 、クライアント: 1 })

これら 2 つの異なる構造を使用すると、挿入パフォーマンスの違いも明らかです。

最初の構造を使用する場合、データ量が 2,000 万未満の場合、挿入速度は基本的に 10k/s に維持されますが、データ量が再び増加すると、挿入速度は 2.5k/s まで徐々に低下します。データ量がさらに増加すると、パフォーマンスが低下する可能性があります。

2番目の構造を使用すると、挿入速度は基本的に10k/sで安定します。

その理由は、2 番目の構造がインデックスの最初に日付フィールドを配置するためです。そのため、インデックスを構築するとき、新しいデータがインデックスを更新するときに、データは途中で更新されず、インデックスの末尾でのみ変更されます。挿入が早すぎるインデックスは、後続の挿入操作中にほとんど変更を必要としません。前者の場合、日付フィールドが先頭にないため、ツリー構造の途中でインデックス更新が行われることが多く、インデックス構造の大規模な変更が頻繁に発生します。

3. スペースを確保する

ポイント 1 と同じ。この点も、従来の機械式ハードディスクの主な動作時間がディスクのシーク操作に費やされているという事実に基づいています。

たとえば、ポイント 1 の例では、データを挿入するときに、今年のデータに必要なすべてのスペースを一度に挿入します。これにより、1 年のうち 12 か月分のデータが 1 つのレコードに格納され、ディスク上に順次に保存されるようになります。これにより、データを読み取る際に必要となるのは、1 年に 1 回の連続読み取り操作だけになります。過去 12 回の読み取りでは、ディスク シークは 1 回だけです。

db.metrics.insert([

{ metric: 'content_count', client: 3, date: '2012-01', 0: 0, 1: 0, 2: 0, ... }

{ . ....................、日付: '2012-02'、... })

{ . ...................................、日付: '2012-03'、... })

{ ................................................、日付: '2012-04'、... } )

{ ...................................................、日付: '2012-05'、 ... })

{ ...................................、日付: '2012-06' , ... } )

{ ...................................................、日付: ' 2012-07', ... })

{ ...................................., 日付: '2012-08', . . })

{ ..................................., 日付: '2012-09', .. })

{ .....................日付: '2012-10', ... })

{ ................................... ...、日付: '2012-11' 、... })

{ ................................... ...., 日付: '2012-12 ', ... })

])

結果:

予約スペース方式を使用しない場合、1 年間の記録を読み取るのに 62 ミリ秒かかります

予約スペース方式を使用すると、1年分の記録を読み取るのに62msかかりますが、6.6msしかかかりません

以上がMongoDB のディスク IO 問題の解決策の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。