#製品と注文サービスの間で MQ を使用する
製品サービスの在庫が変更されると、注文サービスのインベントリは、MQ Variety を通じて通知されます。元の同期プロセス
// 原始的MySQL同步流程// 判断此代金券是否加入抢购SeckillVouchers seckillVouchers = seckillVouchersMapper.selectVoucher(voucherId);AssertUtil.isTrue(seckillVouchers == null, "该代金券并未有抢购活动");// 判断是否有效AssertUtil.isTrue(seckillVouchers.getIsValid() == 0, "该活动已结束");// 插入数据库seckillVouchersMapper.save(seckillVouchers);
問題があります
異なるサービスのデータベースへのアクセスは避ける 同一サービスは原則として自身のサービスのデータベースのみ操作可能です。
MQ の非同期化
まず、ステップ 4 のみを非同期にすることを検討します。分析
2 と 4 はすべてデータベース上の操作です。ステップ 4 は待機しません。ステップ 1 の成功後、すぐにユーザーにフィードバックが与えられます。 2、および3。 その後、注文はメッセージ通知サービスを通じて非同期に発注されます。手順 4 の非同期発注が失敗した場合は、操作が再試行され、注文が再生成されます。MQ メッセージも追跡できます。戻る。
オーダーが作成されるとキュー状態になり、サービスはイベント
Order Created をメッセージ キューに発行します。
つまり、注文サービスはメッセージを外部に送信します。注文を作成すると、その注文が MQ によってメッセージをサブスクライブするサービスに転送されます。
注文サービスは在庫控除の結果をサブスクライブします。メッセージを受信した後:
に変更されます。成功
、つまり注文が失敗した
非同期設計
は、 mysql インベントリ
を差し引かないでください。
redis 在庫が差し引かれると、製品を注文できなくなり、注文が失敗するため、外側の層がブロックされます。
MQ非同期的に分離されたタスクキュー、このプロセスは
mysqlインベントリの控除
支払い前は 源泉徴収
、それはredis インベントリの控除 、つまり在庫をロックするプロセスです
支払い後は、実際の控除、mysql インベントリーの控除
、インベントリーが最終的に一貫性があることを確認してくださいただし、極端な場合にはデータの不整合が発生する可能性があります
If redis inventory = mysql の在庫では問題ありません。
データベース インベントリと Redis インベントリに一貫性がありません。それを検出するにはどうすればよいですか?
不一致が検出された場合の同期方法
良い計画が思いつきません
もっと乱暴な方法は、午前1時などの低ピーク時間帯、定期的な強制取材。ただし、極端な場合には、同期後も不正確さが残る可能性があります。たとえば、同期プロセス中に、たまたま注文の支払いが発生しました。注文が正常に支払われた後、MySQL 在庫はアウトバウンド プロセス中に差し引かれますが、 Redis インベントリは差し引かれません。
これはデータベース同期キャッシュの更新メカニズムに問題があります
これは一貫した論理設計の問題ですキャッシュ番号 = データベース インベントリ番号 - 番号差し引かれます
もちろん、他の解決策もあり、一貫性の要件を考慮すると、単純な解決策も複雑な解決策も使用できます
システムの複雑さに依存します。システムが大規模になるほど、より詳細な情報が必要になります。細分化する必要があります
たとえば、差し引かれる数値をキューまたはキャッシュに置くことができ、同時にカウントもあります。カウントを直接読み取るだけです。
たとえば、それが配置された場合モンゴでは、支払われて出荷される数量は一般にそれほど多くありません。数えるだけで大丈夫です。それほど多くは失われません。
したがって、一般的なシステムでは、データ チェーンが確実に機能することを完全に保証することはできません。エラーは発生しませんが、補償が必要です。つまり、エラーは修正できます。
エラーがないことを保証するコストは明らかに高すぎます。
一連の同期が存在します。リフレッシュ メカニズムはスケジュール設定できます。 MQ を介して行うことも、同期との不整合を監視することもできます。 。 。
キャッシュされたデータの鮮度の確保とも呼ばれます
一般的には、30 分か数分程度で完了します。シナリオが異なればニーズも異なります
12306
12306 電車の切符を購入する場合、夜間は切符を購入できません。これはおそらく在庫を同期し、データベースの在庫を Redis インベントリーに同期させるためです。ただし、電車の切符を購入する場合は、実際の金額を差し引く必要があります。注文が生成される前に、在庫、つまり、mysql の在庫を差し引く必要があります。
鉄道の切符を買うのは、ショッピングとは異なります。ショッピングは支払い後に倉庫から発送できますが、チケットを購入するのは、決済前にチケットを倉庫から発送する必要があるため、在庫から発送する在庫を差し引く必要がある 倉庫処理が進められ、倉庫の発送が成功して初めて注文が生成される Redis在庫の導入も必要.
キャッシュ内のインベントリを最初に差し引く必要があります。差し引きが成功した後、mysql 内のインベントリを差し引くことができます。
キャッシュ内のインベントリが差し引かれなかった場合、キャッシュはブロックされ、不十分なインベントリが返されます。これらのリクエストは mysql にパンクチャされず、リクエストの圧力のほとんどがブロックされます。
Redis インベントリは、mysql インベントリと不一致になります。極端な場合には、いくつかの不一致があるはずであり、インベントリの同期が必要です。
キャッシュ在庫がデータベース在庫より多い場合 多すぎると、クエリにはチケットがあるように見えますが、注文することができず、注文すると在庫が足りないと言われます。この場合、データベースに過剰な負荷がかかりますが、12306 にはこの問題を回避する別の手段があるはずですが、実際に、チェックしたときにチケットがあったのに注文できないという状況に遭遇しました。
キャッシュ在庫がデータベース キャッシュより少ない場合は問題ありません。チケットのみが存在し、販売はありません。在庫の同期が完了すると、再び正確になります。明日。
以上がRedis での売れすぎ在庫の問題の解決の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。