ガールフレンドへの送金が分散トランザクションについて考えるきっかけとなった

ガールフレンドへの送金が分散トランザクションについて考えるきっかけとなった

[[268931]]

2日前に給料をもらったのですが、私の最初の反応は、遠くに住んでいる彼女にちょっとしたサプライズをあげることでした!そこで、彼女に送金するために平安銀行アプリを開きました!相手の招商銀行のカード番号と口座名を記入し、ワンクリックで送金できました!終わり!クリックした瞬間、アプリから口座変更のリマインダーが届き、図 1 に示すプロンプト インターフェイスが表示されました。「処理中です。他の銀行から結果が返されるのを待っています...」 うーん!やはり銀行間送金なので数秒待つのは当たり前ですね!彼女が振込を受け取り、驚き感動する姿が目に浮かびました!


しかし、すべてが順調だったわけではありません。しばらくすると、図 2 に示すように、受取人の口座名が一致しないため送金が失敗したというメッセージがアプリに表示されました。


カードからお金が引き落とされたばかりですが、送金が失敗したというメッセージが表示されます。銀行は私のお金を飲み込んでしまうのでしょうか?送金できなかったお金は返金してもらえますか?緊張して不安で落ち着かない気分になっていたところ、先ほど送金に失敗したお金が返金されたというメッセージがアプリから届きました。心配しすぎていたようです...これは、私たちの平安銀行アプリが依然として比較的安全で信頼できるものであることを証明しています。

私のカードからはすぐにお金が引き落とされるのに、相手側がお金を受け取るまでに数秒もかかるのはなぜですか?送金が失敗した後、差し引かれた金額は時間内にカードに返金されますか?お金が返ってこなかったらどうなるのでしょうか?あるいは、私が一度送金したのに、相手が2回送金申請を受け取った場合はどうなりますか?これらの疑問から、「取引」という言葉が私の頭の中に浮かびました。

私たちがまだ「幼児期」だった頃、先生はお金の送金の例を通して取引を説明することが多かったのですが、ここでのシーンとの違いは、先生がローカル取引について話していたのに対し、ここでは分散取引に直面しているということです。まずはローカルトランザクションを簡単に確認してみましょう。

地方問題

ローカル トランザクションについては、データベース エンジン レベルでサポートされているため、誰もがよく知っていることでしょう。そのため、データベース トランザクションとも呼ばれます。データベース トランザクションには、原子性 (A)、一貫性 (C)、独立性 (I)、永続性 (D) という 4 つの主要な特性があります。これら 4 つの特性のうち、一貫性が最も基本的な特性であり、他の 3 つの特性は一貫性を確保するために存在すると思います。

私たちが学生だったときに先生が教えてくれた典型的な例に戻りましょう。アカウント A が 100 元をアカウント B に送金します (A と B は同じデータベース内にあります)。 A の口座からお金が引き落とされたのに、B の口座に入金されなかった場合、データの不整合が発生します。データの一貫性を確保するために、データベース トランザクション メカニズムは、口座 A からお金を差し引く操作と口座 B でお金を受け取る操作の 2 つの操作が同時に成功することを保証します。 1 つの操作が失敗した場合、複数の操作が同時にロールバックされます。これはトランザクションのアトミック性です。トランザクション操作のアトミック性を保証するには、ログベースの REDO/UNDO メカニズムを実装する必要があります。ただし、システムはマルチスレッド環境で実行されるため、アトミック性だけでは不十分です。複数のトランザクションが並行して実行される場合、各トランザクションのアトミック性が保証されていても、データの不整合は発生します。たとえば、口座 A の残高は元々 200 元です。口座 A が口座 B に 100 元を振り替えます。まず口座 A の残高が読み取られ、次にこの値から 100 元が差し引かれます。ただし、これら 2 つの操作の間に、口座 A は口座 C に 100 元を振り替えます。そのため、最終結果は A から 200 元を引いた金額になります。しかし実際には、口座 A から口座 B への振替が最終的に完了した後、口座 A から差し引かれたのは 100 元だけでした。口座 A から口座 C への振替で差し引かれた 100 元が上書きされたためです。したがって、同時実行状況での一貫性を確保するために、分離が導入されます。つまり、複数のトランザクションが同時に実行された後の状態は、シリアルに実行された後の状態と同等になります。分離には複数の分離レベルがあります。分離を実現するために (最終的には一貫性を確保するために)、データベースでは悲観的ロック、楽観的ロックなどが導入されています。この記事のテーマは分散トランザクションなので、ローカル トランザクションについては簡単に説明します。覚えておくべきことの 1 つは、トランザクションはデータの一貫性を確保するためのものであるということです。

