Docs Menu
Docs Home
/
MongoDBマニュアル
/

FAQ: 同時実行性

項目一覧

MongoDB では、複数のクライアントが同じデータを読み書きできます。 整合性を確保するために、MongoDB はロックと同時実行制御を使用して、複数のクライアントが同じデータを同時に変更するのを防ぎます。 1 つのドキュメントへの書き込みは、完全に行われるか、まったく行われないかのどちらかであるため、クライアントは常にコンシステント データを参照できます。

MongoDBは、グローバル、データベース、またはコレクション レベルで操作をロックできる複数粒度ロック [1] を使用し、個々のストレージエンジンがコレクションレベル以下(たとえば、WiredTiger 内のドキュメントレベル)で各自の同時実行制御の実装を可能にします。

MongoDB は、データベースやコレクションなどのリソースへの同時リーダー共有アクセスを許可するリーダーおよびライターのロックを使用します。

読み取り操作用の共有(S)ロックモードと書き込み操作用の排他的(X)ロックモードに加えて、意向共有(IS)モードと意向排他(IX)モードは、より細かい粒度のロックを使用してリソースを読み書きする意向を示すものです。特定の粒度でロックする場合、上位レベルはすべて意向ロックを使用してロックされます。

たとえば、コレクションを書き込み用にロックする場合(モード X を使用)、対応するデータベース ロックとグローバル ロックの両方を意向排他(IX)モードでロックする必要があります。単一のデータベースを IS モードと IX モードで同時にロックすることは可能ですが、排他(X)ロックは他のモードと共存できず、共有(S)ロックは意向共有(IS)ロックとのみ共存できます。

ロックは公平であり、読み取りと書き込みのロック要求は順番にキューに入れられます。ただし、スループットを最適化するために、1 つのロック要求が許可されると、互換性のある他のすべてのロック要求が同時に許可され、競合するロック要求が実行される前にロックが解除される可能性があります。たとえば、X ロックが解除された直後に、競合キューに次のロックが含まれている状況を考えてみましょう。

IS → IS → X → X → S → IS

厳密な先入れ先出し(FIFO)の順序では、最初の 2 つの IS モードのみが付与されます。しかし、MongoDB は実際にはすべての IS モードと S モードを付与し、それらがすべてはけると、その間に新しい IS または S リクエストがキューに入っていても、X を付与します。付与によって他のリクエストはすべてキューの先頭に移動されるため、どのリクエストにも資源飢餓が発生することはありません。

db.serverStatus() 出力および db.currentOp() 出力では、ロック モードは次のように表されます。

ロックモード
説明
R
共有ロック(S)を表します。
W
排他ロック(X)を表します。
r
インテント共有ロック(IS)を表します。
w
インテント排他ロック(IX)を表します。
[1] 詳細については、 Wikipedia の複数粒度ロック に関するページを参照してください。

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

一部のグローバル操作(通常は複数のデータベースに関係する短時間の操作)では、依然としてグローバルな「インスタンス全体」のロックが必要です。 renameCollectionなどの他の操作では、依然として特定の状況で排他的データベース ロックが必要です。

ロックに関するロック使用情報のレポート作成には、次のいずれかの方法を使用します。

具体的には 、locks serverStatus の出力 の ドキュメント、またはlocks 現在の操作レポート の フィールドにより、 インスタンス内のロックmongod タイプとロック競合の量に関するインサイトが提供されます。

db.serverStatus() 出力および db.currentOp() 出力では、ロック モードは次のように表されます。

ロックモード
説明
R
共有ロック(S)を表します。
W
排他ロック(X)を表します。
r
インテント共有ロック(IS)を表します。
w
インテント排他ロック(IX)を表します。

操作を終了するには、db.killOp() を使用します。

状況によっては、読み取り操作と書き込み操作はロックを解除することがあります。

クエリ、更新、および削除などの読み取りや書き込み操作の実行が長時間になると、さまざまな条件下でロックを解除します。MongoDB 操作では、複数のドキュメントに影響を与える書き込み操作において、個々のドキュメントの変更間でロックを解除することもあります。

