Pythonを使用して分散トランザクションTCCを簡単に完了する、乳母レベルのチュートリアル

Pythonを使用して分散トランザクションTCCを簡単に完了する、乳母レベルのチュートリアル

分散トランザクションとは何ですか?銀行間送金業務は、典型的な分散型トランザクションのシナリオです。 A が銀行間で B に送金する必要がある場合、2 つの銀行のデータが関係します。転送の ACID は、データベースのローカル トランザクションでは保証できず、分散トランザクションを通じてのみ解決できます。

分散トランザクションとは、トランザクション イニシエーター、リソースとリソース マネージャー、およびトランザクション コーディネーターが分散システムの異なるノードに配置されていることを意味します。上記の転送業務では、ユーザーA-100操作とユーザーB+100操作は同一ノード上に存在しません。本質的に、分散トランザクションは、分散シナリオでデータ操作が正しく実行されるように設計されています。

TCC 分散トランザクションとは何ですか? TCC は Try、Confirm、Cancel の略です。これは、2007 年に発表された「分散トランザクションを超えた生活: 背教者の意見」と題された論文の中で、パット ヘランドによって初めて提案されました。

TCC構成

TCCは3つの段階に分かれています

  • 試行フェーズ: 実行を試行し、すべてのビジネス チェックを完了し (一貫性)、必要なビジネス リソースを予約します (準分離)
  • 確認フェーズ: すべてのブランチの試行が成功した場合は、確認フェーズに進みます。 Confirmは、ビジネスチェックなしで実際にビジネスを実行し、Tryステージで予約されたビジネスリソースのみを使用します。
  • キャンセル ステージ: すべてのブランチの Try 操作のいずれかが失敗した場合、プロセスはキャンセル ステージに進みます。キャンセルは、試行フェーズで予約されたビジネス リソースを解放します。

TCC 分散トランザクションには、従来の XA 分散トランザクションと同じように、次の 3 つの役割があります。

  • AP/アプリケーションは、グローバルトランザクションを開始し、どのトランザクションブランチがグローバルトランザクションに含まれるかを定義します。
  • 支店業務のさまざまなリソースの管理を担当するRM/リソースマネージャー
  • TM/トランザクション マネージャーは、確認とキャンセルの実行、ネットワーク例外の処理など、グローバル トランザクションの正しい実行の調整を担当します。

銀行間送金に似た業務を行う場合、送金 (TransOut) と入金 (TransIn) は異なるマイクロサービスに存在します。正常に完了した TCC トランザクションの一般的なシーケンス図は次のとおりです。

TCC実践

上記の銀行間振替操作の場合、最も簡単な方法は、Try 段階で残高を調整し、Cancel 段階で逆方向に残高を調整し、Confirm 段階では何​​も操作を行わないことです。これを実行すると、A がお金をうまく引き落とすと、その金額が B に送金されず、最終的にロールバックされて、A の残高が初期値に調整されるという問題があります。この過程で、A が自分の残高が差し引かれたことに気付いたが、受取人 B が長期間その残高を受け取っていない場合、A に問題が生じます。

より良い方法は、Try 段階で A の送金金額を凍結し、Confirm 段階で実際の控除を行い、Cancel 段階で資金の凍結を解除することです。こうすることで、ユーザーが見るデータはどの段階でも明確になります。

次に、TCC取引の具体的な開発を行います。

現在 TCC で利用できるオープン ソース フレームワークは主に Java 言語であり、seata が最も代表的です。この例では Python 言語を使用し、使用される分散トランザクション フレームワークは https://github.com/yedf/dtm です。これは分散トランザクションを非常にエレガントにサポートします。 TCCの構成について詳しく説明します。

まず、ユーザー残高テーブルと凍結資金テーブルの 2 つのテーブルを作成します。テーブル作成ステートメントは次のとおりです。

  1. テーブル dtm_busi.`user_account` を作成します (
  2. `id` int ( 11 ) AUTO_INCREMENT 主キー、
  3. `user_id` int ( 11 ) NULLではない一意、
  4. `balance` 小数点( 10 , 2 ) NOT NULL デフォルト'0.00' ,
  5. `create_time` datetime DEFAULT now(),
  6. `update_time` 日時 DEFAULT now()
  7. );
  8.  
  9. テーブル dtm_busi.`user_account_trading` を作成します (
  10. `id` int ( 11 ) AUTO_INCREMENT 主キー、
  11. `user_id` int ( 11 ) NULLではない一意、
  12. `trading_balance` 小数点( 10 , 2 ) NOT NULL デフォルト'0.00' ,
  13. `create_time` datetime DEFAULT now(),
  14. `update_time` 日時 DEFAULT now()
  15. );