分散理論

卒業したばかりの年、意気込みたっぷりでインターネット企業に入社し、リーダーから最初に与えられた仕事がリスト内のデータを変更する機能を追加することだったことを今でも覚えています。これは私を困惑させるでしょうか?数分で解決できますよ!リストに「編集」ボタンを追加するだけではないでしょうか?ボタンをクリックしてポップアップ ボックスを表示し、変更して保存します。しかし、すべてが想像していたほどスムーズにはいきませんでした。 [保存] をクリックしてリストを更新した後も、変更が成功しなかったかのように、ページのデータには変更前のコンテンツが表示されたままでした。しばらくしてから、リストを再度更新すると、データが正常に表示されます。何度もテストした結果、このようになりました!大きなシーンを見たことがなかったので、パニックになり始めました。何か間違ったことを書きましたか?結局、グループ内の経験豊富な先輩たちに助けを求めなければなりませんでした。彼は深呼吸して私に言いました。「何しろ、あなたは卒業したばかりの若者ですからね! 理由をお話ししましょう! 私たちのデータベースは読み取りと書き込みが分離されており、一部の読み取りライブラリと書き込みライブラリは異なるネットワーク パーティションにあります。 あなたのデータは書き込みライブラリに更新され、データを読み取るときは読み取りライブラリから読み取られます。 書き込みライブラリに更新されたデータを読み取りライブラリに同期させるには一定の遅延があり、読み取りライブラリと書き込みライブラリの間には短期的なデータの不整合が生じます」! 「これは悪い経験ではないでしょうか? 書き込まれたデータをすぐに読み取ることができないのはなぜでしょうか? どうすればこの機能を実装できるでしょうか?」私のたくさんの質問に直面して、同僚はイライラしながらこう言いました。「CAP 理論について聞いたことがありますか? まず自分で学ぶべきです!」この聞き慣れない言葉の秘密を知るために、いろいろな資料を調べ始めたのは私でした!

CAP理論はカリフォルニア大学のエリック・ブリューワー教授によって提唱されました。この理論によれば、分散システムは一貫性、可用性、分断耐性という 3 つの基本要件を同時に満たすことはできず、最大でもそのうちの 2 つしか満たすことができません。

一貫性: ここでの一貫性は、データの強い一貫性、つまり線形一貫性を指します。分散環境内の複数のコピー間でデータの一貫性を維持できるかどうかを指します。つまり、あるデータに対して書き込み操作を実行した直後に読み取り操作を実行すると、書き込まれたばかりの値を読み取る必要があります。 (書き込み操作が完了した後に開始される読み取り操作は、その値、またはそれ以降の書き込み操作の結果を返す必要があります)

可用性: 障害のないノードが受信したすべての要求は、限られた時間内に結果で応答できる必要があります。 (システム内の障害のないノードが受信したすべてのリクエストは、応答を返す必要があります)

パーティション耐性: クラスター内のマシンが 2 つの部分に分割され、2 つの部分が相互に通信できない場合、システムは正常に動作し続けることができますか? (ネットワークは、あるノードから別のノードに送信されたメッセージを任意の数失うことが許されます)

