ホームページ >データベース >mysql チュートリアル >分散トランザクションの 7 つのソリューションをまとめます (理論 + ソリューション)

分散トランザクションの 7 つのソリューションをまとめます (理論 + ソリューション)

藏色散人
藏色散人転載
2021-09-22 15:44:103556ブラウズ

ビジネスの急速な発展とビジネスの複雑さの増大に伴い、ほぼすべての企業のシステムはモノリシックから分散へと移行します。マイクロサービスアーキテクチャへ。その場合、必然的に分散トランザクションの問題に遭遇することになります。

この記事では、最初に関連する基本理論を紹介し、次に最も古典的なトランザクションの解決策を要約し、最後にサブトランザクションのアウトオブオーダー実行 (冪等性、ヌル補償、およびハング問題) の解決策を示します。みんなでシェアしましょう。

基本理論

具体的なソリューションを説明する前に、まず分散トランザクションに関連する基本的な理論的知識を理解しましょう。

送金を例に挙げます。A は B に 100 元を送金する必要があります。すると、A への残高は -100 元、B への残高は 100 元になります。送金全体で A-100 が保証される必要があります。と B 100 が同時に成功するか、両方が同時に失敗します。さまざまなシナリオでこの問題がどのように解決されるかを見てみましょう。

トランザクション

複数のステートメントをまとめて操作する機能をデータベーストランザクションと呼びます。データベース トランザクションでは、トランザクションの範囲内のすべての操作が成功または失敗する可能性があることが保証されます。

トランザクションには、原子性、一貫性、分離性、耐久性という 4 つの属性があります。これら 4 つのプロパティは、多くの場合、ACID プロパティと呼ばれます。

  • 原子性 (アトミック性): トランザクション内のすべての操作は完全に完了するか、完了しないかのいずれかであり、中間リンクで終了することはありません。トランザクションの実行中にエラーが発生した場合は、トランザクションが実行されなかったかのように、トランザクションが開始される前の状態に復元されます。
  • Consistency (一貫性): トランザクションの開始前とトランザクションの終了後にデータベースの整合性が破壊されません。外部キー制約、アプリケーション定義の制約などを含む整合性は破壊されません。
  • 分離: データベースでは、複数の同時トランザクションが同時にデータの読み取り、書き込み、変更を行うことができます。分離により、複数のトランザクションが同時に実行される場合のクロス実行によるデータの不整合を防ぐことができます。
  • 耐久性: トランザクション完了後のデータへの変更は永続的であり、システムに障害が発生した場合でも失われることはありません。

当社のビジネス システムが複雑でなく、1 つのデータベースと 1 つのサービスでデータの変更と転送を完了できる場合は、データベース トランザクションを使用して転送ビジネスを正しく完了することができます。

分散トランザクション

銀行間送金ビジネスは典型的な分散トランザクション シナリオです。A が銀行をまたいで B に送金する必要があるとします。この場合、これには 2 つの銀行のデータが含まれるため、通過することはできません。 1 つのデータベースのローカル データベース トランザクション保証転送の ACID は、分散トランザクションを通じてのみ解決できます。

分散トランザクションとは、トランザクションの開始者、リソースとリソース マネージャー、およびトランザクション コーディネーターが分散システムの異なるノードに配置されていることを意味します。上記転送業務では、ユーザA−100の業務とユーザB100の業務は同一ノード上に存在しない。本質的に、分散トランザクションは、分散シナリオでのデータ操作の正しい実行を保証することを目的としています。

分散環境における分散トランザクションは、可用性、パフォーマンス、劣化したサービスのニーズを満たし、一貫性と分離の要件を軽減するために、一方では BASE 理論 (BASE 関連の理論、多くの内容が含まれています。興味のある学生は BASE 理論を参照してください):

  • Basic Business Availability (Basic Availability)
  • Soft state (Soft state)
  • Eventual Consistency一貫性)

