データベースシステムには、特に重要なデータが含まれる場合に、データの一貫性と整合性を保証する義務があります。これらの側面は、MongoDBのACIDトランザクションを通じて実施されます。 ACIDトランザクションは、データベースに更新を行う前に、データの有効性に関するいくつかの定義されたルールを満たす必要があります。そうでない場合、ACIDトランザクションは中止され、データベースに変更は加えられません。すべてのデータベーストランザクションは単一の論理操作と見なされ、実行時間中、変更がコミットされるまでデータベースは一貫性のない状態になります。データベースの状態を正常に変更する操作は書き込みトランザクションと呼ばれ、データベースを更新せずにデータを取得するだけの操作は読み取り専用トランザクションと呼ばれます。 ACIDは、Atomicity、Consistency、Isolation、およびDurabilityの頭字語です。
データベースは、さまざまなユーザーがさまざまなタイミングで、または同時にアクセスできる共有リソースです。このため、同時トランザクションが発生する可能性があり、適切に管理されていないと、システムクラッシュ、ハードウェア障害、デッドロック、データベースパフォーマンスの低下、または同じトランザクションの実行の繰り返しが発生する可能性があります。
ACIDルールとは何ですか?
データの整合性を保証するには、すべてのデータベースシステムがACIDプロパティを満たしている必要があります。
トランザクションは、完全に成功することも完全に失敗することもできる単一の操作単位と見なされます。トランザクションを部分的に実行することはできません。トランザクションを参照する条件のいずれかが失敗した場合、トランザクション全体が完全に失敗し、データベースは変更されません。たとえば、アカウントXからYに資金を転送する場合、ここでは2つのトランザクションがあります。最初のトランザクションはXから資金を削除することであり、2番目のトランザクションはYに資金を記録することです。最初のトランザクションが失敗した場合、全体トランザクションは中止されます
操作が発行されると、実行前はデータベースは一貫性のある状態にあり、すべてのトランザクション後も一貫性のある状態を維持する必要があります。更新がある場合でも、トランザクションはデータベースを常に有効な状態にし、データベースの不変条件を維持する必要があります。たとえば、別のコレクションで外部キーとして参照されている主キーを削除することはできません。違法なトランザクションによるデータの破損を防ぐために、すべてのデータは定義された制約を満たす必要があります。
同時に実行される複数のトランザクションは、相互に影響を与えることなく実行されます。それらが連続して実行される場合、それらの結果は同じである必要があります。 2つ以上のトランザクションがMongoDB内の同じドキュメントを変更する場合、競合が発生する可能性があります。データベースは、コミットされる直前に競合を検出します。ドキュメントのロックを取得する最初の操作は続行されますが、他の操作は失敗し、競合エラーメッセージが表示されます。
これは、トランザクションがコミットされると、停電やインターネットの切断などのシステム障害が発生した場合でも、変更を常に維持する必要があることを示しています。
MongoDBACIDトランザクション
MongoDBは、柔軟なスキーマを備えたドキュメントベースのNoSQLデータベースです。トランザクションは、1回のドキュメント書き込みよりもパフォーマンスコストが高くなるため、書き込み操作ごとに実行する必要のある操作ではありません。ドキュメントベースの構造と非正規化されたデータモデルにより、トランザクションの必要性が最小限に抑えられます。 MongoDBではドキュメントの埋め込みが許可されているため、書き込み操作を満たすために必ずしもトランザクションを使用する必要はありません。
MongoDBバージョン4.0は、レプリカセットのデプロイメントに対してのみマルチドキュメントトランザクションのサポートを提供し、おそらくバージョン4.2はシャードデプロイメントのサポートを拡張します(リリースノートによる)。
トランザクションの例:
$ mongosとすると、username:PRIMARY>
のようなものが表示されます。$use app
$db.users.insert([{_id:1, name: ‘Brian’}, {_id:2, name: ‘Sheila’}, {_id:3, name: ‘James’}])
トランザクションのセッションを開始する必要があります:
$db.getMongo().startSession() and you should see something like
session { "id" : UUID("dcfa8de5-627d-3b1c-a890-63c9a355520c") }
このセッションを使用すると、次のコマンドでトランザクションを使用してユーザーを追加できます。
$session.startTransaction()
session.getDatabase(‘app’).users.insert({_id:4, name: ‘Hitler’})
WriteResult({“ nInsterted”:2})
が表示されますトランザクションはまだコミットされておらず、通常の$ db.users.find({})は、以前に保存されたユーザーのみを提供します。ただし、
を実行すると$session.getDatabase(“app”).users.find()
最後に追加されたレコードは、返された結果で利用可能になります。このトランザクションをコミットするには、以下のコマンドを実行します
$session.commitTransaction()
トランザクションの変更はメモリに保存されるため、障害が発生した後でも、データはリカバリ時に利用できます。
MongoDBでのマルチドキュメントACIDトランザクション
これらは、相互に影響を与えることなく順次実行する必要があるマルチステートメント操作です。上記のサンプルでは、2つのトランザクションを作成できます。1つはユーザーを追加するためのもので、もう1つはユーザーを年齢のフィールドで更新するためのものです。つまり
$session.startTransaction()
db.users.insert({_id:6, name “Ibrahim”})
db.users.updateOne({_id:3 , {$set:{age:50}}})
session.commit_transaction()
トランザクションは、1つまたは複数のコレクション/データベースに含まれる複数のドキュメントに対する操作に適用できます。ドキュメントトランザクションによる変更は、関連のない、またはそれらを必要としないワークロードのパフォーマンスに影響を与えません。トランザクションがコミットされるまで、コミットされていない書き込みはセカンダリノードに複製されず、トランザクションの外部で読み取ることもできません。
マルチドキュメントトランザクションは、WiredTigerストレージエンジンでのみサポートされます。前述のように、トランザクションを必要とするアプリケーションはほとんどないため、トランザクションを必要とする場合は、トランザクションを短くする必要があります。そうしないと、単一のACIDトランザクションで、過剰な数の操作を実行しようとすると、WiredTigerキャッシュに高い負荷がかかる可能性があります。最も古いスナップショットが作成されてから、キャッシュは常に後続のすべての書き込みの状態を維持するように指示されます。つまり、新しい書き込みはトランザクションの期間中キャッシュに蓄積され、古いスナップショットで現在実行されているトランザクションがコミットまたは中止された後にのみフラッシュされます。トランザクションで最高のデータベースパフォーマンスを得るには、開発者は次のことを考慮する必要があります。
- プライマリおよび一時的なネットワークの一時的な中断を選択するのを待つなどの一時的な例外により、トランザクションが中止される場合があります。開発者は、定義されたエラーが表示された場合にトランザクションを再試行するロジックを確立する必要があります。
- MongoDBが提供するデフォルトの60秒からトランザクションを実行するための最適な期間を構成します。さらに、トランザクション内での高速データアクセスを可能にするために、インデックス付けを採用します。また、制限時間内に実行できるようにトランザクションをバッチに分割することで、タイムアウトに対処する際にトランザクションを微調整する柔軟性もあります。
- 16MBのサイズ制約に適合するように、トランザクションを小さな一連の操作に分解します。それ以外の場合、操作とoplogの説明がこの制限を超えると、トランザクションは中止されます。
- エンティティに関連するすべてのデータは、単一のリッチなドキュメント構造で保存する必要があります。これは、さまざまなフィールドが変更されるときにキャッシュされるドキュメントの数を減らすためです。
- トランザクションの実行にはかなりの時間がかかり、どういうわけかデータベースのパフォーマンスが低下する可能性があります。
- トランザクションサイズは16MBに制限されており、このサイズを超える傾向のあるトランザクションをより小さなトランザクションに分割する必要があります。
- 多数のドキュメントをトランザクションにサブジェクトすると、WiredTigerエンジンに過度のプレッシャーがかかる可能性があり、スナップショット機能に依存しているため、フラッシュされていない大規模な操作がメモリに保持されます。これにより、データベースのパフォーマンスが低下します。
MongoDBバージョン4.0では、データの整合性と一貫性を向上させる機能として、レプリカセットのマルチドキュメントトランザクションサポートが導入されました。ただし、MongoDBを使用するときにトランザクションを必要とするアプリケーションはほとんどありません。この機能には制限があり、トランザクションの概念に関する限り、かなり未成熟になります。たとえば、シャードクラスターのトランザクションはサポートされておらず、16MBのサイズ制限を超えることはできません。データモデリングは、データベース内のトランザクションを減らすためのより良い構造を提供します。特別な場合を扱っているのでない限り、MongoDBでのトランザクションを避けることをお勧めします。