MongoDBのトランザクション

画像 MongoDBは、最近人気が高まっている優れたデータベースです。 SQLの経験がある人がますます多く使用され始めており、最初の質問の1つは、 MongoDBトランザクションですか?

あなたがstackoverflowで答えを信じるなら、すべてが悪いです。

MongoDB doesn't support complex multi-document transactions. If that is something you absolutely need it probably isn't a great fit for you. 
 If transactions are required, perhaps NoSQL is not for you. Time to go back to ACID relational databases. 
 MongoDB does a lot of things well, but transactions is not one of those things. 
ただし、MVCCに基づくトランザクション(ACID * )を信じて実装することはありません。 以下は、これらのトランザクションがどのように機能するかについての物語であり、コードを見たいと思う人のために、 GitHub (慎重に、java)にようこそ。

投稿はMongoDBに関するものではなく、compare-and-setを使用してトランザクションを作成する方法であり、ストレージが提供する範囲で永続性が正確に提供されます。

データモデル


他の多くのNoSQLソリューションとは異なり、MongoDBは比較と設定をサポートしています。 ACIDトランザクションを追加できるのはCASサポートです。 CASをサポートする他のNoSQLストレージ(HBase、Project Voldemort、ZooKeeperなど)を使用する場合、ここで説明したアプローチを適用できます。
CASとは何ですか?
  ,      ,          .    -   ,     ,      . 

実際、トランザクションで変更するすべてのオブジェクトはCASで保護する必要があります。これはデータモデルに影響します。 銀行の仕事をシミュレートすると仮定します。以下は保護ありとなしの口座モデルです。これから、残りを変更する方法が明確であることを望みます。
無防備被告
モデル
 { _id : ObjectId(".."), name : "gov", balance : 600 } 
 { _id : ObjectId(".."), version : 0, value : { name : "gov", balance : 600 } } 
データ変更
 db.accounts.update( { _id:ObjectId("...") }, { name:"gov", balance:550 } ); 
 db.accounts.update({ _id: ObjectId("..."), version: 0 },{ version : 1, value : { name:"gov", balance:550 } }); 

さらに、オブジェクトにはバージョンがあり、オブジェクトへの変更はそのバージョンを考慮するという事実に焦点を当てませんが、オブジェクトへの変更は競合アクセスで失敗する可能性があることを覚えておく必要があります。

実際、バージョンの追加は、トランザクションをサポートするためにモデルに加える必要があるすべての変更ではありません。完全に変更されたモデルは次のようになります。

 { _id : ObjectId(".."), version : 0, value : { name : "gov", balance : 600 }, updated : null, tx : null } 

追加されたフィールド-更新および送信。 これは、トランザクションプロセスで使用されるオーバーヘッドです。 更新の構造は値と同じです。つまり、これはオブジェクトの修正バージョンであり、トランザクションが成功すると値に変わります。 txはObjectIdクラスのオブジェクトです-トランザクションを表すオブジェクトの_idの外部キー。 トランザクションを表すオブジェクトもCASによって保護されています。

アルゴリズム


アルゴリズムを説明するのは簡単で、その正確さが明白で、より複雑になるように説明することです。 したがって、定義する前にいくつかのエンティティを操作する必要があります。

以下は、アルゴリズムが後で構成される元のステートメント、定義、およびプロパティです。



クリーン状態は、トランザクションが成功した後のオブジェクトを表します。値にはデータが含まれ、更新され、txはnullです。

ダーティな非セキュア状態は、トランザクションの時点でのオブジェクトを表し、更新には新しいバージョンが含まれ、txはトランザクションを表すオブジェクトの_idであり、このオブジェクトは存在します。

ダーティコミット状態は、トランザクションが成功した後のオブジェクトを表しますが、それ自体がクリーンアップされる前に落ち、更新にはトランザクションを表すオブジェクトのtx-_idが含まれますが、オブジェクト自体は既に削除されています。

取引

  1. トランザクションに参加するオブジェクトを読み取ります
  2. トランザクションを表すオブジェクトを作成します(tx)
  3. 更新された各オブジェクトに新しい値を書き込み、tx-tx._idに書き込みます
  4. TXオブジェクトを削除します
  5. 各オブジェクトの値に、更新された値、txおよび更新されたnullifyを書き込みます

読書

  1. オブジェクトを読む
  2. それがきれいな場合-それを返します。
  3. 汚れている場合、更新された値、tx、更新されたゼロの値を書き込みます
  4. 汚れたものがそうでない場合-txのバージョンを変更し、更新されたtxを無効にします
  5. ステップ1に進みます


正しいことを確信していない人のために、宿題はすべてのプロパティとステートメントが満たされていることを確認し、それらを使用してACIDを証明することです

おわりに


MongoDBにトランザクションを追加しました。 しかし、実際には、これは万能薬ではなく、制限があります。一部は以下にリストされ、一部はコメントに記載されています


よくある質問


このようなトランザクションは、シャーディングやログの無効化にどのように役立ちますか?


サーバーエラーが発生した場合、実際にはデータベースの一貫性のない状態を取得できますが、記録時にクライアントがクラッシュすることによって引き起こされる一貫性のない状態から保護されています。 2番目のリスクが1番目のリスクよりも大きい場合、トランザクションを使用すると、システムの信頼性が向上します。

単一ノード構成でmongaを使用していますが、トランザクションは役立ちますか?


はい、ジャーナリングを使用すると、正直なACIDトランザクションを取得できます。 使用しない場合、信頼性を高めるための2番目の方法であるレプリケーションを使用していないため、データ損失の可能性にすでに同意しています。 同意すると、通常モードのトランザクションは競合アクセスおよびクライアントエラーとの一貫性を維持しますが、サーバーがクラッシュした場合、それを失う可能性があります。 しかし、これはそれほど怖いものではありません。単一のノードが落ちた場合、システムが利用できなくなるため、ノードを再起動する前にリカバリ手順をより困難にし、一貫性を復元できます。

公式ドキュメントの 2フェーズトランザクションを使用しないのはなぜですか?


彼らは複数のクライアントで動作しないためです。 より正確に機能しますが、大きな制限があります。

そうしないと、一貫性と可用性が失われます(凍結されたトランザクションは可能です-唯一の合理的なステップは、これらのトランザクションに参加するオブジェクトの読み取り/書き込みを拒否することです)。

Source: https://habr.com/ru/post/J153321/


All Articles