同様に、分散トランザクションも ACID 仕様に部分的に準拠します。

  • 原子性: 厳密に準拠します
  • 一貫性: トランザクション完了後の一貫性は次のとおりです。厳密に守られます。トランザクションの一貫性は適切に緩和できます。
  • 分離: 並列トランザクションは影響を受けません。中間トランザクション結果の可視性によりセキュリティを緩和できます
  • 永続性: 厳密に守られます

分散トランザクション ソリューション

分散トランザクション ソリューションのため、完全な ACID 保証は達成できません。すべてのビジネス上の問題を解決できる完璧なソリューションはありません。したがって、実際のアプリケーションでは、ビジネスのさまざまな特性に基づいて最適な分散トランザクション ソリューションが選択されます。

Two-phase commit/XA

XA は、X/Open 組織によって提案された分散トランザクション仕様です。XA 仕様では、主に (グローバル) トランザクション マネージャー (TM) と (ローカル) トランザクション マネージャーが定義されています。リソース マネージャー (RM) 間のインターフェイス。 mysql などのローカル データベースは、XA

XA で RM の役割を果たします。

XA は 2 つのフェーズに分かれています。

最初のフェーズ (準備): つまり、すべての参加者がトランザクションの実行とロックの準備をします。生きていくために必要な資源。参加者の準備が完了すると、参加者は準備ができたことを TM に報告します。

第 2 フェーズ (コミット/ロールバック): トランザクション マネージャー (TM) は、すべての参加者 (RM) の準備ができていることを確認すると、すべての参加者にコミット コマンドを送信します。

現在主流のデータベースは、mysql、oracle、sqlserver、postgres などの XA トランザクションを基本的にサポートしています

###XA トランザクションは、1 つ以上のリソース マネージャー (RM)、トランザクション マネージャー (TM)、およびアプリケーション プログラム (ApplicationProgram) で構成されます。 )。 ###
ここでの RM、TM、AP の 3 つの役割は古典的な役割分担であり、Saga や Tcc などの後続のトランザクション モードで実行されます。

上記の転送を例として、正常に完了した XA トランザクション シーケンス図は次のとおりです。
分散トランザクションの 7 つのソリューションをまとめます (理論 + ソリューション)

参加者のいずれかが準備に失敗した場合、TM はすべての完了を通知します。 Prepare の参加者はロールバックを実行します。

XA トランザクションの特徴は次のとおりです。

  • シンプルで理解しやすく、開発が容易です
  • リソースの長期ロック、低い同時実行性

XA、Go 言語、PHP、Python、Java、C#、Node などをさらに詳しく学習したい場合は、DTM

SAGA

Saga はこのデータベース ペーパーを参照してください。サガで言及された解決策。基本的なアイデアは、ロング トランザクションを複数のローカル ショート トランザクションに分割し、Saga トランザクション コーディネーターによって調整されることです。正常に終了した場合は正常に完了します。ステップが失敗した場合は、補償操作が逆の順序で 1 回呼び出されます。

上記の転送を例として、正常に完了した SAGA トランザクション シーケンス図は次のとおりです。

分散トランザクションの 7 つのソリューションをまとめます (理論 + ソリューション)

Saga がキャンセル ステージに到達したら、キャンセルします。ビジネスロジックの失敗は許されない。ネットワークまたはその他の一時的な障害により成功が返されない場合、TM はキャンセルが成功を返すまで再試行を続けます。

Saga トランザクションの特徴:

  • 高い同時実行性、XA トランザクションのように長時間リソースをロックする必要がない
  • 通常操作と補正操作を定義する必要があり、開発量が XA Big より大きい
  • 一貫性が弱く、送金の場合、ユーザー A がお金を差し引いてしまい、最終的な送金が再び失敗する可能性があります

この文書には、2 種類のリカバリを含む多くの SAGA コンテンツが含まれています。戦略には、ブランチ トランザクションの同時実行が含まれます。ここでの説明には、最も単純な SAGA のみが含まれています。

