私はデータベースの専門家ではなく、正式なコンピューターサイエンスのバックグラウンドも持っていません。 現実世界の古いものを使用した場合に発生する可能性のあるマイナスの種類を知りたい v4より前のMongoDBバージョン 、 ACID に準拠していませんでした。これは、ACID非準拠データベースに適用されます。
MongoDBは Atomic Operations を実行できることを理解していますが、主にパフォーマンス上の理由から、「従来のロックと複雑なトランザクションをサポート」していません。また、データベーストランザクションの重要性、およびデータベースが銀行向けであり、すべての同期が必要な複数のレコードを更新している場合、トランザクションが初期状態に戻る場合の例を理解していますクレジットが購入などに等しい停電.
しかし、MongoDBに関する会話を始めると、データベースが実際にどのように実装されているかの技術的な詳細を知らない私たちは、次のようなステートメントを投げ始めます。
MongoDBはMySQLやPostgresよりもはるかに高速ですが、100万分の1など、「正しく保存されない」というわずかな可能性があります。
「正しく保存されない」という部分は、この理解を指します。MongoDBに書き込みを行っている瞬間に停電が発生した場合、特定のレコードが記録される可能性があります(たとえば、10個の属性を持つドキュメントのページビューを追跡しているそれぞれ)、そのドキュメントの1つは5つの属性しか保存していません…つまり、ページビューカウンタはやがて「少し」オフになります。どれだけ正確かはわからないでしょう。99.999%が正しいことはわかりますが、100%は正しいとは限りません。これは、特にこれを mongodbアトミック操作 にしない限り、操作がアトミックであることが保証されないためです。
私の質問は、MongoDBが「正しく保存」されない場合とその理由の正しい解釈は何ですか? ACIDのどの部分が満たされていないか、どのような状況下で、0.001%のデータがオフになっていることをどのように確認しますか?これはどういうわけか修正できませんか?そうでない場合、レコードは保存されない可能性があるため、MongoDBにusers
テーブルのようなものを保存しないでください。しかし、その場合も、その1/1,000,000ユーザーは「もう一度サインアップしてみる」だけでいいのではないでしょうか。
MongoDBなどのACID非準拠データベースでネガティブな事態が発生するタイミングと理由のリストを探しているだけで、標準的な回避策がある場合(バックグラウンドジョブを実行してデータをクリーンアップする、SQLのみを使用するなど) 。
MongoDBで失うことの1つは、マルチコレクション(テーブル)トランザクションです。 MongoDBのアトミック修飾子は、単一のドキュメントに対してのみ機能します。
在庫からアイテムを削除し、同時に誰かの注文に追加する必要がある場合は、できません。在庫と注文という2つのものが同じドキュメント内に存在しない限り(おそらく存在しません)。
私が取り組んでいるアプリケーションで、これとまったく同じ問題に遭遇しました。選択できる解決策は2つありました。
1)ドキュメントを可能な限り最善の方法で構造化し、アトミック修飾子を可能な限り使用します。残りの部分では、バックグラウンドプロセスを使用して、同期していない可能性のあるレコードをクリーンアップします。たとえば、インベントリからアイテムを削除し、アトミック修飾子を使用して同じドキュメントのreservedInventory配列に追加します。
これにより、アイテムが在庫にないことを常に知ることができます(顧客によって予約されているため)。顧客がチェックアウトしたら、reservedInventoryからアイテムを削除します。これは標準的なトランザクションではなく、顧客がカートを放棄できるため、放棄されたカートを調べて予約済み在庫を利用可能な在庫プールに戻すバックグラウンドプロセスが必要です。
これは明らかに理想的とは言えませんが、mongodbがニーズに完全に適合しない大規模アプリケーションの唯一の部分です。さらに、これまでのところ問題なく動作します。これは多くのシナリオでは不可能な場合がありますが、私が使用しているドキュメント構造のため、うまく適合しています。
2)トランザクションデータベースをMongoDBと組み合わせて使用します。 MySQLを使用して、MongoDB(またはその他のNoSQL)に最善を尽くしながら、絶対に必要なものにトランザクションを提供するのが一般的です。
#1のソリューションが長期的に機能しない場合は、MongoDBとMySQLの組み合わせについてさらに調査しますが、現時点では#1がニーズに合っています。
MongoDBがACIDに準拠していないことは実際には正しくありません。それどころか、MongoDBはACIDに準拠しています、ドキュメントレベル。
単一のドキュメントの更新は
MongoDBにないのは、transactions-つまり、複数のドキュメントを更新できることです。ロールバックされ、ACIDに準拠しています。
2フェーズコミットを使用 により、単一のドキュメントに対するACID準拠の更新の上にトランザクションを構築できることに注意してください。
適切な説明は 「スターバックスは2フェーズコミットを使用しない」 に含まれています。
これはNoSQLデータベースに関するものではありませんが、トランザクションを失ったり、一時的にデータベースを一貫性のない状態にしたりする余裕がある場合があることを示しています。
私はそれを「修正」する必要があるものとは思わないでしょう。修正方法は、ACID準拠のリレーショナルデータベースを使用することです。動作がアプリケーションの要件を満たしている場合、NoSQLの代替を選択します。
他の人はすでに良い答えをしてくれたと思います。ただし、ACID NOSQL DB( http://ravendb.net/ など)があることを追加したいと思います。 NOSQLの決定だけではありません-ACIDとACIDの関係はありません。
「正しく保存しない」とは、次のことを意味します。
デフォルトでは、MongoDBは変更をすぐにドライブに保存しません。そのため、ユーザーに「更新が成功した」と伝え、停電が発生し、更新が失われる可能性があります。 MongoDBには、更新の「耐久性」のレベルを制御するオプションがあります。他のレプリカがこの更新を(メモリ内で)受け取るのを待ち、ローカルジャーナルファイルへの書き込みが発生するのを待ちます。
複数のコレクションや、同じコレクション内の複数のドキュメントに対する簡単な「アトミック」更新はありません。 Two Phase Commit で回避できるか、スキーマが再構築されて単一のドキュメントが更新されるため、ほとんどの場合は問題になりません。この質問を参照してください: ドキュメントデータベース:冗長データ、参照など(具体的にはMongoDB)
MongoDB v4.0以降、マルチドキュメントACIDトランザクションがサポートされる予定です。スナップショット分離により、トランザクションはデータのグローバルに一貫したビューを提供し、データの整合性を維持するためにオールオアナッシングの実行を実施します。
彼らは、リレーショナル世界からの取引のように感じます、例えば:
with client.start_session() as s:
s.start_transaction()
try:
collection.insert_one(doc1, session=s)
collection.insert_one(doc2, session=s)
s.commit_transaction()
except Exception:
s.abort_transaction()
https://www.mongodb.com/blog/post/multi-document-transactions-in-mongodb を参照してください
ACIDプロパティ を読んで理解を深めてください。
MongoDBのドキュメントでも question and answer を見つけることができます。
MongoDBはACIDに準拠していません。 ACIDコンプライアンスの説明については、以下をお読みください。
A
tomicです。リレーショナルデータベースシステムから知っているアトミックの定義、特に上記のリンクには準拠していません。この意味で、MongoDBはACIDのAに準拠していません。C
onsitentです。 ただし、レプリカセット内のセカンダリサーバーから読み取ることができます。この場合、最終的な整合性のみを持つことができます。これは、少し古いデータを読むことを気にしない場合に便利です。I
solationを保証しません(上記の定義による):
- 複数のリーダーとライターが同時に存在するシステムの場合、MongoDBを使用すると、クライアントは書き込み操作が戻る前に書き込み操作の結果を読み取ることができます。
- ジャーナルがコミットする前にmongodが終了した場合、書き込みが正常に戻ったとしても、mongodの再起動後に存在しないデータがクエリに読み込まれる可能性があります。
ただし、、MongoDBは各ドキュメントを個別に変更します(挿入および更新用)。マルチドキュメントトランザクションではなく、ドキュメントレベルでのみ。
D
urabilityに関しては、write concern
オプションでこの動作を設定できますが、確かではありません。たぶん誰かがよく知っている。NoSQLをACID制約などに移行するための研究が進行中であると思います。 NoSQLデータベースは通常高速であり、ACID制約によりパフォーマンスが大幅に低下する可能性があるため、これは課題です。
アトミックが単一コレクションに対する作業を変更する唯一の理由は、mongodb開発者が最近、データベース全体のロックをコレクション全体の書き込みロックと交換したためです。ここでの並行性の向上はトレードオフの価値があると判断しました。その中核となるmongodbはメモリマップドファイルです。バッファプール管理をマシンのvmサブシステムに委任しています。常にメモリ内にあるため、非常に粗いロックで逃げることができます。それを保持している間はメモリ内のみの操作を実行します。これは非常に高速です。これは、ページロックまたは行ロックを保持しながらI/Oの実行を強制されることがある従来のデータベースシステムとは大きく異なります。
「MongoDBでは、単一のドキュメントに対する操作はアトミックです」-それが過去のことです
MongoDBの新しいバージョン4.0では次のことができます。
ただし、複数のドキュメントの更新のアトミック性または複数のドキュメントの読み取り間の一貫性を必要とする状況では、MongoDBはレプリカセットに対してマルチドキュメントトランザクションを実行する機能を提供します。マルチドキュメントトランザクションは、複数の操作、コレクション、データベース、およびドキュメントで使用できます。マルチドキュメントトランザクションは、「すべてか無か」という命題を提供します。トランザクションがコミットされると、トランザクションで行われたすべてのデータ変更が保存されます。トランザクション内のいずれかの操作が失敗すると、トランザクションは中止され、トランザクション内で行われたすべてのデータ変更は表示されることなく破棄されます。トランザクションがコミットされるまで、トランザクション内の書き込み操作はトランザクションの外部からは見えません。
ただし、HowおよびWhat操作の実行には制限があります。
Mongo Docを確認してください。 https://docs.mongodb.com/master/core/transactions/
ストレージがキーごとの線形化と比較および設定をサポートしている場合(MongoDBの場合)、クライアント側でアトミックマルチキー更新(シリアル化可能なトランザクション)を実装できます。このアプローチは GoogleのPercolator および CockroachDB で使用されていますが、MongoDBで使用することを妨げるものは何もありません。
このようなトランザクションの ステップバイステップの視覚化 を作成しました。それらを理解するのに役立つことを願っています。
読み取りコミットされた分離レベルに問題がない場合は、Peter Bailisによる RAMPトランザクション を確認することをお勧めします。クライアント側でMongoDBに実装することもできます。