分散システムでは、パーティション耐性が基本的な要件です。つまり、一貫性と可用性の間でトレードオフを行うことしかできません。一貫性と可用性を同時に実現できないのはなぜでしょうか?リストを変更する前の例に戻りましょう。データは異なるネットワーク パーティションに分散されるため、必然的にデータ同期に問題が発生します。同期にはネットワーク遅延、例外などの問題が発生するため、データの不整合が発生します。データの一貫性を確保したい場合は、書き込みデータベースを操作するときに他の読み取り操作をロックする必要があります。書き込みが成功し、データの同期が完了した後にのみ、読み取りと書き込みを再度解放することができ、ロック期間中はシステムは使用できなくなります。 CAP理論の詳細についてはこちらの記事が分かりやすく解説されているので参考にしてください!

分散トランザクション

分散トランザクションは、分散シナリオで満たす必要があるトランザクションです。前回の記事では、メッセージミドルウェアについて説明しました。この記事では、分散トランザクションについて説明します。これら 2 つを組み合わせることで、メッセージ ミドルウェアに基づく分散トランザクション ソリューションが実現します。ローカルトランザクションであっても、分散トランザクションであっても、データの一貫性の問題を解決します。一貫性という言葉についてはこれまで何度も言及してきました。ローカル トランザクションとは異なり、分散トランザクションでは、分散環境内の異なるデータベース テーブル内のデータの一貫性を確保する必要があります。分散トランザクションには、XA プロトコル、TCC 3 フェーズ コミット、メッセージ キュー ベースなど、さまざまなソリューションがあります。この記事では、メッセージ キュー ベースのソリューションについてのみ説明します。

ローカル トランザクションでは一貫性について説明し、分散トランザクションでは必然的に一貫性の問題に直面します。冒頭の銀行間送金の例に戻ると、銀行 A のユーザーが銀行 B のユーザーに送金する場合、通常のプロセスは次のようになります。

1. 銀行Aは振込口座を確認し、金額を差し引きます。

2. 銀行 A は銀行 B の転送インターフェースを同期的に呼び出します。

3. 銀行Bは振込先の口座を確認し、金額を増額します。

4. 銀行Bは処理結果を銀行Aに返します。

一貫性の要件が高くない通常の状況では、このような設計でニーズを満たすことができます。しかし、もし銀行のようなシステムがこのように導入されていたら、とっくの昔に破綻していただろう。まず、この設計の主な問題を見てみましょう。

1. リモート インターフェイスを同期的に呼び出します。インターフェースに時間がかかる場合、メインスレッドは長時間ブロックされます。

2. 交通を適切に制御できない。銀行 A のシステムのトラフィックのピークにより、銀行 B のシステムが圧倒される可能性があります (もちろん、銀行 B には独自のトラフィック制限メカニズムが必ずあります)。

3. 「ステップ 1」の実行直後に何らかの理由でシステムがクラッシュした場合、銀行 A の口座から資金が引き落とされますが、銀行 B はインターフェース呼び出しを受信できず、2 つのシステムのデータに不整合が生じます。

4. 「ステップ 3」を実行した後、何らかの理由で銀行 B がクラッシュし、要求に正しく応答できない場合 (実際には転送操作が実行され、銀行 B のシステムに保存されている)、銀行 A はインターフェイス応答を待機しているときに異常になり、転送が失敗したと誤って判断して「ステップ 1」操作をロールバックし、2 つのシステムのデータに不整合が発生します。

問題1と2は簡単に解決できます。メッセージ キューに詳しい人であれば、非同期処理やピークカット処理のためにメッセージ ミドルウェアを導入することをすぐに思いつくはずです。そこで私たちはソリューションを再設計しました。そのプロセスは次のようになります。

1. 銀行Aは口座を確認し、金額を差し引きます。

2. 銀行 B のリクエストが非同期的にキューに書き込まれ、メイン スレッドが返されます。

3. バックグラウンド プログラムを起動して、処理するデータをキューから取得します。

4. バックグラウンド プログラムは、銀行 B のインターフェイスをリモートで呼び出します。

