web-dev-qa-db-ja.com

MongoDBは書き込みをどのレベルまでロックしますか? (または:「接続ごと」とはどういう意味ですか

Mongodbのドキュメントでは、次のように書かれています。

バージョン2.2以降、MongoDBは、ほとんどの読み取りおよび書き込み操作に対してデータベースごとにロックを実装します。一部のグローバル操作、通常は複数のデータベースを含む短命の操作では、グローバルな「インスタンス」ワイドロックが必要です。 2.2より前では、mongodインスタンスごとに「グローバル」ロックは1つしかありません。

これは、たとえば、ネットワーク上で実行されているさまざまなアプリからmongodb:// localhost/testへの接続が3つあるという状況では、一度に1つしか書き込みできないことを意味しますか?それとも接続ごとですか?

IOW:接続ごとですか、または書き込み中に/ testデータベース全体がロックされていますか?

58
nicksahler

接続ごとではなく、mongodごとです。つまり、そのサーバー上のtestデータベースへのすべての接続にロックが存在します。

また、読み取り/書き込みロックなので、書き込みが発生している場合は読み取りを待機する必要があります。

ただし、MongoDBロックは、取得するSQL /通常のトランザクションロックとは非常に異なり、通常、平均更新の間に約1秒間ロックが保持されます。

37
Sammaye

MongoDBロックは異なります

MongoDBでのロックは、RDBMSでのロックのようには機能しないため、少し説明が必要です。 MongoDBの以前のバージョンでは、単一のグローバルリーダー/ライターラッチがありました。 MongoDB 2.2以降では、各データベースにリーダー/ライターラッチがあります。

リーダーライターラッチ

ラッチは、マルチリーダー、シングルライターであり、ライター欲張りです。この意味は:

  • データベース上に同時リーダーの数に制限はありません
  • 1つのデータベース内のコレクションには、一度に1人のライターしか存在できません(これについては後で詳しく説明します)
  • 作家は読者をブロックする
  • 「ライター欲張り」とは、書き込み要求が入ると、書き込みが完了するまですべてのリーダーがブロックされることを意味します(これについては後で説明します)

これを「ロック」ではなく「ラッチ」と呼ぶことに注意してください。これは、軽量であり、適切に設計されたスキーマでは、書き込みロックが数十マイクロ秒のオーダーで保持されるためです。リーダーライターのロックの詳細については、 here を参照してください。

MongoDBでは、必要な数のクエリを同時に実行できます。関連データがRAMにある限り、ロック競合なしですべて満たされます。

アトミックドキュメントの更新

MongoDBでは、トランザクションのレベルは単一のドキュメントであることを思い出してください。 1つのドキュメントに対するすべての更新はアトミックです。 MongoDBは、RAM内の1つのドキュメントを更新するのに必要な時間だけ書き込みラッチを保持することでこれを実現します。低速の操作がある場合(特に、ドキュメントまたはインデックスエントリをディスクからページインする必要がある場合)、その操作はyield書き込みラッチ。操作がラッチを生成すると、次のキュー操作が続行できます。

これは、単一のデータベース内のすべてのドキュメントへの書き込みがシリアル化されることを意味します。スキーマの設計が貧弱で、書き込みに時間がかかる場合、これは問題になる可能性がありますが、適切に設計されたスキーマでは、ロックは問題になりません。

ライター・グリーディ

作家貪欲であることに関するいくつかの言葉:

一度にラッチを保持できるライターは1人だけです。一度に複数のリーダーがラッチを保持できます。単純な実装では、単一のリーダーが動作している場合、ライターは無期限に飢えてしまう可能性があります。これを避けるため、MongoDB実装では、1つのスレッドが特定のラッチに対して書き込み要求を行うと、

  • そのラッチを必要とするすべての後続のリーダーはブロックします
  • そのライターは、現在のすべてのリーダーが終了するまで待機します
  • ライターは書き込みラッチを取得し、作業を行ってから、書き込みラッチを解除します
  • キューに入れられたすべてのリーダーが続行します

この作家の貪欲な振る舞いは、非自明な方法で譲歩と相互作用するため、実際の振る舞いは複雑です。リリース2.2以降では、各データベースにseparateラッチがあるため、データベース 'A'のコレクションへの書き込みは個別のラッチを取得することを思い出してください。データベース「B」の任意のコレクションに書き込むよりも。

特定の質問

特定の質問について:

  • ロック(実際にはラッチ)は、単一のドキュメントを更新するのにかかる限り、MongoDBカーネルによって保持されます。
  • MongoDBに接続する複数の接続があり、それらのそれぞれが一連の書き込みを実行している場合、その書き込みが完了するのにかかる限り、ラッチはデータベースごとに保持されます
  • 書き込み(更新/挿入/削除)を実行する際に着信する複数の接続はすべてインターリーブされます

これはパフォーマンス上の大きな懸念事項のように聞こえますが、実際には速度を落とすことはありません。適切に設計されたスキーマと典型的なワークロードにより、MongoDBは、データベースのロック率が50%を超える前に、SSDであってもディスクI/O容量を飽和させます。

私が知っている最大容量のMongoDBクラスターは、現在1秒あたり200万回の書き込みを実行しています。

239
William Z

Mongo 3.0は、コレクションレベルのロックをサポートするようになりました。

これに加えて、Mongoはストレージエンジンを作成できるAPIを作成しました。 Mongo 3.0には2つのストレージエンジンが付属しています。

  1. MMAPv1:デフォルトのストレージエンジンと以前のバージョンで使用されているもの。コレクションレベルのロックが付属しています。
  2. WiredTiger:新しいストレージエンジンには、ドキュメントレベルのロックと圧縮が付属しています。 (64ビットバージョンでのみ使用可能)

MongoDB 3.0リリースノート

WiredTiger

20
Londo

私は質問がかなり古いことを知っていますが、それでも一部の人々は混乱しています...

MongoDB 3.0以降では、WiredTigerストレージエンジン(document-level concurrencyを使用)は64ビットビルドで使用できます。

WiredTigerは、書き込み操作にドキュメントレベルの同時実行制御を使用します。その結果、複数のクライアントがコレクションの異なるドキュメントを同時に変更できます。

ほとんどの読み取りおよび書き込み操作では、WiredTigerはオプティミスティック同時実行制御を使用します。 WiredTigerは、グローバル、データベース、およびコレクションレベルでインテントロックのみを使用します。ストレージエンジンが2つの操作間の競合を検出すると、書き込みの競合が発生し、MongoDBがその操作を透過的に再試行します。

一部のグローバル操作、通常は複数のデータベースを含む短命の操作では、グローバルな「インスタンス全体」のロックが必要です。コレクションの削除など、その他の一部の操作では、引き続きデータベースの排他ロックが必要です。

ドキュメントレベルの同時実行性

9
Muhammad Ali