注文の繰り返し提出を防ぐ戦略と方法

藏色散人
リリース: 2023-04-06 16:42:01
転載
5665 人が閲覧しました

背景

ビジネス開発では、リクエストの繰り返しを防ぐという問題に直面することがよくあります。リクエストに対するサーバーの応答にデータの変更やステータスの変更が含まれる場合、大きな損害を引き起こす可能性があります。繰り返しのリクエストによる影響は、トランザクション システム、販売後の権利保護、支払いシステムにおいて特に深刻です。

フォアグラウンド操作、高速操作、ネットワーク通信、またはバックエンドの応答にジッターがあると、バックエンド処理が繰り返される可能性が高くなります。フロントエンド操作をデバウンスし、高速操作を防ぐための対策を講じるために、まずフロントエンドの制御層について考えます。フロントエンドが操作をトリガーすると、確認インターフェイスがポップアップ表示されたり、エントリが無効になったりする場合があり、カウントダウンなどについてはここでは詳しく説明しません。しかし、フロントエンドの制限だけでは解決できる問題は少なく、十分に徹底されていないため、バックエンド独自の重複防止対策が不可欠かつ義務化されています。

インターフェイスの実装では、繰り返されるリクエストのうち 1 つだけが有効であることを保証するために、インターフェイスが冪等性を満たす必要があることがよくあります。

クエリ クラスのインターフェイスはほとんどの場合冪等ですが、データの挿入や複数モジュールのデータ更新が含まれる場合、冪等、特に同時実行性が高い場合の冪等の要件を達成することがより困難になります。たとえば、サードパーティの支払いフロントエンド コールバックとバックグラウンド コールバック、サードパーティの支払いバッチ コールバック、遅いビジネス ロジック (ユーザーが返金申請を提出する、加盟店が返品/返金に同意するなど)、または低速なネットワーク環境が原因で、繰り返し処理のリスクシナリオ。

お試しください

ここでは、試した重複防止処理方法の効果を説明するために、「ユーザーが返金申請を送信する」例を示します。バックエンドの重複防止処理の 3 つの方法を試しました。

(1) DB の返金注文ステータスに基づく検証

この方法はシンプルで直感的であり、DB Refund からクエリされます。詳細 (ステータスを含む) は、繰り返しのリクエストに対処するために特別な作業を費やすことなく、後続のロジックでも使用できることがよくあります。

ステータスをクエリした後のこの種の検証ロジックは、コードがオンラインになって以来、ステータスを含むすべてのビジネス ロジック処理に常に存在しており、不可欠です。ただし、重複防止処理の効果は良好ではありません。フロントエンドに重複防止送信を追加する前は、平均数が 1 週間あたり 25 件でしたが、フロントエンドの最適化後は、平均数が 1 週間あたり 7 件に減少しました。この数字は払い戻し申請総数の 3% を占めており、この割合は依然として受け入れがたいものです。

理論的には、データのステータスが更新される前にリクエストがクエリ操作を完了する限り、ビジネス ロジックの処理が繰り返し発生します。以下に示すように。最適化の方向性は、クエリと更新の間のビジネス処理時間を短縮することです。これにより、ギャップ期間による同時実行性の影響を軽減できます。極端な場合、クエリと更新がアトミック操作になれば、現在の問題は存在しなくなります。

注文の繰り返し提出を防ぐ戦略と方法

# (2) キャッシュされたデータの状態に基づく検証

Redis ストレージ クエリは軽量かつ高速です。リクエストが到着すると、最初にキャッシュに記録できます。後続の受信リクエストは毎回検証されます。プロセス全体が完了し、キャッシュがクリアされます。払い戻しを例に挙げます:

  • I. 払い戻し申請が開始されるたびに、キーとして orderId を持つ値がキャッシュ内にあるかどうかを読み取ります
  • II. ない場合は、キャッシュに移動します。 orderId をキーとして value
  • III を書き込みます。「はい」の場合、この注文の返金が進行中であることを意味します。
  • IV. 操作後にキャッシュをクリアするか、キャッシュに値が保存されるときのライフサイクルを設定します。

1) の発行と比較して、データベースは次のキャッシュに置き換えられます。より速い応答。しかし、まだアトミックな操作ではありません。キャッシュの挿入と読み取りの間には、まだ時間間隔があります。極端な場合には、依然として操作が繰り返される場合があります。この方法が最適化された後、この操作は週に 1 回繰り返されます。

注文の繰り返し提出を防ぐ戦略と方法

(3) 一意のインデックス機構を使用した検証

はアトミックな操作が必要なので、データベースの一意のインデックスを考えました。新しい TradeLock テーブルを作成します:

CREATE TABLE `TradeLock` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`type` int(11) NOT NULL COMMENT '锁类型',
`lockId` int(11) NOT NULL DEFAULT '0' COMMENT '业务ID',
`status` int(11) NOT NULL DEFAULT '0' COMMENT '锁状态',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='Trade锁机制';
ログイン後にコピー

# リクエストが受信されるたびに、データがテーブルに挿入されます:

成功,则可以继续操作(相当于获取锁);
失败,则说明有操作在进行。
ログイン後にコピー

# 操作が完了したら、このレコードを削除します。 (ロックを解除することに相当)。

現在オンラインになっており、来週のデータ統計を待っています。

注文の繰り返し提出を防ぐ戦略と方法

(4) キャッシュベースのカウンタ検証

データベース操作は比較的高いパフォーマンスを消費するため、redis カウンタもアトミック操作であることがわかりました。カウンターを思い切って使いましょう。パフォーマンスが向上するだけでなく、ストレージの必要性がなくなり、ピーク QPS も向上します。

注文の払い戻しを例に挙げてみましょう:

# リクエストが受信されるたびに、キーとして orderId を持つ新しいカウンターが作成され、+1 されます。

如果>1(不能获得锁): 说明有操作在进行,删除。
如果=1(获得锁): 可以操作。
ログイン後にコピー

# 操作の終了 (ロックの削除): このカウンタを削除します。

rreeee

注文の繰り返し提出を防ぐ戦略と方法

总结:

PHP语言自身没有提供进程互斥和锁定机制。因此才有了我们上面的尝试。网上也有文件锁机制,但是考虑到我们的分布式部署,建议还是用缓存。在大并发的情况下,程序各种情况的发生。特别是涉及到金额操作,不能有一分一毫的差距。所以在大并发要互斥的情况下可以考虑3、4两种方案。

爱迪生尝试了1600多种材料选择了钨丝发明了灯泡,实践出真知。遇到问题,和问题斗争,最后解决问题是一个最大提升自我的过程,不但加宽自己的知识广度,更加深了自己的技能深度。达到目标之后的成就感更是不言而喻。
ログイン後にコピー


以上が注文の繰り返し提出を防ぐ戦略と方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:cnblogs.com
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート