マイクロサービス(.NET CoreとKubernetes)、イベントソーシング(Kafka)、CQRSを使用してeコマースシステムを具体化しようとしています。私が考えている特定のユースケースは次のとおりです。
CQRSを使用するように設計されたインベントリマイクロサービスがあります。更新はKafkaとしてイベントとして提供されます。これは、インベントリマイクロサービスがマテリアライズドビューを更新するために消費し、読み取りはマテリアライズドビューに対して直接実行されます。私が対処しようとしている問題は、現在の設計では、注文は注文マイクロサービスで作成され、在庫マイクロサービスが消費し、注文の一部である在庫を差し引くイベントを発行します。ただし、ここには競合状態があります。別の購入者が以前の注文の在庫が差し引かれる前に同じ製品を購入する。
マイクロサービスにまたがるこのタイプのトランザクション操作をどのように処理しますか?マテリアライズドビューではなくストリームに対してストックを検証する必要があることを読んだことがありますが(ストリームは実際の真のソースであるため)、それがどのように実用的であるかについては少し曖昧です(ストリームが巨大になる可能性があるため) 。それを行うつもりなら、なぜそれを信頼できないのにマテリアライズドビューも持っているのですか?
私の経験では、トランザクション可能性とマイクロサービスに関するほとんどの質問は、次の2つの理由が原因です。
トランザクションデータはさまざまなマイクロサービスに配置されます。これは、定義上間違っています。トランザクションで変更する必要があるデータは、同じサービスに属しています。適切なサービスで適切なデータをグループ化することは非常に困難であり、十分に検討する必要があります。エンティティ(注文、ユーザー、在庫、製品など)に基づいてマイクロサービスを作成するだけの場合、同じ問題が何度も繰り返され、さらに、目的を実行するために他のN個のサービスに依存するN個のサービスが発生します。したがって、トランザクションで変化するすべてのデータをまとめます。
そもそも操作はトランザクションではありません。ビジネスルールで解決すべき何かをテクノロジーで解決しようとしています。これは私の意見ではあなたのシナリオです。注文と在庫はトランザクションではありません。在庫切れの商品を購入したくないのは明らかですが、これが発生する可能性は常にわずかにあります(在庫数は正しいが、倉庫の誰かが箱を落として最後の商品を壊した場合)項目?)。企業は、トランザクションが存在するよりはるかに長い間、この種の問題に対処してきました。したがって、ビジネスに話しかけて、注文が入ってきて在庫がなくなったときに何をすべきかを尋ねます。適切な在庫管理が行われていれば、新しい商品がいつ利用可能になるかはすでにわかっているため、顧客に新しい配達日をメールで送信し、受け入れない場合は(例として)払い戻しを提供できます。
補足として、「在庫マイクロサービスから在庫を差し引くためのイベントを発行する注文マイクロサービス」という文章は間違っているようです。それは単なる文言かもしれませんが、念のため、この文言は、あなたがしていることがイベントではなくコマンドを発行していることを示唆していることを指摘したいと思います。コマンドは必須であり、誰かに何かをするように伝えます(DeductInventoryCommand)。イベントは既に発生したものです(OrderPlacedEvent)。
理想的には、コマンドを受け取るサービスの自律性を実質的に破壊するため、あるマイクロサービスが別のマイクロサービスに何をすべきかを伝えたくないでしょう。代わりに、他のマイクロサービスから「聞いた」情報に基づいて、自律的に、ビジネス機能を実行できるようにサービスを開発します。ロジスティクスサービスは、行われた注文(およびキャンセルされた注文)をリッスンして、何をすべきかを知らされることなくすべてのロジスティクスプロセスを処理できます。課金は、どちらを実行するかを指示されることなく、その仕事を実行できなければなりません。
レビュー 競合条件は存在しません 、Udi Dahan著。
以前の注文の在庫が差し引かれる前に、別の購入者が同じ製品を購入する可能性があります。
うん-それが起こったときにビジネスは何をしますか?おそらくより多くの在庫を注文したり、顧客に払い戻しと謝罪を提供したりすることを含むプロトコルがあるでしょう...可能性はたくさんあります。
Pat Hellandの 記憶、推測、謝罪 は、もう1つの重要な資料です
ビジネスの現実は謝罪を強制します。これらの困難な現実に対処するには、コードが必要であり、多くの場合、謝罪する人間が必要です。企業がこれらの謝罪を管理するには、コードと人の両方が必要です。
結局のところ、コンピューターは現実の世界ではなく、コンピューター自体の内部シミュレーションを見ています。 「コンピューターにできる最善のことは、推測することです。」
前の注文の在庫が差し引かれる前に、別のバイヤーが同じ製品を購入する可能性があります。
この問題は、使用するテクノロジーに関係なく発生します。これは、問題の一時的な性質に固有のものです。 2つの解決策があります。楽観的または悲観的です。
会社が在庫を予約できるトランザクションを作成します。これは、注文を確定する前に行う必要があります。これの問題は、顧客に予約をしてもらい、予約の注文や解放に失敗する可能性があることです。それまでの間、お客様はこれらの商品を予約できないため、売り上げを失う可能性があります。
顧客が注文を出し、注文時に在庫を確認して更新します。誰かが満たすことができないアイテムをリクエストすると、あなたはそれを伝えるレスポンスを返します。注文を完全に満たすか、部分的に満たすかを指定するリクエストを許可することをお勧めします。
どちらの方法でも、注文要求と在庫管理を分離することはできません。何十年も前から存在しているシステムでは、これらの注文要求と応答は通常非同期です。これにより、リクエストの順序付けと合理化が可能になります。
一般にeコマースでは、在庫レベルをチェックしません。それは単に物事を遅くします。
ただし、さらに大きな問題がいくつかあります。
従来のデータベーストランザクションでは、在庫レベルの予約を実際に処理することはできません。これは注文プロセスを人間がクリックするためのものなので、トランザクションが単純に長時間開かれます。
これにより、代わりに在庫予約システムを実装できます。これには本当の問題はありません。在庫マイクロサービスを在庫データベースの前に配置するか、kafka話す)の「マテリアライズドビュー」を使用して、RPCスタイルのメッセージで在庫を予約し、商品の在庫がないことを確認できます。
アイテムを購入しようとするユーザーは、最初にStockMicroserviceを介して在庫を予約しようとし、その時点で利用可能なものがないことを知らされます。
ここでの主な問題は、ビジネスイベントをkafkaストリーミングデータベースイベントにまとめることです。
ビジネスイベントが常に状態の変化をもたらすとは限りません。