ドキュメント レベルの同時実行制御 をサポートする、WiredTiger などのストレージ エンジンの場合、グローバル レベル、データベース レベル、およびコレクション レベルで保持される意向ロックは他のリーダーやライターをブロックしないため、ストレージにアクセスするときにロックを解除する必要はありません。しかし、次のような場合に操作は定期的にロックを解除します。

  • 大量のデータをメモリに保持する可能性がある長時間のストレージ トランザクションを回避するため。

  • 長時間実行されている操作を強制終了できるように割り込みポイントとして機能するため。

  • インデックスやコレクションの削除や作成など、コレクションへの排他的アクセスを必要とする操作を許可するため。

次の表は、ドキュメントレベルのストレージエンジンのロックに使用されるいくつかの操作とロックのタイプを示します。

操作
Database
コレクション
クエリの発行
r (意向共有)
r (意向共有)
Insert data
w (意向排他)
w (意向排他)
データの削除
w (意向排他)
w (意向排他)
Update data
w (意向排他)
w (意向排他)
集計の実行
r (意向共有)
r (意向共有)
インデックスの作成
W (排他)
コレクションの一覧化
r (意向共有)
map-reduce
W (Exclusive) およびR (Shared)
w (Intent Exclusive) およびr (Intent Shared)

注意

インデックスを作成するには、コレクションに対して排他的ロック(W)が必要です。 ただし、インデックス構築プロセスの全期間は保持されません。

詳しくは、「 格納済みコレクションでのインデックス ビルド 」を参照してください。

一部の管理コマンドは、データベースの長時間排他ロックができます。 For large clusters, consider taking the mongod instance offline so that clients are not affected. たとえば、 mongodレプリカセットの一部である場合、メンテナンスの実行中はmongodをオフラインにして、レプリカセットの他のノードが要求を処理できるようにします。

以下の管理操作では、データベース レベルでの長時間の排他ロックが必要です。

さらに、 renameCollectionコマンドと対応するdb.collection.renameCollection() shell メソッドは次のロックを取得します。

コマンド
ロック動作
renameCollection データベースコマンド

同じデータベース内のコレクションの名前を変更する場合、renameCollection コマンドはソース コレクションとターゲット コレクションに対して排他(W) ロックを取得します。

ターゲット名前空間がソース コレクションとは異なるデータベースにある場合、renameCollection コマンドは、データベース間でコレクションの名前を変更するときにターゲット データベースに対して排他(W)ロックを取得し、完了するまでそのデータベースに対する他の操作をブロックします。

renameCollection() シェルヘルパー メソッド
renameCollection()メソッドはソース コレクションとターゲット コレクションに対して排他的ロック(W)を取得し、データベース間でコレクションを移動できません。

以下の管理操作では、コレクション レベルで排他ロックが必要です。

  • create コマンドと対応する db.createCollection() および db.createView() shell メソッド。

  • createIndexes コマンドと対応する db.collection.createIndex() および db.collection.createIndexes() shell メソッド。構築プロセスでは、インデックス構築の開始時と終了時にのみコレクションに対して排他ロックが保持されます。

  • drop コマンドと対応する db.collection.drop() shell メソッド。

  • dropIndexes コマンドと対応する db.collection.dropIndex() および db.collection.dropIndexes() shell メソッド。

  • renameCollection コマンドと対応する db.collection.renameCollection() shell メソッドは、バージョンに応じて次のロックを取得します。

    • renameCollectiondb.collection.renameCollection()の場合 : 同じデータベース内のコレクションの名前を変更する場合、その操作はソース コレクションとターゲット コレクションに対して排他(W) ロックを取得します。

    • renameCollectionのみ:ターゲット名前空間がソース コレクションとは異なるデータベースにある場合、データベース間でコレクションの名前を変更するときに、操作によってターゲット データベースで排他ロック(W)が取得され、操作が完了するまでそのデータベース上の他の操作がブロックされます。

  • reIndexコマンドと対応するdb.collection.reIndex() shell メソッドは、コレクションに対して排他的ロック(W)を取得し、完了するまでコレクションに対する他の操作をブロックします。

  • replSetResizeOplogコマンドはoplogコレクションに対して排他的ロック(W)を取得し、終了するまでコレクションに対する他の操作をブロックします。

以下の MongoDB 操作では、複数のデータベースに対してロックを取得して保持する場合があります。

操作
動作
これらの操作では、グローバル排他ロックではなく、排他的コレクション ロック(W)のみが取得されます。

この操作では、データベース間でコレクションの名前を変更するときに、ターゲット データベースでは排他的ロック(W)、ソース データベースでは意向共有ロック(r)、ソース コレクションでは共有ロック(S)が取得されます。

