同様の質問がここにあることは知っていますが、トランザクションが必要な場合、またはアトミック操作または2フェーズコミットを使用する場合は、通常のRDBMSシステムに切り替えるように指示しています。2番目のソリューションが最良の選択のようです。3つ目は、多くの問題が発生する可能性があり、あらゆる面でテストすることができないため、フォローしたくありません。アトミック操作を実行するためにプロジェクトをリファクタリングするのに苦労しています。これが私の限られた視点から来たのか(これまでSQLデータベースでしか作業していない)のか、それとも実際に実行できないのかはわかりません。
弊社でMongoDBをパイロットテストしたいと思います。私たちは比較的単純なプロジェクト、つまりSMSゲートウェイを選択しました。私たちのソフトウェアがSMSメッセージをセルラーネットワークに送信することを可能にし、ゲートウェイは、実際にはさまざまな通信プロトコルを介してプロバイダーと通信するという汚い仕事をします。ゲートウェイは、メッセージの請求も管理します。サービスを申請するすべての顧客は、いくつかのクレジットを購入する必要があります。システムは、メッセージが送信されると自動的にユーザーの残高を減らし、残高が不足している場合はアクセスを拒否します。また、私たちはサードパーティのSMSプロバイダーのお客様であるため、独自の残高を提供する場合もあります。それらも追跡する必要があります。
複雑さを軽減する場合(外部請求、キューSMS送信)、MongoDBで必要なデータを保存する方法について考え始めました。SQLの世界から来て、ユーザー用の別のテーブル、SMSメッセージ用の別のテーブル、およびユーザーのバランスに関するトランザクションを格納するためのテーブルを作成します。MongoDBのすべてのコレクションを個別に作成するとします。
この簡略化されたシステムで次の手順を実行するSMS送信タスクを想像してください。
ユーザーに十分なバランスがあるかどうかを確認します。十分なクレジットがない場合はアクセスを拒否します
詳細とコストを含むSMSコレクションにメッセージを送信して保存します(ライブシステムではメッセージに
status
属性があり、タスクは配信のためにそれを取得し、現在の状態に応じてSMSの価格を設定します)送信されたメッセージのコストによってユーザーのバランスを減らす
トランザクションをトランザクションコレクションに記録する
それで問題は何ですか?MongoDBは、1つのドキュメントに対してのみアトミック更新を実行できます。前のフローでは、なんらかのエラーが発生し、メッセージがデータベースに格納されても、ユーザーの残高が更新されなかったり、トランザクションがログに記録されなかったりする場合があります。
私は2つのアイデアを思いつきました:
ユーザーの単一のコレクションを作成し、残高をフィールドとして保存し、ユーザー関連のトランザクションとメッセージをユーザーのドキュメントのサブドキュメントとして保存します。ドキュメントをアトミックに更新できるため、実際にはトランザクションの問題が解決されます。短所:ユーザーが多数のSMSメッセージを送信すると、ドキュメントのサイズが大きくなり、4MBのドキュメント制限に達する可能性があります。そのようなシナリオで履歴ドキュメントを作成できるかもしれませんが、これは良い考えではないと思います。また、同じ大きなドキュメントにさらに多くのデータをプッシュすると、システムがどのくらい高速になるかわかりません。
ユーザー用とトランザクション用に1つのコレクションを作成します。トランザクションには、正の残高変更のあるクレジット購入と負の残高変更のある送信メッセージの 2種類があります。トランザクションにはサブドキュメントがある場合があります。たとえば、送信されたメッセージでは、SMSの詳細をトランザクションに埋め込むことができます。欠点:現在のユーザーの残高は保存しないので、ユーザーがメッセージを送信しようとするたびに計算して、メッセージが通過できるかどうかを判断する必要があります。保存されたトランザクションの数が増えると、この計算が遅くなる可能性があります。
どの方法を選択するかについて少し混乱しています。他の解決策はありますか?これらの種類の問題を回避する方法に関するオンラインのベストプラクティスを見つけることができませんでした。NoSQLの世界に慣れようとするプログラマーの多くは、最初は同様の問題に直面していると思います。