この記事はWeChatの公開アカウント「Programmer's Insider Things」から転載したもので、著者はProgrammer's Insider Thingsです。この記事を転載する場合は、Programmer Insider 公式アカウントまでご連絡ください。 長い間投稿していませんでした。最近とても忙しいです。父親になって43日目です。肉体的にも精神的にも疲れています。年末だったため、会社はKPIを達成するために技術部門に10時までの残業を強制していました。夜になると、子供は2、3時間おきに起きてしまうので、基本的にぐっすり眠る機会はありませんでした。彼は毎日ぼんやりしており、時々奇妙な発疹も出るので、私たちはいつも心配していました。 記事を書くための限られた時間は無限に分割されます。あぁ〜働くって本当に大変ですね。 その小さな表情は何を意味しているのでしょうか? 最初は何を書いていいか分かりませんでしたが、たまたま分散トランザクションに Alibaba の Seata ミドルウェアを使用するという新しいプロジェクトが手元にあったので、実践を共有します。 Seata を紹介する前に、分散トランザクションの基本的な概念を簡単に確認しましょう。 分散トランザクションの生成 まず、Baidu の分散トランザクションの定義を見てみましょう。分散トランザクションとは、参加者、トランザクションをサポートするサーバー、リソース サーバー、およびトランザクション マネージャーが異なる分散システムの異なるノードに配置されているトランザクションを指します。 え〜とちょっと抽象的ですね。理解するために簡単な絵を描いてみましょう。注文を受けて在庫を減らし、残高を差し引く例を見てみましょう。 システムが小さい場合、モノリシック アーキテクチャは既存のビジネス ニーズを完全に満たすことができます。すべてのビジネスがデータベースを共有し、注文プロセス全体では、1 つの方法と同じトランザクションでデータベースを操作するだけで済む場合があります。この時点で、すべての操作をコミットするか、すべての操作をロールバックするのは簡単です。 サブライブラリとサブテーブル、SOA しかし、ビジネス量が拡大し続けると、モノリシックアーキテクチャは徐々に膨大なトラフィックに耐えられなくなります。このとき、データベースとテーブルを分割し、アプリケーションを SOA サービスに分割する必要があります。これにより、注文センター、ユーザー センター、在庫センターなどが生まれました。これによって生じた問題は、ビジネスが互いに分離され、各ビジネスが独自のデータベースを維持し、データ交換が RPC 呼び出しを通じてのみ実行できることでした。 ユーザーが再度注文を行う場合、注文ライブラリ、在庫ライブラリ、ユーザーライブラリ アカウントに対して同時に操作を実行する必要があります。ただし、現時点ではローカルデータの一貫性のみを保証でき、他のサービスを呼び出す操作が成功するかどうかは保証できません。したがって、注文プロセス全体のデータの一貫性を確保するには、分散トランザクションが必要になります。 シータの利点 分散トランザクションを実装するためのソリューションは数多くあり、XA プロトコルに基づく 2PC や 3PC、ビジネス レイヤーに基づく TCC、メッセージ キュー + メッセージ テーブルを適用して実装される最終的な一貫性ソリューション、そして今日説明する Seata ミドルウェアなどがあります。それぞれのソリューションの長所と短所を見てみましょう。 2PC XA プロトコルに基づいて実装された分散トランザクションは、トランザクション マネージャーとローカル リソース マネージャーの 2 つの部分に分かれています。ローカル リソース マネージャーは、Oracle、MYSQL などのデータベースによって実装されることが多く、これらのデータベースは XA インターフェイスを実装しており、トランザクション マネージャーはグローバル スケジューラーとして機能します。 2 フェーズ コミット (2PC) はビジネスにほとんど影響を与えません。その最大の利点は、ユーザーにとって透明性があることです。ユーザーは、ローカル トランザクションと同様に XA プロトコルに基づく分散トランザクションを使用できるため、トランザクションの ACID 特性を厳密に保証できます。 しかし、2PC の欠点も明らかです。これは、強力な一貫性を備えた同期ブロッキング プロトコルです。トランザクションの実行中は、必要なすべてのリソースをロックする必要があります。これは一般に、固定トランザクションと呼ばれます。したがって、一定の実行時間を持つ短いトランザクションに適しており、全体的なパフォーマンスは比較的劣ります。 トランザクション コーディネーターがクラッシュしたり、ネットワーク ジッターが発生すると、参加者はリソースをロックした状態のままになったり、一部の参加者のみが正常に送信したりして、データの不整合が発生します。したがって、高い同時実行パフォーマンスが最も重要となるシナリオでは、XA プロトコルに基づく分散トランザクションは最適な選択ではありません。 3PC 3 フェーズ コミット (3PC) は、2 フェーズ コミット (2PC) の改良版です。これは、2 フェーズ コミット プロトコルのブロッキング問題を解決するために使用されます。コーディネータがクラッシュすると、参加者は最終的な選択を行うことができず、ブロックされたままになり、リソースがロックされます。 2PC では、コーディネータのみにタイムアウト メカニズムがありますが、3PC では、コーディネータと参加者の両方にタイムアウト メカニズムが導入されています。コーディネーターが失敗した場合、参加者は永久にブロックされることはありません。さらに、第 1 フェーズと第 2 フェーズの間に準備フェーズが挿入され (下の図に示すように、少し長く見えます)、最終的な送信フェーズの前に各参加ノードのステータスが一貫していることが保証されます。 3PC は、コーディネータの障害後に参加者がブロックされる問題を解決するためにタイムアウト メカニズムを使用しますが、余分なネットワーク通信が追加され、パフォーマンスが低下するため、推奨されません。 TCC いわゆる TCC プログラミング モードも、2 フェーズ コミットのバリエーションです。違いは、TCC がビジネス レイヤーでコードを記述して 2 フェーズ コミットを実装することです。 TCC はそれぞれ Try、Confirm、Cancel の略です。一つの業務運営は、これら3つの方法に対応している必要があります。 次の単一在庫控除を例に挙げます。試行段階では在庫を取得し、確認段階では実際に在庫を減らします。在庫の減額が失敗した場合、キャンセル ステージがロールバックされ、在庫が解放されます。 TCC では、各メソッドがトランザクションを直接コミットするため、リソース ブロッキングの問題はありません。例外が発生すると、Cancel を使用してロールバックし、補正します。これはしばしば補償取引と呼ばれます。 元々は 1 つの方法でしたが、現在は 3 つの方法のサポートが必要です。 TCC はビジネスに非常に侵襲的であり、このモデルはうまく再利用できないため、開発量の急増につながることがわかります。ネットワークの変動やその他の要因も考慮する必要があります。リクエストが確実に配信されるように再試行メカニズムが用意されているため、インターフェースのべき等性を考慮する必要があります。 メッセージトランザクション(結果整合性) メッセージ トランザクションは、実際にはメッセージ ミドルウェアに基づく 2 フェーズ コミットであり、ローカル トランザクションとメッセージ送信を同じトランザクションに配置して、ローカル操作とメッセージ送信が同時に成功することを保証します。発注時に在庫を差し引く原理図:
メッセージ ミドルウェアに基づく 2 フェーズ コミット ソリューションは、通常、同時実行性の高いシナリオで使用され、パフォーマンスが大幅に向上する代わりに、強力なデータ一貫性が犠牲になります。ただし、この方法を実装するにはコストと複雑さが比較的高く、実際のビジネス状況によって異なります。 シータ Seata は、2 フェーズ コミットから進化した分散トランザクション ソリューションでもあり、AT、TCC、SAGA、XA などのトランザクション モードを提供します。ここではATモードに焦点を当てます。 Seata は 2 段階のサブミッションなので、各段階で何が行われるか見てみましょう。以下では、注文から在庫と残高を差し引く例も取り上げます。 まず、Seata 分散トランザクションのいくつかの役割を紹介します。
Seata は分散トランザクションを実装し、重要な役割 UNDO_LOG (ロールバック ログ レコード テーブル) を設計します。このテーブルは、各アプリケーションの分散トランザクションのビジネス ライブラリに作成されます。このテーブルの中心となる機能は、更新前後の業務データのデータミラーリングをロールバックログに整理し、UNDO_LOG テーブルにバックアップして、業務上の異常をいつでもロールバックできるようにすることです。 フェーズ1 たとえば、以下ではユーザー テーブルの名前フィールドを更新します。
まず、Seata の JDBC データ ソース エージェントは、ビジネス SQL を解析して SQL メタデータを抽出します。つまり、SQL タイプ (UPDATE)、テーブル (ユーザー)、条件 (名前 = 'Programmer') などの関連情報を取得します。 第一段階のフローチャート まず、データ フロント ミラーをクエリし、解析によって取得した条件情報に基づいてクエリ ステートメントを生成し、データの一部を検索します。
データフロントミラー 次に、ビジネスSQLを実行して、フロントミラーデータの主キーに基づいてバックミラーデータをクエリします。
データバックミラー 更新前後の業務データのデータミラーをロールバックログに整理し、業務データの更新ログとロールバックログを同じローカルトランザクションでコミットし、それぞれ業務テーブルと UNDO_LOG テーブルに挿入します。 ロールバックレコードのデータ形式は次のとおりです: afterImage (前イメージ)、beforeImage (後イメージ)、branchId (ブランチトランザクションID)、xid (グローバルトランザクションID)
これにより、送信されたビジネス データの更新には必ず対応するロールバック ログが必要になります。 ローカル トランザクションをコミットする前に、各ブランチ トランザクションは、ブランチ (ブランチ ID) をグローバル トランザクション コーディネーター TC に登録し、変更するレコードのグローバル ロックを申請する必要があります。このデータをロックするには、SELECT FOR UPDATE ステートメントを使用します。ロックを取得できない場合は、ローカル トランザクションをロールバックする必要があります。 TM がトランザクションを開始すると、グローバルに一意の XID が生成され、呼び出された各サービス間で渡されます。 このようなメカニズムにより、グローバル トランザクションの最初のフェーズでローカル トランザクション ブランチ (Branch Transaction) をコミットし、ローカル トランザクションによってロックされたリソースを即座に解放することができます。第 2 フェーズでリソースを解放する従来の XA トランザクションと比較して、Seata はロック範囲を削減し、効率を向上させます。第 2 フェーズで例外が発生し、ロールバックする必要がある場合でも、対応するロールバック データを UNDO_LOG テーブルからすばやく見つけて、SQL に逆解析し、ロールバック補正を実現できます。 最後に、ローカル トランザクションがコミットされ、更新されたビジネス データと以前に生成された UNDO LOG データが一緒にコミットされ、ローカル トランザクションの送信結果がグローバル トランザクション コーディネーター TC に報告されます。 第二段階 2 番目の段階では、各ブランチの解決に基づいてコミットまたはロールバックを実行します。 解決がグローバル コミットの場合、各ブランチ トランザクションはコミットされて成功し、グローバル トランザクション コーディネーター (TC) はブランチに第 2 フェーズの要求を送信します。 TC からブランチ送信要求を受信すると、要求は非同期タスク キューに配置され、送信成功結果がすぐに TC に返されます。非同期キューは、ブランチ ID に基づいて、対応する UNDO LOG ロールバック レコードを非同期かつバッチで検索して削除します。 解決がグローバル ロールバックの場合、プロセスはグローバル コミットよりも少し複雑になります。 RM サービスは、TC グローバル コーディネータからロールバック要求を受信し、XID とブランチ ID を通じて対応するロールバック ログ レコードを見つけ、ロールバック レコードを通じて逆更新 SQL を生成して実行し、ブランチのロールバックを完了します。 注意: ローカル ビジネス トランザクションの実行後、ロールバック ログ レコード操作を削除する必要があります。 複数の分散トランザクションの利点と欠点については上記で説明しました。分散トランザクションの途中でSeataを実践して体感してみましょう。 シータプラクティス Seata は独立して導入する必要があるミドルウェアなので、まずは Seata Server をセットアップします。ここでは、最新バージョンの seata-server-1.4.0 を例に説明します。ダウンロードアドレス: https://seata.io/en-us/blog/download.html ファイルを解凍した後は、\seata\conf ディレクトリ内の file.conf ファイルと registry.conf ファイルのみに注意する必要があります。 Seata サーバー ファイル.conf file.conf ファイルは、永続的なトランザクション ログのモードを構成するために使用されます。現在、file、db、redis の 3 つのモードが提供されています。 file.conf ファイルの設定 注: db モードを選択した後、対応するデータベースに 3 つのテーブルを作成する必要があります: globalTable (永続的なグローバル トランザクション)、branchTable (送信された各ブランチの永続的なトランザクション)、および lockTable (リソースをロックする各ブランチの永続的なトランザクション)。
レジストリ.conf registry.conf ファイルは、レジストリ センターと構成センターを設定します。 現在、登録センターは、nacos、eureka、redis、zk、consul、etcd3、sofa の 7 種類をサポートしています。ここでは登録センターとして eureka を使用します。構成センターは、nacos、apollo、zk、consul、etcd3 の 5 つのタイプをサポートしています。 registry.conf ファイルの設定 設定が完了したら、\seata\bin ディレクトリで seata-server を起動すると、Seata サーバーがセットアップされます。 シータクライアント Seata Server 環境が構築されたら、order-server (注文サービス)、storage-server (在庫控除サービス)、account-server (口座金額サービス) の 3 つの新しいサービスを作成し、それぞれ eureka に登録します。 各サービスの一般的なコア構成は次のとおりです。
一般的なビジネス プロセスは次のとおりです。ユーザーが注文要求を開始し、ローカル注文サービスが注文レコードを作成し、RPC を介してリモートでストレージ控除在庫サービスとアカウント控除残高サービスを呼び出します。 3 つのサービスが同時に正常に実行された場合にのみ、注文プロセスが完了します。サービスの実行に失敗した場合、他のすべてのサービスはロールバックされます。 Seata はビジネス コードに非常に干渉します。コード内でこれを使用するには、@GlobalTransactional アノテーションを使用してグローバル トランザクションを開始するだけです。
前述したように、Seata AT モードは分散トランザクションを実装します。データ ロールバック ログを保存するには、関連するビジネス ライブラリに undo_log テーブルを作成する必要があります。テーブル構造は次のとおりです。
環境設定の作業はこれで完了です。完全なケースは後で GitHub に投稿される予定なので、ここではスペースを取りません。 シータのテスト プロジェクト内のサービス呼び出しプロセスは次のとおりです。 サービスコールプロセス 各サービスを開始した後、注文インターフェースを直接要求して効果を確認します。注文テーブルが正常にレコードを作成し、保管在庫テーブルの使用フィールドの数が増加し、口座残高テーブルの使用フィールドの数が増加している限り、注文プロセスが成功したことを意味します。 生データ リクエスト後の転送プロセスは正常であり、データは期待どおりです 注文データ そして、TMトランザクションマネージャのオーダーサーバーサービスのコンソールにも2フェーズコミットのログが出力されていることがわかりました。 コンソールが2回送信 それでは、いずれかのサービスに異常がある場合、正常にロールバックされるかどうかを確認しましょう。アカウント サーバー サービスでタイムアウト例外をシミュレートして、グローバル トランザクションをロールバックできるかどうかを確認します。 グローバルトランザクションのロールバック すべてのデータが正常に実行されなかったことが判明しましたが、これはグローバル トランザクションのロールバックも成功したことを示しています。 undo_log ロールバック レコード テーブルの変更を見てみましょう。 Seata はロールバック ログを非常に速く削除するため、テーブル内のロールバック ログを確認するには、特定のサービスにブレークポイントを設定して、より明確に確認する必要があります。 ロールバックレコード 要約する 上記では、2PC、3PC、TCC、MQ、Seata の 5 つの分散トランザクション ソリューションについて簡単に紹介し、Seata ミドルウェアの実装についても詳しく説明しました。しかし、どのソリューションを選択する場合でも、プロジェクトに適用する際には注意が必要です。データの一貫性が強い特定のシナリオを除き、可能であれば使用を避ける必要があります。なぜなら、どれだけパフォーマンスが優れていても、プロジェクトが分散トランザクションで覆われると、全体的な効率は数倍低下し、特に同時実行性の高い状況ではそのデメリットが顕著になるからです。 この場合の github アドレス: https://github.com/chengxy-nds/Springboot-Notebook/tree/master/springboot-seata-transaction |
<<: SD-WAN 業界を理解する: WAN クラウド化の観点から SD-WAN を見る
今日のダイナミックなビジネス環境において、組織は効率性、俊敏性、価値を高める革新的な方法を常に模索し...
みなさんこんにちは、私はXiaosiです。私のSina Weiboアカウントは(Xiaosi Des...
百度は長年にわたり中国の検索分野のリーダーであり、そのルーツは深く、後発企業が百度の地位に挑戦するの...
ショートビデオ、セルフメディア、インフルエンサーのためのワンストップサービス今は、個人のウェブサイト...
Velocihost は設立されてまだ半年ですが、KVM + SSD をベースにした低価格の VPS...
Shark Host (sharktech コンピュータ ルーム) の最新ニュース: ロサンゼルス ...
北京大学インターネット発展研究センターが9月1日に発表した「オンライン会議の社会的価値と今後の発展報...
オランダの VPS の推奨: オランダの VPS は苦情に強いものが多く、またオランダはヨーロッパや...
近年、国内のクラウドコンピューティング市場は、複数の業界での徹底的な応用の傾向を示しています。特に、...
ウェブサイトの最適化は、オンサイト最適化とオフサイト最適化の 2 つの側面に分かれています。その中で...
VPS のダークホースである Vultr.com は、長い間注目を集めていません。ブラック フライデ...
今日、偶然、360 Travelのウェブサイトが注目を集める形で立ち上げられたことを発見しました。一...
「外部リンクこそが王様」という言葉は、SEO 従事者が常に主張してきた言葉ですが、外部リンクがあらゆ...
2 番目の記事では、ロングテールキーワードの方がコンバージョン率が高いことをようやく説明しました。し...
コロナウイルス危機への対応として、世界中の組織は、世界が正常に戻るか、少なくとも次の正常に戻るまで待...