5. 銀行Bは振込先の口座を確認し、金額を増額します。

6. 処理が完了すると、銀行Bは銀行Aのインターフェースをコールバックして処理結果を通知します。


上の図から、メッセージ キューの導入後、システムの複雑さが瞬時に増加したことがわかります。これは最初のソリューションのいくつかの欠点を補いますが、メッセージ キュー システム自体の可用性、メッセージ キューの遅延など、さらに多くの問題ももたらします。さらに、このような設計では、私たちが直面している中核的な問題、つまりデータの一貫性は依然として解決されません。

1. 「ステップ 1」の実行直後に何らかの理由でシステムがクラッシュした場合、銀行 A の口座から金額が引き落とされますが、メッセージ キューへの書き込みに失敗し、銀行 B のインターフェイス呼び出しが行われず、データの不整合が発生します。

2. 「ステップ 5」の実行時に銀行 B が検証失敗のために資金の送金に失敗し、ロールバックを通知するために銀行 A のインターフェースをコールバックしたときにネットワークが異常またはダウンしている場合、銀行 A の送金はロールバックできず、データの不整合が発生します。

上記の問題に直面したため、システムを再度アップグレードする必要がありました。 「銀行口座 A から金額が引き落とされたが、メッセージ キューへの書き込みに失敗した」という問題を解決するには、転送ログ テーブル、または転送フロー テーブルを使用する必要があります。このテーブルのシンプルなデザインは次のとおりです。

フィールド名フィールドの説明tIdトランザクション フローidaccountNo振替口座番号targetBankNo振替先銀行コードtargetAccountNo振替先銀行カード番号amountトランザクション金額statusトランザクション ステータス (保留中、成功、失敗)lastUpdateTime***更新時間

このトランザクションテーブルをどのように使用しますか? 「ステップ 1」でお金を差し引くときに、トランザクション テーブルに「保留中」のステータスで操作フローも書き込みます。これらの 2 つの操作はアトミックである必要があります。つまり、ローカル トランザクションを使用して、これらの 2 つの操作が同時に成功するか、同時に失敗することを保証する必要があります。これにより、転送控除が成功する限り、「保留中」ステータスの転送フローが記録されます。このステップが失敗すると、転送は当然失敗し、後続の操作は行われません。この操作の後にシステムがクラッシュし、メッセージがメッセージ キューに正常に書き込まれなかったとしても (つまり、「ステップ 2」)、トランザクション データは保持されているため、問題はありません。現時点では、補正のためにバックグラウンド スレッドを追加し、転送トランザクション テーブルからステータスが「保留中」で最終更新時刻が一定のしきい値を超えているデータを定期的に読み取り、補正のためにメッセージ キューに戻すだけで済みます。このようにして、メッセージが失われた場合でも補償メカニズムが存在することが保証されます。振替リクエストを処理した後、銀行 B は銀行 A のインターフェースをコールバックして振替のステータスを通知し、銀行 A の取引テーブルのステータス フィールドを更新します。これにより、以前のソリューションの 2 つの欠点が完全に解決されます。システム設計図は次のとおりです。


これまでのところ、メッセージ損失の問題はうまく解決されており、銀行 A の送金操作が成功すれば、送金リクエストは確実に銀行 B に送信されるようになっています。しかし、この解決策は別の問題を引き起こします。バックグラウンド スレッドをポーリングしてメッセージをメッセージ キューに入れて処理すると、同じ転送要求がメッセージ キューに複数回入れられ、複数回消費される可能性があります。このようにすると、銀行 B は同じ送金を複数回処理することになり、データの一貫性が失われます。では、銀行 B の送金インターフェースのべき等性をどのように確保するのでしょうか?