SAGA は、多くのシナリオ、長いトランザクション、およびビジネス シナリオに適用できます

#読者が SAGA をさらに詳しく学びたい場合は、SAGA の成功と失敗のロールバックの例や、さまざまなネットワーク例外の処理が含まれる DTM を参照できます。

TCC

TCC (試行-確認-キャンセル) の概念は、2007 年にパット ヘランドによって「分散トランザクションを超えた生活: 背教者の意見」というタイトルの記事で初めて発表されました。

TCC は 3 つのフェーズに分かれています。

    トライ フェーズ: 実行を試み、すべてのビジネス チェックを完了する (一貫性)、必要なビジネス リソースを確保する (準分離)
  • 確認フェーズ: ビジネス チェックなしで実行が実際にビジネスを実行し、試行フェーズで予約されたビジネス リソースのみを使用することを確認します。確認操作には冪等な設計が必要であり、確認が失敗した後は再試行が必要です。
  • キャンセル フェーズ: 実行をキャンセルし、Try フェーズで確保されたビジネス リソースを解放します。キャンセルフェーズの例外処理スキームは基本的に確認フェーズの例外処理スキームと同じであり、冪等な設計が必要です。
上記の送金を例にとると、通常、Try では金額が凍結されますが差し引かれず、confirm では金額が差し引かれ、Cancel では金額の凍結が解除されます。

分散トランザクションの 7 つのソリューションをまとめます (理論 + ソリューション)

TCC の確認/キャンセル フェーズでは、ビジネス ロジックの観点から失敗を返すことはできません。ネットワークやその他の一時的な障害により成功を返せない場合、TM は確認/キャンセルが正常に返されるまで、再試行が続けられます。

TCC の機能は次のとおりです。

    高い同時実行性と長期的なリソース ロックなし。
  • 開発量が大きいため、試行/確認/キャンセルのインターフェイスを提供する必要があります。
  • 一貫性が高く、SAGAで引き落とされたのに送金に失敗するといった事態は発生しません。
  • TCCは受注型ビジネスや納期に制約のあるビジネスに適しています。中間ステータス
読者が TCC をさらに詳しく知りたい場合は、DTM

ローカル メッセージ テーブルを参照してください

このソリューションは、もともと eBay アーキテクト Dan によって公開された記事です。プリチェットは2008年にACMに就任。設計の核心は、メッセージによる分散処理を必要とするタスクの非同期実行を保証することです。

一般的なプロセスは次のとおりです。

分散トランザクションの 7 つのソリューションをまとめます (理論 + ソリューション)

ローカル メッセージの書き込みとビジネス操作は 1 つのトランザクションに配置され、ビジネスとメッセージ送信のアトミック性が保証されます。それらはすべて成功するか失敗するかです。

フォールト トレランス メカニズム:

    残高控除トランザクションが失敗した場合、トランザクションは後続の手順なしで直接ロールバックされます
  • シーケンス生成メッセージが失敗した場合、残高増加トランザクションは失敗します。再試行
  • #ローカル メッセージ テーブルの機能:

