0

私の質問がこのサイトに適していて、広すぎないことを願っていますが、次のアーキテクチャの設計に問題があります。

私は2つのサイトを持っています。サイト 1 は、ユーザー間のクレジットの転送を担当します。サイト 2 は、これらのユーザーに、サイト 1 で所有するクレジットで支払うことができるサービス/製品を提供する責任があります。

サイト 1 で 1000 クレジットを持っているとします。サイト 2 で 50 クレジットのサービス/製品があり、ユーザーがサイト 1 で所有しているクレジットの量でそれを購入したいと考えています。

どちらのサイトも REST と通信します。したがって、たとえば、ユーザーがサービス/製品を購入したい場合、サイト 2 はその要求を準備し、それをサイト 1 に送信します。サイト 1 は取引を行い、取引が成功したことをサイト 2 に確認します (たとえば、ユーザーはサービス/製品に対して十分なクレジットを持っていました)。これらのクレジットは宛先に正常に転送されました)

ここがトリッキーな部分です。サイト 1 には、次のロジックがあります。

Begin transaction
update user set credits -= 50 where id = 1
update user set credits += 50 where id = 2
REST CALL (Site 2) Success
Site 2 response - OK, commit transaction
Commit

REST は別のサイトへの呼び出しであるため、トランザクションが完了するまでに時間がかかる場合があります。その間、トランザクションに対してテーブル全体がロックされていますか、それともユーザー 1 とユーザー 2 の行がロックされていますか? これは私のロジックを実装する適切な方法ですか? 何か不足していますか?

前もって感謝します。

4

2 に答える 2

1

これは、ケーシーの答えに関するあなたの質問への回答です。

はい、あなたがこのようにそれをする限り:

  • サイト2:

    1. 顧客がログインします。
    2. このユーザー(ユーザー1)のクレジット合計とトランザクション履歴(GETリクエスト)をサイト1に問い合わせます。
    3. (「トランザクションが成功しました」という応答を受信する待機中のトランザクションは、ダウンロード/ディスパッチできるようになります)
    4. クレジット合計を使用して、余裕のあるものの「購入」ボタンを有効にします。
    5. 顧客が[購入]ボタンをクリックする
    6. サイト2に固有のトランザクションIDを生成し、誰が何を購入したか、状態=保留中の詳細とともにデータベースに保存します。ユーザートランザクションが受信されたことを通知し、成功したかどうかをすぐに通知する必要があります(HTTP 202応答)
    7. サイト1へのPOST購入要求。これには、認証(偽造された要求によって、人々が使いたくないお金を使わせないようにする)とトランザクションIDが含まれます。
  • サイト1

    1. 認証を検証する
    2. サイト2のtransactionIDがサイト2によって以前に使用されていないことを確認します。使用されている場合は、エラーを返します。使用されていない場合は、次のようにします。
    3. トランザクションを開始します
    4. ユーザー設定クレジットの更新-=50ここで、id = 1
    5. ユーザー設定クレジットを更新+=50ここで、id = 2
    6. トランザクションに挿入remoteSiteID='Site2'、remoteTransactionID = tID、user = 1
      site2がsite1のクレジットを使用する唯一のサイトである場合、remoteSiteIDフィールドは必要ありません。
    7. 専念
    8. REST CALL(サイト2)の成功
  • サイト2:

いずれか:1。REST
成功コールを受信し、購入をダウンロード/ディスパッチできるようにし、購入処理が完了したことを示すメッセージをユーザーに表示します。ローカルトランザクションレコードを更新します。state=succeeded。

または
2.サイト2がダウンしています。トランザクションの成功は、次回のバックグラウンドポーリングプロセスの実行時(応答を待機している購入要求のステータスをチェックする)または顧客が次回ログインしたときに記録されます(この場合、ポーリングも開始されます-最初のリストのステップ3)

トランザクションへの応答を受け取っていない場合は、トランザクションIDを使用してGETを実行します。応答がエラーの場合、サイト1は元のリクエストを受信して​​いません。サイト2は、トランザクション(POST)リクエストを自由に繰り返すことができます。応答が「トランザクションに失敗しました」の場合、ユーザーは十分なクレジットを持っていません。それに応じてサイト2のトランザクションレコードを更新してください。結果が「トランザクション成功」の場合は、それも記録します。

トランザクションがN回失敗した場合、またはユーザーがボタンをクリックしてから一定の期間(たとえば5分)が経過した場合、サイト2は購入の再試行を停止します。

于 2013-01-22T09:02:05.823 に答える
1

範囲ではなく主キーを使用しているため、行レベルのロックにする必要があります。共有ロックと排他ロックの概念もあります。共有ロックは、更新/削除シナリオで排他ロックが使用されている間、他のプロセスがデータを読み取ることを許可し、他のすべてのプロセスがデータを読み取ることをブロックします。

一般的なロジックについて..クレジットを保存する場所が1 つだけで、クレジットを読み取る場所が 1しかない場合、リアルタイムで同期することはどれほど重要ですか? 3 秒後、5 秒後、または 10 秒後で十分ですか? サイト 1 が完全にダウンしている場合でも、サイト 2 を引き続き機能させますか?

個人的に、私は物事を少し再構築します:

  • ユーザーがサイト 1 でアカウントを作成します。
  • サイト 2 で初めてトランザクションが実行されると、アカウントが S1 に存在することを確認し、クレジット数を取得して保持します。
  • サイト 2 でトランザクションが行われるたびに、最初にローカル クレジット カウント (キャッシュ) を確認し、十分なクレジットがある場合は202 Accepted応答コードを返します。基本的には、「これは受け入れましたが、まだ完了していません」という意味です。
  • この時点で、ユーザーが続行することをすぐに許可できます。
  • しかし、ローカルの信用調査を行うと同時に、実際のトランザクションで S1 に別のリクエストを行いました。
  • うまくいけば、そのサービスが成功/失敗のメッセージ、更新された決定的な/公式のクレジット数を提供できることを願っています.
  • それを使用して、ローカル トランザクション ステータスを 204 NO Content (成功) に更新し、次回のためにキャッシュを更新します。

S1 は常に最終的な現在のクレジット カウントを返すため、S2 のクレジット カウントを 100% 正確な方法で維持することを心配する必要はありません。S1 からのクレジット カウントを待つだけで済みます。

本当に神経質な場合は、N 時間ごとに実行されるジョブを実行して、S1 をポーリングし、その N 時間の間に更新されたすべてのアカウントの更新を要求することができます。

于 2013-01-19T23:21:02.587 に答える