同様に、B 銀行システムに転送ログ テーブルまたは転送フロー テーブルを追加できます。 B銀行は、振込依頼を受けるたびに、口座操作時に振込ログテーブルに振込ログレコードを挿入します。これら 2 つの操作もアトミックである必要があります。転送要求を受信した後、まずログ テーブルで一意の転送フロー ID を検索して、転送が処理されたかどうかを判断します。処理されていない場合は処理され、そうでない場合は直接コールバックされて返されます。最終的なアーキテクチャ図は次のようになります。


したがって、ここでの核心は、銀行 A がローカル トランザクションを使用してログ記録とバックグラウンド スレッド ポーリングを実行し、メッセージが失われないようにすることです。銀行 B は、メッセージが繰り返し消費されないように、ローカル トランザクションを使用してログ記録を確保します。銀行Bは銀行Aのインターフェースをコールバックする際に処理結果を通知します。送金が失敗した場合、銀行Aは処理結果に基づいてロールバックします。

もちろん、分散トランザクションに対する最善の解決策は、分散トランザクションを可能な限り回避することです。

<<:  クラウドコンピューティング技術が大企業に与える影響

>>:  Docker コンテナをバックグラウンドで実行する方法 (デタッチ モード)

推薦する

HPA PaaS コミュニティが設立されました!

1. HPA PaaSとは注: HP APaaS には、ゼロ コード、ロー コード プラットフォーム...

5G が新しいインフラストラクチャと出会うと、エッジ コンピューティングはどのように発展するのでしょうか?

エッジコンピューティングは、5G 開発において最も注目されているテクノロジーの 1 つになりました。...

digitalocean-9月に最新バージョンを10ドルで送る

digitalocean は本日、最新のプロモーション コード HAPPYMONDAY10 をリリー...

Linode ブラックフライデーイベント、25 ドルをプレゼント!

Linode も毎年恒例のブラックフライデーに参加しています。Linode がユーザーに特典を提供す...

垂直産業ウェブサイト構築のリスクに関する議論

垂直産業ウェブサイトは、かつては比較的競争力が低いため、多くの個人ウェブマスターが好むウェブサイトの...

Kafka の適用可能なシナリオをネットワーク全体で最も包括的に図解で解説します。

メッセージングシステムメッセージング システムは、データ プロデューサーの分離や未処理メッセージのキ...

edgenat: 韓国のCN2独立サーバー(ネイティブIP)、500元/月、2*e5-2670v3/32gDDR4/1TSSD/10M帯域幅

edgenat は現在、CN2 + BGP ネットワークに接続された韓国のサーバー (ハイエンドの独...

対外貿易ウェブサイトのプロモーションで注意が必要な詳細の最適化

2018年最もホットなプロジェクト:テレマーケティングロボットがあなたの参加を待っています対外貿易ウ...

信頼性の高い設計により VMware 環境の障害を防止

ESXi ホストでは高度な機能と管理のために vCenter が必要ですが、vCenter がなくて...

新しいウェブサイト xen/openvz 50% オフ プロモーション

newwebsiteは13年の歴史を持ち、幅広い事業を展開しているIDCです。今回販売されるVPSに...

どの EDM 電子メール マーケティングが優れていますか?

ショートビデオ、セルフメディア、インフルエンサーのためのワンストップサービス電子メール マーケティン...

virpus: シアトルの格安 Windows VPS、超高設定、35% 割引、独立したコンピュータ ルーム

一般的に、Windows VPS は Linux シリーズよりも高価であり、米国西海岸の Windo...

中小規模のウェブサイトは、質の高い人材不足というボトルネックをどう打破できるでしょうか?

昨今、質の高い人脈がウェブサイトの発展にますます大きな影響を与えていることは否定できません。無名の新...

kdatacenter: 韓国の VPS、高速直接接続、Web サイト構築に最適 + 「言葉にできない」など。

kdatacenterは主に韓国のSKデータセンターで韓国のVPSとサーバーを運営しており、1Gbp...

あらゆるインターネット企業が利用する Kafka がなぜ高速なのか?

データが王様である時代において、膨大なデータの保存、伝送、分析は特に重要になっています。データの保存...