同じデータベース内のコレクションの名前を変更する場合、操作にはソース コレクションとターゲット コレクションに対する排他(W)ロックのみが必要です。

この操作では、グローバル排他ロックではなく oplog コレクションの排他ロック(W)のみが取得されます。

シャーディングは、コレクションを複数の mongod インスタンスに分散することで同時実行性を向上させ、シャード サーバー(具体的には mongos プロセス)を下流の mongod インスタンスと同時に実行できるようにします。

シャーディングされたクラスターでは、ロックはクラスター全体ではなく、個々のシャードに適用されます。つまり、各 mongod インスタンスは、シャーディングされたクラスター内では他のインスタンスから独立しており、各自がロックを使用します。1 つの mongod インスタンスに対する操作は、他のインスタンスに対する操作をブロックしません。

レプリカセットを使用すると、MongoDB がプライマリのコレクションに書き込むとき、MongoDB はプライマリの oploglocal データベースの特別なコレクション)にも書き込みます。そのため、MongoDB はコレクションのデータベースと local データベースの両方をロックする必要があります。mongodは、データベースの整合性を維持し、レプリケーションがある場合でも、書き込み操作がすべて完了するか、または何もなかったようにするために、両方のデータベースを同時にロックする必要があります。

レプリカセットに書き込む場合、ロックのスコープはプライマリに適用されます。

レプリケーションでは、MongoDB はセカンダリに対して書き込みを順次に適用することはありません。セカンダリは oplog エントリをバッチで収集し、それらのバッチを並列に適用します。書き込みは、oplog に現れる順序で適用されます。

セカンダリがレプリケーションを実行中の場合、 セカンダリを対象とする読み取りはWiredTigerのスナップショットからデータを読み取ります。 これにより、データの一貫したビューが保証されしながら、レプリケーションと同時に読み取りを実行できるようになります。

単一のドキュメントには、リレーショナルスキーマの別々の親子テーブルにまたがってモデル化される関連データを含めることができるため、MongoDB のアトミックな単一ドキュメント操作は、大半のアプリケーションのデータの完全性要件を満たすトランザクション セマンティクスをすでに提供しています。複数のサブドキュメントや配列の要素の更新を含め、1 つの操作で 1 つ以上のフィールドに書き込むことができます。MongoDB が提供する保証により、ドキュメントが更新されるときに完全な分離が保証されます。エラーが発生すると、操作がロールバックされ、クライアントはドキュメントの整合性のあるビューを受け取ることができます。

MongoDB は(単一または複数のコレクション内の)複数のドキュメントへの読み取りと書込みにアトミック性を必要とする状況で、レプリカセットやシャーディングされたクラスターでのトランザクションを含む分散トランザクションをサポートします。

詳細については、「トランザクション」を参照してください。

重要

ほとんどの場合、分散トランザクションでは 1 つのドキュメントの書き込み (write) よりもパフォーマンス コストが高くなります。分散トランザクションの可用性は、効果的なスキーマ設計の代わりにはなりません。多くのシナリオにおいて、非正規化されたデータモデル(埋め込みドキュメントと配列)が引き続きデータやユースケースに最適です。つまり、多くのシナリオにおいて、データを適切にモデリングすることで、分散トランザクションの必要性を最小限に抑えることができます。

トランザクションの使用に関するその他の考慮事項(ランタイム制限や oplog サイズ制限など)については、「本番環境での考慮事項」も参照してください。

読み取り保証(read concern)に応じて、クライアントは書き込みが永続的になる前にその書き込みの結果を確認できます。読み取られたデータをロールバックできるかどうかを制御するには、クライアントは readConcern オプションを使用できます。

バージョン 5.0 で追加

ロックフリーの読み取り操作はただちに実行されます。この操作は、別の操作がコレクションに対して排他(X)書込みロック(write lock)を持っている場合、ブロックされません。

MongoDB 5.0 以降では、別の操作がコレクションに対して排他的(X)書込みロック(write lock)を保持している場合、次の読み取り操作はブロックされません。

コレクションに書き込む場合、mapReduceaggregate は、意向排他(IX)ロックを保持します。そのため、コレクションに対して排他 X ロックがすでに保持されている場合、 mapReduce および aggregate 書き込み操作はブロックされます。

詳細については、次を参照してください。

戻る

Indexes