#長いトランザクションは複数のタスクに分割するだけで済み、使いやすい

    プロデューサーには追加のメッセージ テーブルの作成が必要です
  • ##各ローカル メッセージ テーブルをポーリングする必要があります
  • ##コンシューマ ロジックが再試行によって成功しない場合は、操作をロールバックするための追加のメカニズムが必要です
  • 非同期に実行でき、後続の操作にロールバックが必要ないビジネスに適用可能
  • トランザクション メッセージ

    上記のローカル メッセージ テーブル ソリューションでは、プロデューサーは追加のメッセージ テーブルを作成してローカル メッセージ テーブルをポーリングする必要があり、これにより大きなビジネス負担が生じます。 Alibaba のオープン ソース RocketMQ 4.3 以降ではトランザクション メッセージが正式にサポートされており、このトランザクション メッセージは基本的に RocketMQ 上にローカル メッセージ テーブルを配置し、運用側でのメッセージ送信とローカル トランザクション実行のアトミック性の問題を解決します。

    トランザクション メッセージの送信と送信:

    • メッセージの送信 (ハーフ メッセージ)
    • サーバーはメッセージを保存し、メッセージの書き込み結果に応答します
    • 送信結果に基づいてローカル トランザクションを実行します (書き込みが失敗した場合、この時点では半分のメッセージはビジネスに表示されず、ローカル ロジックは実行されません)
    • コミットまたはロールバックを実行ローカル トランザクション ステータスに基づいて (コミット操作によりメッセージがパブリッシュされ、メッセージが消費されます) 表示されます)

    通常の送信フローチャートは次のとおりです:

    分散トランザクションの 7 つのソリューションをまとめます (理論 + ソリューション)

    #補償プロセス:

    コミット/ロールバック メッセージ (保留ステータスのメッセージ) のないトランザクションの場合、サーバーから「レビュー」を開始します。

    プロデューサーはレビュー メッセージを受信し、ローカルのステータスを返します。メッセージに対応するトランザクション (コミットまたはロールバック)
    トランザクション メッセージ スキームとローカル メッセージ テーブルのメカニズムは非常に似ていますが、主な違いは、元の関連するローカル テーブルの操作がリバース クエリ インターフェイスに置き換えられることです。 ##トランザクション メッセージの特性は次のとおりです:

    長いトランザクションは複数のタスクに分割する必要があるだけであり、単純な

      If コンシューマーのロジックが再試行に失敗した場合、操作をロールバックするには追加のメカニズムが必要です。
    • 非同期で実行されるビジネスと後続の操作にロールバックが必要ないアプリケーションに適用されます
    Ifトランザクション メッセージをさらに詳しく知りたい場合は、DTM または Rocketmq を参照してください。

    ベスト エフォート通知

    通知を開始した当事者は、特定の方法でビジネス処理結果を受信者に通知するために最善を尽くします。機構。具体的には次のとおりです。

    特定のメッセージ重複通知メカニズムがあります。通知を受信する側が通知を受信しない可能性があるため、メッセージを繰り返し通知するには、特定のメカニズムを導入する必要があります。

    メッセージ校正メカニズム。最善の努力にもかかわらず受信者が通知されない場合、または受信者がメッセージを消費した後に再度そのメッセージを消費したい場合、受信者は要求を満たすためにメッセージ情報をノーティファイアに積極的に問い合わせることができます。

    先ほど紹介したローカルメッセージテーブルとトランザクションメッセージはどちらも信頼できるメッセージですが、ここで紹介したベストエフォート通知とはどう違うのでしょうか?


    信頼できるメッセージの一貫性。通知の開始側は、メッセージが送信され、通知の受信側に送信されることを確認する必要があります。メッセージの信頼性の鍵は、通知の開始側によって保証されます。

    ベストエフォート通知では、通知を開始する側は受信側に業務処理結果を通知するために最善を尽くしますが、メッセージが受信されない場合があります。この場合、受信側はインターフェースを能動的に呼び出す必要があります。結果として、通知の信頼性の鍵は通知を受信する当事者にあります。

    ソリューションの観点から見ると、ベスト エフォート型通知には次のことが必要です。

    通知の受信者がインターフェースを通じて業務処理の結果を照会できるようにインターフェースを提供する

      メッセージキュー ACK メカニズム、メッセージ キューは、通知に必要な時間ウィンドウの上限に達するまで、1 分、5 分、10 分、30 分、1 時間、2 時間、5 時間、10 時間の間隔で通知間隔を徐々に増やします。後で通知する必要はありません
    • ベスト エフォート通知は、ビジネス通知タイプに適しています。たとえば、WeChat トランザクションの結果は、ベスト エフォート通知を通じて各販売者に通知されます。コールバック通知とトランザクション クエリ インターフェイスの両方があります。
    AT トランザクション モード

    これは、Alibaba オープン ソース プロジェクト シートのトランザクション モードであり、Ant Financial では FMT とも呼ばれます。利点は、トランザクション モードが XA モードと同様の方法で使用されることです。ビジネスはさまざまな補償操作を記述する必要がなく、ロールバックはフレームワークによって自動的に完了します。欠点も XA モードと同様です。長いトランザクション モードがあります。 -term ロック。これは高い同時実行性のシナリオを満たしません。パフォーマンスの観点から見ると、AT モードは XA よりも優れていますが、ダーティ ロールバックなどの新たな問題も引き起こします。興味のある学生は、seata-AT

    例外処理

    ネットワーク障害やビジネス障害などの問題は、分散トランザクションのあらゆる側面で発生する可能性があります。これらの問題には、分散トランザクションのビジネス メソッドが必要です。アンチエア ロールバック、冪等性、アンチハングの 3 つの特性。

    例外

    以下では、TCC トランザクションを使用してこれらの例外を説明します。

    空のロールバック:

    TCC リソースが呼び出されない場合Try メソッドの場合、2 段階の Cancel メソッドが呼び出されます。Cancel メソッドは、これが空のロールバックであることを認識して、直接成功を返す必要があります。

    これは、ブランチトランザクションでサービスダウンやネットワーク異常が発生した場合、ブランチトランザクションの呼び出しが失敗として記録されるためで、このとき実際にはTryフェーズは実行されず、障害が復旧すると、分散トランザクションはロールバックされ、2 段階の Cancel メソッドが呼び出され、空のロールバックが行われます。

    インポテンス

    :

    どのリクエストにもネットワーク異常やリクエストの繰り返しが存在する可能性があるため、すべての分散トランザクション ブランチは冪等性を確保する必要があります

    一時停止:

    一時停止とは、分散トランザクションの場合、Try インターフェイスの前に第 2 段階の Cancel インターフェイスが実行されることを意味します。

    理由は、RPC がブランチ トランザクション try を呼び出すと、最初にブランチ トランザクションが登録されてから RPC 呼び出しが実行されるためで、このとき RPC が呼び出すネットワークが混雑している場合、RPC タイムアウト後に TM が RM に通知します。おそらくロールバックが完了した後、Try の RPC リクエストがパーティシパントに到達し、実際に実行されます。

    上記の問題をよりよく理解するために、ネットワーク異常のタイミング図を見てみましょう。
    分散トランザクションの 7 つのソリューションをまとめます (理論 + ソリューション)

    • ビジネス プロセスがリクエスト 4 を実行する場合、 Try の前に Cancel が実行されます。 handle empty rollback
    • 業務処理要求 6、Cancel を繰り返し実行する場合、冪等である必要がある
    • 業務処理要求 8、Cancel 後に Try を実行し、一時停止処理が必要な場合

    上記の複雑なネットワーク異常に直面して、さまざまな企業が現在提案している解決策は、ビジネス パーティが一意のキーを使用して、関連する操作が完了したかどうかを問い合わせ、完了している場合は、その操作を照会するというものです。成功を直接返します。関連する判断ロジックは複雑でエラーが発生しやすく、ビジネス上の負担が大きくなります。

    サブトランザクションバリア

    プロジェクト https://github.com/yedf/dtm で、サブトランザクションバリア技術が登場しました。この技術を使用すると、この効果を実現できます。概略図:
    分散トランザクションの 7 つのソリューションをまとめます (理論 + ソリューション)

    これらのリクエストがすべてサブトランザクション バリアに到達すると、異常なリクエストはフィルタリングされ、通常のリクエストはバリアを通過します。開発者がサブトランザクション バリアを使用すると、上記のすべての例外が適切に処理されるため、ビジネス開発者は実際のビジネス ロジックに集中するだけで済み、負担が大幅に軽減されます。
    サブトランザクション バリアは、ThroughBarrierCall メソッドを提供します。このメソッドのプロトタイプは次のとおりです:

func ThroughBarrierCall(db *sql.DB, transInfo *TransInfo, busiCall BusiFunc)

ビジネス開発者は、busiCall に独自の関連ロジックを記述して、この関数を呼び出すことができます。 ThroughBarrierCall は、空のロールバックや一時停止などのシナリオで BusiCall が呼び出されないことを保証します。ビジネスが繰り返し呼び出される場合、ビジネスが 1 回だけ送信されることを保証する冪等な制御があります。

サブトランザクション バリアは TCC、SAGA、トランザクション メッセージなどを管理し、他の領域にも拡張できます

サブトランザクション バリアの原則

原則サブトランザクション バリア技術の特徴は、ローカル データベースにブランチ トランザクション ステータス テーブル sub_trans_barrier を確立することです。一意のキーは、グローバル トランザクション ID-サブトランザクション ID-サブトランザクション ブランチ名 (try|confirm|cancel)

です。
  • トランザクションを開く
  • If Try ブランチの場合、insertignore が gid-branchid-try に挿入されます。正常に挿入されると、バリア内のロジックが呼び出されます。
  • 確認ブランチの場合は、gid-branchid-confirm に insertignore が挿入されます。正常に挿入された場合は、バリア内のロジックを呼び出します。
  • キャンセル ブランチの場合は、挿入します。無視して gid-branchid-try に挿入し、gid-branchid-cancel を挿入します。try が挿入されず、cancel が正常に挿入された場合は、バリア内のロジックを呼び出します。
  • バリア内のロジックは成功を返し、トランザクションを返し、成功を返します。
  • バリア内のロジックはエラーを返し、トランザクションをロールバックし、エラーを返します。

