1. ホーム
  2. mongodb

[解決済み] MongoDBのトランザクション不足を回避する方法とは?

2022-05-10 22:57:50

質問

似たような質問があることは知っていますが、それらはどちらかというと を教えてください を使うか、トランザクションが必要なら通常の RDBMS システムに切り替えるか、あるいは 原子操作 または 二相コミット . 2番目の解決策は最良の選択と思われます。3番目の方法は、多くのことがうまくいかない可能性があり、すべての面でそれをテストすることができないので、私はそれに従いたくありません。私はアトミック操作を実行するために私のプロジェクトをリファクタリングするのに苦労しています。これは私の限られた視点(これまでSQLデータベースしか扱ったことがない)から来るものなのか、それとも実際にはできないものなのか、わかりません。

私たちの会社でMongoDBをパイロットテストしたいと思います。私たちは比較的単純なプロジェクト、SMS ゲートウェイを選びました。これは、私たちのソフトウェアが携帯電話ネットワークに SMS メッセージを送信することを可能にし、ゲートウェイが汚れ仕事をします。また、ゲートウェイはメッセージの課金も管理します。サービスを申し込んだお客様は、クレジットを購入する必要があります。メッセージを送ると自動的に残高が減り、残高不足になるとアクセスが拒否される仕組みです。また、私たちはサードパーティのSMSプロバイダーの顧客であるため、彼らとの間で独自の残高を持つこともあります。私たちは、それらも記録しておかなければなりません。

私は、いくつかの複雑さ (外部請求、キューに入った SMS 送信) を削減する場合、MongoDB で必要なデータをどのように保存できるかを考え始めました。SQL の世界から来た私は、ユーザー用に別のテーブルを作成し、SMS メッセージ用に別のテーブルを作成し、ユーザーの残高に関するトランザクションを保存するためのテーブルを作成します。MongoDBでこれらすべてのために別々のコレクションを作成するとします。

この単純化されたシステムで、次のようなステップでSMSを送信するタスクを想像してください。

  1. ユーザーが十分な残高を持っているかどうかを確認する。十分な残高がない場合はアクセスを拒否する。

  2. 詳細とコストを含むメッセージを送信し、SMSコレクションに保存します(ライブシステムでは、メッセージには status 属性があり、タスクは配信のためにそれをピックアップし、現在の状態に応じてSMSの価格を設定します)

  3. ユーザーの残高を送信したメッセージのコスト分だけ減らす

  4. トランザクションコレクションにトランザクションを記録する

さて、これの何が問題なのでしょうか?MongoDBは1つのドキュメントに対してのみアトミックな更新を行うことができます。先ほどのフローでは、何らかのエラーが発生し、メッセージがデータベースに保存されても、ユーザーの残高は更新されず、トランザクションは記録されないということが起こり得ます。

私は2つのアイデアを思いつきました。

  • ユーザーに対して単一のコレクションを作成し、残高をフィールドとして、ユーザー関連のトランザクションとメッセージをユーザーのドキュメントにサブドキュメントとして格納します。ドキュメントをアトミックに更新することができるので、これは実際にトランザクションの問題を解決しています。デメリット:ユーザーが多くのSMSメッセージを送信すると、ドキュメントのサイズが大きくなり、4MBのドキュメントの制限に達する可能性があります。そのようなシナリオでは履歴ドキュメントを作成できるかもしれませんが、これは良いアイデアとは思えません。また、同じ大きなドキュメントにどんどんデータをプッシュした場合、システムがどの程度速くなるのかわかりません。

  • ユーザー用のコレクションを1つ、トランザクション用のコレクションを1つ作成します。トランザクションは2種類存在する可能性があります。 クレジット購入 という2種類の取引があります。 メッセージの送信 で、残高がマイナスになったときに送信されます。トランザクションはサブドキュメントを持つことができます。 送信されたメッセージ で、SMSの詳細は、トランザクションに埋め込むことができます。デメリット 現在のユーザー残高を保存していないので、ユーザーがメッセージを送信しようとするたびにそれを計算して、メッセージが送信されるかどうかを判断しなければなりません。この計算は、保存されるトランザクションの数が増えるにつれて遅くなる可能性がありますね。

どの方法を選ぶべきか、少し迷っています。他の解決策はありますか? この種の問題を回避する方法について、ネット上でベストプラクティスを見つけることができませんでした。NoSQLの世界に慣れようとしている多くのプログラマーが、最初は同じような問題に直面しているのでしょう。

どのように解決するのですか?

4.0では、MongoDBはマルチドキュメントのACIDトランザクションを持つようになります。計画では、まずレプリカセットのデプロイメントでそれを有効にし、次にシャード化されたクラスタで有効にすることになっています。MongoDB のトランザクションは、開発者がリレーショナルデータベースで慣れ親しんでいるトランザクションと同じように感じられるでしょう。 start_transactioncommit_transaction ). 重要なのは、トランザクションを可能にする MongoDB の変更は、トランザクションを必要としないワークロードのパフォーマンスに影響を与えないということです。

詳細については をご覧ください。 .

分散トランザクションがあるからといって、表形式のリレーショナルデータベースのようにデータをモデル化する必要はありません。文書モデルのパワーを受け入れ、優れた推奨される プラクティス に従いましょう。