取引テーブルでは、trading_balance は取引される金額を記録します。

まず、資金を凍結/解凍するためのコアコードを記述します。制約balance+trading_balance >= 0 がチェックされます。制約が保持されない場合、実行は失敗します。

  1. def tcc_adjust_trading(カーソル、uid、金額):
  2. 影響を受ける = utils.sqlexec(cursor, "dtm_busi.user_account_trading を更新し、trading_balance =trading_balance + %d (user_id = %d の場合) および trading_balance + %d + (dtm_busi.user_account からバランスを選択 (id = %d の場合) >= 0" % (amount, uid, amount, uid))
  3. 影響を受ける場合== 0 :
  4. 例外が発生します( "更新エラー、残高が足りない可能性があります" )

次にバランスを調整します

  1. def tcc_adjust_balance(カーソル、uid、金額):
  2. utils.sqlexec(cursor, "dtm_busi.user_account_trading を更新し、trading_balance = trading_balance+ %d を設定します。user_id=%d" %( -amount, uid))
  3. utils.sqlexec(カーソル、 「dtm_busi.user_account を更新し、残高を balance+%d に設定し、user_id を %d にします」 %(amount, uid))

次に、具体的なTry/Confirm/Cancel処理関数を書いてみましょう。

  1. @app .post( "/api/TransOutTry" )
  2. trans_out_try() を定義します:
  3. #トランザクションと例外処理
  4. tcc_adjust_trading(c, out_uid, - 30 )
  5. 戻り: "dtm_result" : "SUCCESS" }
  6.  
  7. @app .post( "/api/TransOutConfirm" )
  8. def trans_out_confirm(): 定義:
  9. #トランザクションと例外処理
  10. tcc_adjust_balance(c, out_uid, - 30 )
  11. 戻り: "dtm_result" : "SUCCESS" }
  12.  
  13. @app .post( "/api/TransOutCancel" )
  14. trans_out_cancel() を定義します:
  15. #トランザクションと例外処理
  16. tcc_adjust_trading(c, out_uid, 30 )の書式
  17. 戻り: "dtm_result" : "SUCCESS" }
  18.  
  19. @app .post( "/api/TransInTry" )
  20. trans_in_try() を定義します:
  21. #トランザクションと例外処理
  22. tcc_adjust_trading(c, in_uid, 30 )の書式
  23. 戻り: "dtm_result" : "SUCCESS" }
  24.  
  25. @app .post( "/api/TransInConfirm" )
  26. trans_in_confirm() を定義します:
  27. #トランザクションと例外処理
  28. tcc_adjust_balance(c, in_uid, 30 )は、
  29. 戻り: "dtm_result" : "SUCCESS" }
  30.  
  31. @app .post( "/api/TransInCancel" )
  32. trans_in_cancel() を定義します:
  33. #トランザクションと例外処理
  34. tcc_adjust_trading(c, in_uid, - 30 )
  35. 戻り: "dtm_result" : "SUCCESS" }

この時点で、各サブトランザクションの処理機能は正常であり、TCCトランザクションが開かれて分岐呼び出しが行われます。

  1. @app .get( "/api/fireTcc" )
  2. fire_tcc() を定義します:
  3. # tccトランザクションを開始する
  4. gid = tcc.tcc_global_transaction(dtm、utils.gen_gid(dtm)、tcc_trans)
  5. { "gid" : gid}を返します
  6.  
  7. # tcc トランザクションの特定の処理
  8. tcc_trans(t)を定義します。
  9. req = { "amount" : 30 } # ビジネスリクエストの負荷
  10. # 転送サービスの呼び出し試行|確認|キャンセル
  11. t.call_branch(req、svc + "/TransOutTry" 、svc + "/TransOutConfirm" 、svc + "/TransOutCancel" )
  12. # 転送サービスのTry|Confirm|Cancel関数を呼び出す
  13. t.call_branch(req、svc + "/TransInTry" 、svc + "/TransInConfirm" 、svc + "/TransInCancel" )

この時点で、完全な TCC 分散トランザクションが書き込まれました。

完全な成功例を実行する場合は、dtmcli-py-sample プロジェクトの指示に従ってください。

TCC ロールバック