このメカニズムでは、ネットワーク例外は解決されます。関連する問題

  • 空の補償制御 -- Try が実行されず、Cancel が直接実行された場合、バリア内のロジックを使用せずに gid-branchid-try に挿入された Cancel が成功し、空の補償制御が保証されます。
  • インポテント コントロール -- どのブランチにも一意のキーを繰り返し挿入することはできないため、繰り返し実行されないことが保証されます。
  • アンチハング コントロール -- Try は Cancel の後に実行され、挿入された gid- Branchid -try が失敗した場合は実行されず、ハング防止制御が保証されます。
これは、SAGA、トランザクション メッセージなどと同様のメカニズムです。

サブトランザクション バリアの概要

サブトランザクション バリア テクノロジは、https://github.com/yedf/dtm によって先駆的に開発されました。 Capital で使用されるインターフェイスの重要性は、シンプルで実装しやすいアルゴリズムを設計し、シンプルで使いやすいインターフェイスを提供することです。これら 2 つの項目により、開発者はネットワーク例外の処理から完全に解放されます。

このテクノロジーは現在、yedf/dtm トランザクション マネージャーと組み合わせる必要があります。現在、SDK は Go および Python 言語開発者に提供されています。他の言語用の SDK も計画中です。他の分散トランザクション フレームワークについては、適切な分散トランザクション情報が提供されている限り、この技術は上記の原則に従って迅速に実装できます。

概要

この記事では、分散トランザクションの基本理論を紹介し、一般的に使用される分散トランザクション ソリューションについて説明します。記事の後半では、トランザクション例外の理由も説明します。分類、そしてエレガントなソリューション。

yedf/dtm は、TCC、XA、SAGA、トランザクション メッセージ、ベストエフォート通知 (トランザクション メッセージを使用して実装) をサポートし、アクセスが非常に簡単な HTTP および gRPC プロトコルのサポートを提供します。

yedf/dtm は、Python、Java、PHP、C#、Node およびその他の言語のクライアントをサポートしています。「各言語の SDK」を参照してください。

皆さん、https://github.com/yedf/dtm プロジェクトにアクセスし、スターを付けてサポートしてください。

以上が分散トランザクションの 7 つのソリューションをまとめます (理論 + ソリューション)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はsegmentfault.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。