銀行がユーザー2に金額を振り込む準備をしているときに、ユーザー2の口座に異常を発見し、失敗を返した場合はどうなりますか?この状況をシミュレートするためにコードを変更します。

  1. @app .post( "/api/TransInTry" )
  2. trans_in_try() を定義します:
  3. #トランザクションと例外処理
  4. tcc_adjust_trading(c, in_uid, 30 )の書式
  5. 戻り値: "dtm_result" : "FAILURE" }

これはトランザクション失敗の相互作用のタイミング図です

これと成功した TCC の違いは、サブトランザクションが失敗を返すと、その後グローバル トランザクションがロールバックされ、各サブトランザクションのキャンセル操作が呼び出されて、グローバル トランザクションが完全にロールバックされるようになることです。

TCCネットワーク異常

TCC のグローバル トランザクション プロセス全体にわたって、空のロールバック、べき等性、中断など、さまざまなネットワーク例外が発生する可能性があります。 TCC の例外は SAGA や信頼性の高いメッセージングなどのトランザクション モードに似ているため、この記事では、分散トランザクションの最も古典的な 7 つのソリューションの例外処理セクションで、例外に対するすべてのソリューションについて説明します。

まとめ

この記事では、TCC の理論的知識を紹介し、通常の正常な完了と正常なロールバックを含む、TCC トランザクションの記述プロセスの完全な例を示しました。この記事を通じて読者の皆様にはTCCについて深く理解して頂けたのではないかと思います。

<<:  ZK (ZooKeeper) 分散ロック実装

>>:  クラウドへの移行を成功させる方法

推薦する

クラウドネイティブデータレイクの探求と実践: Mobvista EnginePlusチームがAlibaba Cloud Summitに参加したとき

人工知能からビッグデータ、クラウドコンピューティングまで、新しいテクノロジーの革命はあらゆるところで...

病院のウェブサイト最適化のための4つのソリューション

1. 分析1. ウェブサイトとターゲット顧客を分析します。まず顧客の属性を調べます。ターゲット顧客が...

率先して行動し、冷静さを保つ: Kubernetes クラスターの積極的な拡張

クラスター リソースが不足している場合、Cluster Autoscaler は新しいノードをプロビ...

veesp: 月額 1 ドル、ロシアの VPS、KVM 仮想化、512 RAM/10G ハードディスク、PayPal 対応

2004年に設立されたFishnet Сommunicationsは、RNET、vStoike、Ve...

リベート ウェブサイトには良いものも悪いものもあり、その多くは中身のないものです。

ショッピングリベートが届くまで10日以上かかるオンラインショッピングは安く、リベートを利用すればさら...

仮想デスクトップ GPU カード: AMD と Nvidia の比較

クラウドベンダーはさまざまなベンダーの GPU ベースの機能に投資しているため、企業は AMD と ...

検索エンジンマーケティング (SEM) の 10 大原則

以下は、Web サイトの計画に携わるすべての友人に捧げる、概念的な検索エンジン マーケティング (S...

マイクロソフトは、あらゆるデバイスでWindowsを実行できるクラウドサービス「Windows 365」を発表

本日、マイクロソフトは Inspire 2021 カンファレンスで Windows 365 Clou...

racknerdはどうですか? racknerd の Seattle AMD Ryzen9 3900X+DDR4+NVMe シリーズ VPS の簡単なレビュー

racknerdはどうですか? racknerdは良いですか? Hostcat は、公式のものを除い...

Hostus 20% 割引コード - $3.48/Windows/512M メモリ/15G ハードディスク/750G トラフィック

Hostus の最新の公式イベント: すべての KVM 仮想 VPS が 20% オフ。Hostus...

YYを「密かに」店頭から撤去し、匿名ソーシャルアプリ「プライベートサークル」を立ち上げた

[要約] 秘密権使用者の特徴は、若く、教養が高く、活力があり、新しいものを好むことです。彼らは家にこ...

Baidu - ウェブマスター情報およびサービスセンターへ

このタイトルを思いついたとき、私はまだウェブサイトの宣伝に取り組んでいました。しかし、時代は変わり、...

Dogyun:「香港-KC」データセンターの「International Line」VPSの簡単なレビュー

Dogyun は、香港-KC データセンターだけでも複数の回線を保有しています。本日は、「香港-KC...

適切なウェブサイトを構築するための Baidu Google 最適化ガイドの解釈

私は数年にわたり SEO に携わってきました。最適化についてはあまり詳しくありませんが、業務をこなし...