1. 分散トランザクションとは何ですか?
これを導入する前に、まずこれらの問題を理解しましょう
-
トランザクションとは何ですか?
-
地方事務って何ですか?
-
何が配布されているのでしょうか?
-
分散トランザクションとは何ですか?
1.1. トランザクションとは何ですか?
何かを達成するために、複数の参加者が複数のステップを実行する必要がある場合があり、最終的には複数のステップがすべて成功するかすべて失敗するかのどちらかになります。
たとえば、A が WeChat で B に 100 元を送金し、A のアカウントが 100 減り、B のアカウントが 100 増えます。これはトランザクションであり、この操作は成功するか失敗します。
ビジネスシーンも多く、参加者も多様
-
ユーザー登録によりメールが正常に送信されます。これには 2 つの操作が含まれます: ユーザー情報をデータベースに挿入、ユーザーにメールを送信、2 つの主な参加者: データベース、メール サーバー
-
Alipay を使用して電話料金をリチャージするには、2 つの操作が含まれます: Alipay アカウントの資金の減少、携帯電話の残高の増加、2 つの主な参加者: Alipay アカウント、携帯電話番号サービスプロバイダーのアカウント
トランザクションにはさまざまな参加者がいますが、この記事では主に db のトランザクションを使用して説明します。
1.2. ローカルトランザクションとは何ですか?
ローカル トランザクション、一般的な理解: つまり、トランザクション内のすべての操作は同じデータベース内で発生します。
たとえば、A が B に送金する場合、A と B の口座は同じデータベースにあります。
通常、MySQL、Oracle、SQL Server などのリレーショナル データベースを使用します。デフォルトでは、これらのデータベースはトランザクションの機能、つまりデータベース内でトランザクション操作を実行する機能を実現しており、データベース自体がこのトランザクションの正確性を保証できます。トランザクションの正確性を保証する方法を当社が検討する必要がなくなります。
1.3. データベーストランザクションの4つの特徴
1.3.1. 一貫性
トランザクション操作後の結果は、予想された結果と一致しています。A は 100 を B に転送します。トランザクションが終了すると、A のアカウントは 100 減り、B のアカウントは 100 増えるはずです。他には何も起こりません。
1.3.2. 原子性
トランザクションのプロセス全体はアトミック操作のようなもので、最終的にはすべて成功するかすべて失敗するかのどちらかになります。このアトミック性は最終結果からわかり、プロセスは最終結果から切り離すことができません。
1.3.3. 隔離
トランザクションの実行は、他のトランザクションによって干渉されることはできません。つまり、トランザクション内で使用される操作とデータは他の同時トランザクションから分離されており、同時に実行されるトランザクションは相互に干渉することができません。
1.3.4. 耐久性
トランザクションがコミットされると、データベース内のデータに対する変更は永続的になるはずです。トランザクションがコミットされた後、データはハードディスクに保存され、変更は永続的になります。
1.4. 何が配布されますか?
ある物事を完了するには複数の参加者がいて、複数の参加者は異なるマシンに分散されており、これらのマシンはネットワークまたはその他の方法を介して通信します。
たとえば、ICBC カードを使用して Alipay にチャージする場合、ICBC カードのアカウントは ICBC のデータベースにあり、Alipay のアカウントは Alipay のデータベースにあり、2 つのデータベースは異なる場所にあります。
1.5. 分散トランザクションとは何ですか?
誰もが分散とトランザクションの 2 つの概念を理解していれば、分散トランザクションは簡単に理解できます。トランザクションの複数の参加者が異なる場所に分散されているということです。
単一の DB 内でトランザクションの正確性を確認するのは簡単ですが、トランザクションの参加者が複数の DB に存在する場合、トランザクションの正確性をどのように確認すればよいでしょうか?
例: A が B に送金し、A は DB1 にあり、B は DB2 にあります。
step1.通过网络,给DB1发送指令:给A账户减少100
step2.通过网络,给DB2发送指令:给B账户增加100
ステップ 1 が成功した後、ステップ 2 が実行されると、ネットワークが失敗し、ステップ 2 の実行が失敗します。最終的に: A は 100 減りますが、B は 100 増加しません。最終結果は予期された結果と一致しません。それはトランザクションの失敗につながります。
分散トランザクションのソリューションを紹介する前に、他の 2 つの概念、 CAP と基本理論を理解する必要があります。これら 2 つの理論は分散トランザクションのソリューションの基礎を提供します。
2. CAP理論
2.1. CAP の概念を理解する
CAP は Consistency、Availability、Partition Tolerance の略称で、それぞれ整合性、可用性、パーティション許容度を表します。
以下で個別に説明しましょう。
CAP 理論の理解を容易にするために、電子商取引システムのいくつかのビジネス シナリオを組み合わせて CAP を理解します。
商品情報管理の実行プロセスを次の図に示します。
全体的な実行プロセスは次のとおりです。
1. 商品サービスはメインデータベースに商品情報の書き込みを要求(商品の追加、商品の変更、商品の削除)
2. メイン データベースはコモディティ サービスへの応答を正常に書き込みます。
3. 商品サービスは、データベースから商品情報を読み取るように要求します。
2.1.1. C - 一貫性
一貫性とは、書き込み操作後の読み取り操作で最新のデータ状態を読み取れることを意味し、データが複数のノードに分散している場合、どのノードから読み取っても最新の状態になります。
上の図では、製品情報の読み取りと書き込みは次の目標を満たしている必要があります。
1. コモディティ サービスがマスター データベースに正常に書き込まれると、スレーブ データベースへの新しいデータ クエリも正常に実行されます。
2. コモディティ サービスのマスター データベースへの書き込みに失敗すると、スレーブ データベースからの新しいデータのクエリも失敗します。
一貫性を実現するにはどうすればよいでしょうか?
1. マスター データベースに書き込んだ後、データをスレーブ データベースに同期する必要があります。
2. マスター データベースへの書き込み後、スレーブ データベースとの同期中にスレーブ データベースをロックし、同期の完了後にロックを解除します。これにより、クライアントがマスター データベースのプロセス中に古いデータをスレーブ データベースにクエリできないようになります。新しいデータをスレーブ データベースに書き込みます。
分散システムの一貫性の特徴:
1. データ同期プロセスにより、書き込み操作の応答にある程度の遅延が発生します。
2. データの整合性を確保するために、リソースは一時的にロックされ、データの同期が完了すると、ロックされたリソースは解放されます。
3. データ同期を要求したノードが失敗した場合、エラー メッセージが返され、古いデータは返されません。
2.1.2. A - 可用性
可用性とは、どのトランザクション操作でも応答結果を取得でき、応答タイムアウトや応答エラーが発生しないことを意味します。
上の図では、在庫状況に合わせて製品情報を読み取ることで、次の目標を達成できます。
1. データベースからデータクエリ要求を受信し、データクエリ結果に即座に応答します。
2. データベースからの応答タイムアウトまたは応答エラーは許可されません。
ユーザビリティを実現するにはどうすればよいでしょうか?
1. マスター データベースに書き込んだ後、データをスレーブ データベースに同期する必要があります。
2. スレーブ データベースの可用性を確保するために、スレーブ データベース内のリソースをロックすることはできません。
3. データが同期されていない場合でも、クエリ対象のデータは古いデータであってもデータベースから返される必要があります。古いデータがない場合は、規約に従ってデフォルトのメッセージを返すことができますが、エラーまたは応答タイムアウトを返すことができます。
分散システムの可用性の特徴:
1. すべてのリクエストが応答され、応答タイムアウトや応答エラーは発生しません。
2.1.3. P - パーティション許容値
通常、分散システムの各ノードはネットワークの分割である異なるサブネット上に展開されますが、ネットワークの問題によりノード間の通信障害が発生することは避けられませんが、この時点でもサービスは外部から提供できます。分割許容差です。
上の図では、パーティション許容値を満たす製品情報の読み取りおよび書き込みにより、次の目標を達成することができます。
1. マスター データベースからスレーブ データベースへのデータの同期に失敗しても、読み取りおよび書き込み操作には影響しません。
2. 1 つのノードに障害が発生しても、他のノードが提供するサービスには影響しません。
パーティション耐性を実現するにはどうすればよいですか?
1. ノード間の疎結合を効果的に実現できるように、非同期メソッドを使用してマスター データベースからスレーブ データにデータを同期するなど、同期操作ではなく非同期操作を使用するようにしてください。
2. スレーブ データベース ノードを追加します。そのうちの 1 つが他のスレーブ ノードをハングアップしてサービスを提供します。
分散パーティショントレランスの特徴:
1. パーティショントレランスは分散システムの基本的な機能です
2.2. CAPの組み合わせ
1. 上記の製品管理の例には同時に CAP がありますか?
すべての分散トランザクション シナリオでは、P の前提下では C と A が共存できないため、CAP の 3 つの特性を同時に利用することはできません。
例えば:
次の図は P を満たしており、分割耐性が達成されていることを意味します。
この図における分割許容値の意味は次のとおりです。
1) マスター データベースはネットワークを介してデータをスレーブ データと同期します。マスター/スレーブ データベースは異なるパーティションに配置され、ネットワークを介して相互作用すると考えることができます。
2) マスターデータベースとスレーブデータベース間のネットワークに障害が発生した場合でも、マスターデータベースとスレーブデータベースが提供する外部サービスには影響しません。
3) 1 つのノードに障害が発生しても、他のノードが提供するサービスには影響しません。
C を実装する場合は、データの整合性を確保する必要があります。データの同期中にデータベースから一貫性のないデータがクエリされるのを防ぐために、スレーブ データベースのデータをロックし、同期の完了後にロックを解除する必要があります。同期が失敗した場合は、の場合、スレーブ データベースはエラー メッセージまたはタイムアウト情報を返します。
A を実装する場合は、データの可用性を確保する必要があり、いつでもスレーブ データからデータをクエリできます。タイムアウトに応答したり、エラー メッセージが返されたりすることはありません。
分析により、P を満たすという前提の下で、C と A の間には次のような矛盾があることがわかります。
ネットワークが分断されている場合、マスターデータベースのデータをスレーブデータベースに同期することができず、外部から見えるデータの一貫性を確保するため、現時点ではスレーブデータベースに外部からアクセスすることはできません。外部サービスを提供できるのはマスター データベースのみであり、スレーブ データベースは可用性を失います。
ネットワーク パーティションの場合、マスター ライブラリのデータをスレーブ ライブラリに同期できません。このとき、2 つのライブラリのデータは不一致です。これにより、両方のライブラリが外部サービス (可用性) を提供できる場合、アクセスされたライブラリは、データが不整合になります。
したがって、CAP を同時に満たすことはできません。
2. CAP の組み合わせは何ですか?
したがって、運用環境で分散トランザクションを処理する場合は、要件に応じて CAP のどの 2 つの側面が満たされるかを決定する必要があります。
1)AP:
パーティション耐性と可用性を追求するために一貫性を放棄します。これは、多くの分散システム設計の選択です。
例えば:
上記の製品管理は、クエリされたデータが一定期間内に最新でないことをユーザーが受け入れることができる限り、AP を完全に実現できます。
通常、AP の実現により最終的な整合性が保証されます。後述する BASE 理論は AP に基づいて拡張されます。注文の返金、今日の返金は成功、明日の口座への入金など、ユーザーが受け入れることができる限り、いくつかのビジネス シナリオが実現されます。一定期間内に完了するだけです。
2)CP:
可用性を放棄し、一貫性とパーティション耐性を追求する私たちの動物園の飼育員は、実際には強い一貫性を追求しています。
3)CA:
ネットワーク障害やノードのハングアップの問題に関係なく、パーティション耐性を放棄する、つまりパーティションを分割しないことで、一貫性と可用性を実現できます。
その場合、システムは標準的な分散システムではなくなり、最も一般的に使用されるリレーショナル データは CA を満たすことになります。
上記の商品管理について、CA を実装する場合、構造は次のようになります。
マスター データベースとスレーブ データベースの間でデータの同期は実行されなくなり、データベースは各クエリ リクエストに応答でき、各クエリ リクエストはトランザクション分離レベルを通じて最新のデータを返すことができます。
2.3. 概要
以上により、CAP 理論の関連知識を学びましたが、CAP は実証済みの理論であり、分散システムは一貫性 (Consistency)、可用性 (Availability)、分割許容度 (Partition resistance) の 3 つの要件を同時に満たすことしかできません。 . の2点。アーキテクチャ設計や技術選定の検討基準としてご活用いただけます。ほとんどの大規模なインターネット アプリケーション シナリオでは、多くのノードと分散した展開があり、現在のクラスター サイズはますます大きくなっているため、ノード障害やネットワーク障害は正常であり、サービス可用性が N 9 (99.99.99.99.99.99) に達することを保証する必要があります。 .%)、優れた応答パフォーマンスを実現してユーザー エクスペリエンスを向上させるため、一般に次の選択が行われます: P と A を保証し、C の強い一貫性を破棄し、最終的な一貫性を確保します。
3. 基本理論
3.1. 強整合性と結果整合性について理解する
CAP 理論によれば、分散システムは一貫性 (Consistency)、可用性 (Availability)、分割耐性 (Partition Tolerance) の 3 つの項目のうち最大でも 2 つしか満たせないことがわかります。実際のアプリケーションではその中に多くの AP があり、AP は可用性とパーティション耐性を確保するために一貫性を放棄しますが、実際の運用では、多くのシナリオで一貫性を達成する必要があります。たとえば、前に示した例では、マスター データベースはスレーブ データベースとデータを同期します。一貫性が必要ない場合でも、データの一貫性を確保するには、最終的にはデータを同期する必要があります。この一貫性は、CAP の一貫性とは異なります。CAP の一貫性では、各ノードのデータが常に一貫している必要があります。強い一貫性が強調されていますが、最終的な一貫性は各ノードのデータは一定期間不一致であっても許容されますが、一定期間後には各ノードのデータが一致する必要があり、最終的なデータの一貫性が重視されます。
3.2.1. 基底理論の概要
BASE は、Basicly Available (基本的に利用可能)、Soft state (ソフトな状態)、Enterprise Consistent (最終的な一貫性) の 3 つのフレーズの頭字語です。BASE 理論は CAP の AP の拡張です。可用性は強整合性を犠牲にすることで得られます。障害が発生した場合、一部の部分は使用できなくなりますが、コア機能は使用可能であることが保証されます。データの不整合は許容されます。一定の期間は続きますが、最終的には一貫した状態に達します。BASE理論を満たすトランザクションを「フレキシブルトランザクション」と呼びます。
3.2.2. 基本的に利用可能
分散システムに障害が発生した場合、コア機能を確実に利用できるようにするために、利用可能な機能の一部が失われることが許容されます。例えば、ECサイトでの決済に問題が発生しているものの、商品は正常に閲覧できます。
3.2.3. ソフトステート
強い整合性は必要ないため、BASE ではシステム内に中間状態 (ソフト状態とも呼ばれます) が存在することが許可されています。この状態は、注文の「支払い」状態や「データ同期」状態など、システムの可用性には影響しません。 . 最終的にデータの整合性が取れた後、ステータスが「成功」ステータスに変わります。
3.2.4. 最終的な整合性
最終的な整合性とは、一定期間後にすべてのノード データが整合性に達することを意味します。たとえば、注文の「支払い」ステータスは最終的に「支払い成功」または「支払い失敗」に変化するため、注文ステータスは実際の取引結果と一致しますが、一定期間の遅延と待機が必要です。
4. 分散トランザクションの 5 つの一般的なソリューション
-
スキーム 1: 2PC (2 フェーズ コミット)
-
解決策 2: 3PC (3 フェーズ コミット)
-
オプション 3: TCC
-
シナリオ 4: 信頼できるニュース
-
オプション 5: ベストエフォート通知
以下の5つのプログラムを順番に紹介します。
5. スキーム 1: 2PC (2 段階提出)
5.1. 2PCとは何ですか?
2PC は、トランザクション処理全体を準備フェーズとコミット フェーズの 2 つのフェーズに分割する 2 フェーズ コミットのことで、2 は準備フェーズ、P は準備フェーズ、C はコミット フェーズを指します。
2PC の主な役割は次の 2 つです。
-
トランザクションコーディネーター
-
取引参加者
5.1.1. 準備フェーズ
トランザクション コーディネーターは各トランザクション参加者に準備メッセージを送信し、各参加者はローカル トランザクションをローカルで実行しますが、トランザクションはコミットせず (この時点でトランザクション操作のリソースはロックされている可能性があります)、その後、yes または no メッセージをトランザクション コーディネーターに返します。コーディネーター。
5.1.2. コミットフェーズ
準備フェーズでは、すべての参加者が「yes」を返します。このとき、トランザクション コーディネーターは各トランザクション参加者にコミット メッセージを送信します。コミット メッセージを受信した後、参加者はローカル トランザクションでコミット操作を実行します。
準備段階で参加者が「いいえ」を返した場合、または参加者が時間外に応答した場合(ネットワーク上の理由によりトランザクション コーディネーターとトランザクション参加者間の通信障害が発生する場合など)、トランザクション コーディネーターはこの時点で各トランザクション参加者にロールバック メッセージを送信します。参加者はロールバック メッセージを受信した後、ローカル トランザクションでロールバック操作を実行します。
5.1.3. 2pc のいくつかのルール
-
フェーズ 2 のコミット条件: フェーズ 1 のすべての参加者が Yes を返す
-
フェーズ 2 のロールバック条件、2 つのケース: フェーズ 1 の参加者が「いいえ」を返した場合、またはフェーズ 1 の参加者がタイムアウトで応答した場合
-
参加者の準備が成功すると、参加者へのコミットの送信も成功する必要があり、ロールバックの送信はロールバックできる必要があります。
-
2PC では、トランザクション コーディネーターがタイムアウト メカニズムを備えています。つまり、フェーズ 1 で、コーディネーターが参加者にメッセージを送信しますが、応答がないためにタイムアウトが発生します。このとき、第 2 段階のロールバックが直接実行されます。コーディネーターはタイムアウトしない マシン、たとえば、すべての参加者がフェーズ 1 の実行を完了すると、コーディネーターがハングアップします。この時点では、参加者はただ待つことしかできません。
5.1.4. 2PCの問題
-
ステージ 1 の実行が完了した後、参加者のローカル トランザクションは実行されましたが、送信されていません。この時点で、参加者のローカル トランザクション内のリソースはロックされています。この時点でコーディネーターがハングアップすると、参加者のローカル トランザクションはリソースは解放できませんが、他のビジネスの実行に直接影響します。
たとえば、参加者 1 が商品 1 の在庫を減らすと、商品 1 の在庫レコードはロックされますが、この時点で他の事業者もこのレコードを変更する必要がある場合、直接ブロックされて実行できなくなります。
-
2PC にはパフォーマンスの問題があります。たとえば、トランザクションには 10 人の参加者がいて、参加者 1 はフェーズ 1 でローカル リソースをロックし、その後、他の 9 人の参加者がフェーズ 1 を完了するのを待ちます。その後、参加者 1 は、トランザクション コーディネーター または、ロールバック後にリソースが解放され、参加者 1 は参加者 9 人を待機する必要があります。その結果、リソースのロックに時間がかかりすぎて、システムの同時実行性に影響します。
-
コーディネーターには単一障害点があります。フェーズ 1 の実行が完了すると、コーディネーターはハングアップします。このとき、参加者は混乱して待つことしかできません。これは、コーディネーターの高可用性によって解決できます。これは、後述の3pcの質問で解決しました。
-
トランザクションの不整合の問題: フェーズ 2 で、一部の参加者がコミット情報を受信しました。このとき、コーディネーターがハングアップするか、ネットワークの問題により他のコーディネーターがコミット要求を受信できません。このプロセス中に、複数のコーディネーターのデータが失われます。解決策: コーディネーターと参加者は可用性が高く、コーディネーターは 2PC 再試行をサポートし、2PC の 2 つのステージは冪等性をサポートする必要があります。
5.2. XAトランザクション
XA (eXtended Architecture) は、X/Open 団体によって提案された分散トランザクション処理の仕様を指します。XA は Tuxedo によって提案された分散トランザクション プロトコルであるため、分散トランザクションは XA トランザクションとも呼ばれます。
XA プロトコルは主に、トランザクション マネージャー TM (トランザクション マネージャー、コーディネーター) とリソース マネージャー RM (リソース マネージャー、参加者) の間のインターフェイスを定義します。
その中で、リソース マネージャーは、Oracle、DB2、MySQL などのデータベースによって実装されることが多く、これらの商用データベースはすべて XA インターフェイスを実装しており、トランザクション マネージャーはグローバル スケジューラーとして、さまざまなローカル リソースの送信とロールバックを担当します。
XA トランザクションは、データの一貫性を確保できる 2 フェーズ コミット (2PC) プロトコルに基づいて実装されており、多くの分散リレーショナル データ管理システムはこのプロトコルを使用して分散を完了します。フェーズ 1 は準備フェーズです。つまり、すべての参加者がトランザクションを実行し、必要なリソースをロックする準備ができています。参加者が準備ができたら、TM に準備ができたことを報告します。フェーズ 2 は提出フェーズです。TM は、すべての参加者が準備完了であることを確認すると、すべての参加者に COMMIT コマンドを送信します。
簡単に言うと、XA はデータにおける 2PC の実装です。
誰もが mysql を使用したことがある、一般的なトランザクション プロセス:
start transaction; //打开事务
执行事务操作
commit|rollback; // 提交或者回滚事务
上記のトランザクション操作では、現在の接続がコミットまたはロールバック操作を送信しない場合、接続が切断されるか、mysql が再起動される場合、上記のトランザクションは自動的にロールバックされます。
mysql の xa の構文:
XA {START|BEGIN} xid [JOIN|RESUME] //开启XA事务,如果使用的是XA START而不是XA BEGIN,那么不支持[JOIN|RESUME],xid是一个唯一值,表示事务分支标识符
XA END xid [SUSPEND [FOR MIGRATE]] //结束一个XA事务,不支持[SUSPEND [FOR MIGRATE]]
XA PREPARE xid 准备提交
XA COMMIT xid [ONE PHASE] //提交,如果使用了ONE PHASE,则表示使用一阶段提交。两阶段提交协议中,如果只有一个RM参与,那么可以优化为一阶段提交
XA ROLLBACK xid //回滚
XA RECOVER [CONVERT XID] //列出所有处于PREPARE阶段的XA事务
好き:
xa start 'xa-1';
执行事务操作;
xa prepare 'xa-1'; //阶段1,此时事务操作的资源被锁住,事务未提交
xa commit | rollback;//阶段2
xa トランザクションは通常のトランザクションとは少し異なります。上記の xa トランザクションにはロゴが付いています。xa-1
準備後xa-1
、接続が切断されたり、mysql が再起動されたりしても、トランザクションはまだ進行中です。mysql の再起動後、prepare
または呼び出し側が再接続した後も、トランザクションはまだ実行中です。 mysql に送信すると、それを保持できます。トランザクション ID は、トランザクションを終了するためにxa-1
送信され続けます。xa commit |rollback
mysql で複数のデータベースを作成し、上記の xa スクリプトを使用して 2 フェーズ コミットを試して、プロセスの感触を得ることができます。
5.3. XA におけるトランザクション コーディネーター設計の重要なポイント
XA では、一部の一般的な DB などのトランザクション参加者は 2PC の機能を実現していますが、コーディネーターは独自に開発する必要があります。
-
グローバルに一意の XA トランザクション ID レコードを生成し、記録します。
-
トランザクションコーディネーターにはリトライ機能が必要であり、途中段階での異常動作に対してはリトライを続けることで最終的にトランザクションを完了させることができる
-
コーディネーターは操作を再試行するため、2pc の各ステージがべき等であることを確認する必要があります。
5.4. 2PC ソリューション
-
Seata : Seata は、Alibaba ミドルウェア チームによって開始されたオープン ソース プロジェクト Fescar で、後に Seata に名前変更されました。2PC をサポートするオープン ソースの分散トランザクション フレームワークです。
-
atomikos+jta : jta は Java の分散トランザクション用のインターフェイス仕様です。atomikos は jta の実装であり、XA によって内部的に実装されます。トランザクション参加者が XA トランザクションを自己テストする場合、このメソッドを使用して解決できます。参加者は次のとおりです: mysql、oracle、sqlserver この方法を使用できますが、パフォーマンスは全員が考慮する価値のある問題です。
-
開発者が自ら実現する : 全員が2pcのプロセスを理解した後、自分で開発して挑戦することができます。
6. スキーム 2: 3PC (3 フェーズコミット)
6.1. 2PC のレビュー
たとえば、A が B と C を招待して Glory of Kings を一緒にプレイする場合、2PC プロセスは次のようになります。
A がコーディネーター、B と C が参加者です。
6.1.1. フェーズ 1 (準備フェーズ)
(1)、ステップ 1-1: A WeChat B
step1-1-1:A->B:有空么,我们约C一起王者荣耀
step1-1-2:B->A:有空
step1-1-3:A->B:那你现在就打开电脑,登录王者荣耀,你等着,我去通知C,然后开个房间
step1-1-4:B->A:已登录
(2)、ステップ 1-2: A WeChat C
step1-2-1:A->C:有空么,我约了B一起王者荣耀
step1-2-2:C->A:有空
step1-2-3:A->C:那你现在就打开电脑,登录王者荣耀,你等着,我去开个房间
step1-2-4:C->A:已登录
6.1.2. フェーズ 2 (コミットフェーズ)
この時、BとCは既にキングオブグローリーにログインしており、Aがキングオブグローリーにログインしてルームを開きます。
(1)、ステップ2-1: A WeChat B
step2-1-1:A->B:房间号是xxx,你可以进来了
step2-1-2:B->A:我的,我进来了
(2)、ステップ 2-2: A WeChat C
step2-2-1:A->C:房间号是xxx,你可以进来了
step2-2-2:C->A:我的,我进来了
それから三人は楽しく遊び始めた。
6.1.3. 2PC の一部の例外
(1) 状況 1: step1-2-4 がタイムアウトになり、A が C がログインしたことを示すメッセージを受信できなくなりました
このとき、A は C と何が起こっているのか知りませんが、2PC のコーディネーターにはタイムアウト機構があり、コーディネーターが参加者にメッセージを送信し、長時間応答が得られなかった場合は、次のように扱われます。このとき、A は B を与え、C は B と C の両方をロールバックさせる、つまりゲームをキャンセルするロールバック メッセージを送信します。
(2)、状況 2: ステップ 1-1 の後、コーディネーター A が電話を切りました。
この時点で、B さんはすでにパソコンの電源を入れて待っていましたが、A さんと C さんの姿はまだ見えず、かなり苦しんでおり、どれくらい待たなければならないかわかりません。とても大変です。
(3)、状況 3: フェーズ 1 の後、コーディネーター A が電話を切りました。
この時点で、BとCはそれぞれのアカウントにログインしており、10分以上待っていますが、Aの姿が見えなくても、何もせずに待つことしかできません。
(4)、状況 4: ステップ 2-2-1、C ネットワーク障害に問題がある
このとき、C は A が送信したメッセージを受信できません。その結果、A と B の両方が部屋に入ってきて、C が行方不明になり、ゲームは正常に開始できず、最終結果は期待された結果と一致しません ( 3 人が一緒にゲームをプレイすることが期待されていますが、実際には部屋には 2 人しかいません)
6.1.4. 一般に、2PC には 2 つの主な問題があります。
参加者への質問
参加者はコーディネーターの指示に従ってしか行動することができず、コーディネーターの指示が届かない場合はただ座って待つことしかできず、結果としてdb内では操作データが常にロックされ、他のオペレーターの迷惑となるブロックされること。
データの不整合の問題
コミットフェーズでコーディネーターまたは参加者が電話を切ると、最終的なデータの不整合の問題が発生する可能性があります。
6.2. 3PC
3PC は主に、2PC のコミット フェーズで参加者が待機している問題を解決します。2PC のコミット フェーズでは、コーディネーターが電話を切った場合、参加者は退出方法がわかりません。2PC ではコーディネーターのみがタイムアウト機構を持っていますが、3PC ではコーディネーターと参加者がタイムアウト機構を導入しており、コミットフェーズでは、参加者が一定時間経過してもコミットコマンドの受信に失敗すると、参加者は自動的にタイムアウト機構を導入します。 2PC でリソースが長時間ロックされる問題を解決します。
2PC と比較して、3PC には 1 つの段階があり、これは 2PC の準備段階をさらに 2 つに分割することに相当し、3 段階の提出には 、 、CanCommit
およびPreCommit
3DoCommit
つの段階があります。
6.2.1. フェーズ 1: CanCommit フェーズ
2PC の前段階では、ローカル トランザクションの実行が完了した後、最後にコミットせず、他のサービスが実行を完了して Yes を返すのを待ち、実際にコミットを実行する前にコーディネーターがコミットを発行します。ここでの CanCommit はデータベース ロックの取得を試行することを指します。可能であれば 、 Yes を返してください。
この段階は主に 2 つのステップに分かれています
トランザクション クエリ: コーディネーターは CanCommit リクエストを参加者に送信します。トランザクションのコミット操作を実行できるかどうかを確認します。次に、エンゲージメントからの応答を待ち始めます。
応答フィードバック: 参加者が CanCommit リクエストを受信した後、通常の状況では、トランザクションがスムーズに実行できると判断した場合、参加者は Yes 応答を返し、準備完了状態になります。それ以外の場合は、「いいえ」をフィードバックするとトランザクションは終了し、この時点では参加者はタスクに対して操作を実行しません。
6.2.2. フェーズ 2: PreCommit フェーズ
フェーズ 1 で、すべての参加者が Yes を返すと、トランザクションの事前コミットの PreCommit フェーズに入ります。ここでのPreCommit ステージは、コーディネーターと参加者の 両方がタイムアウト メカニズムを導入している点を除いて、上記の最初のステージと似ています (2PC では、コーディネーターのみがタイムアウトでき、参加者にはタイムアウト メカニズムがありません)。
6.2.3. フェーズ 3: DoCommit フェーズ
これは 2pc の第 2 段階と同様です。
6.3. King of Glory 3PC プロセス
6.3.1. 通常のプロセス
(1)、フェーズ 1 (CanCommit フェーズ)
ステップ1-1: A WeChat B
step1-1-1:A->B:有空么,我们约C一起王者荣耀
step1-1-2:B->A:有空
ステップ1-2: WeChat C
step1-1-1:A->B:有空么,我们约B一起王者荣耀
step1-1-2:B->A:有空
(2)、フェーズ 2 (PreCommit フェーズ)
ステップ2-1: A WeChat B
step2-1-1:A->B:你现在就打开电脑,登录王者荣耀,等我消息,如果10分钟没消息,你就自己开个房间玩吧(参与者超时机制)。
step2-1-2:B->A:已登录
ステップ2-2: WeChat C
step2-2-1:A->C:那你现在就打开电脑,登录王者荣耀,等我消息,如果10分钟没消息,你就自己开个房间玩吧(参与者超时机制)。
step2-2-2:C->A:已登录
(3)、フェーズ 3 (DoCommit フェーズ)
この時、BとCは既にキングオブグローリーにログインしており、Aがキングオブグローリーにログインしてルームを開きます。
ステップ3-1: A WeChat B
step3-1-1:A->B:房间号是xxx,你可以进来了
step3-1-2:B->A:我的,我进来了
ステップ3-2: WeChat C
step3-2-1:A->C:房间号是xxx,你可以进来了
step3-2-2:C->A:我的,我进来了
それから三人は楽しく遊び始めた。
6.3.2. いくつかの例外状況
(1)、ステージ 1 の例外
現時点ではトランザクション操作はないため、この段階で問題が発生した場合は、トランザクションを直接終了できます。
(2)、ステージ 2、参加者が電話を切る
参加者が電話を切ったとしても、コーディネーターは他の参加者にロールバックするよう直接通知します。
(3)、フェーズ 2、コーディネーターが電話を切る
コーディネーターが電話を切ります。参加者はタイムアウト機構を導入しているため、無期限に待機することはなく、一定時間待機した後、ローカル トランザクションが自動的に送信されます。
このタイムアウト機構は無限待機の問題を解決しますが、一貫性の問題は解決しません。たとえば、上記の 3PC の後、コーディネータはハングstep2-1:A微信B
アップします。この時点で、A はログインしていますが、C は次のメッセージを受信していません。 A はログインを要求します。 タイムアウト 10 分後、A は自分でゲームをオープンしてプレイしましたが、結果は予想と一致しませんでした。
6.4. 3PCの問題
2PC における参加者の長期ブロックの問題(リソースが長期間解放できない問題)は解決しますが、一貫性の問題は解決しません。
これらの問題を回避する方法はありますか?
はい、TCC、次はTCCを見てみましょう。
7. スキーム 3: TCC
7.1. TCCとは何ですか?
分散トランザクションにおけるいくつかの役割
-
TM: トランザクション マネージャー。分散トランザクションのイニシエーターとして理解できます。
-
ブランチ トランザクション: トランザクションの複数の参加者は、独立したトランザクションとして理解できます。
TCC は Try、confirm、および Cancel の 3 つの単語の略語であり、TCC では各ブランチ トランザクションに 3 つの操作 (Try の前処理、確認の confirm、および Cancel の取り消し) を実装する必要があります。
Try 操作は業務確認とリソース予約を実行し、確認操作は業務確認操作を実行します。キャンセルは Try の逆の操作、つまりロールバック操作を実行します。
TM は、最初にすべてのブランチ トランザクションの try 操作を開始します。いずれかのブランチ トランザクションの try 操作が失敗した場合、TM はすべてのブランチ トランザクションの Cancel 操作を開始します。すべての try 操作が成功した場合、TM はすべてのブランチ トランザクションの confirm 操作を開始します。確認/キャンセル操作が失敗した場合、TM は再試行します。
7.1.1. 通常の流れ
Try フェーズ: 参加者の try メソッドを順番に呼び出し、すべてが成功を返します。
確認フェーズ: 参加者の確認メソッドを順番に呼び出し、すべてが成功を返します。
取引が完了しました。
7.1.2. 例外フロー
Try フェーズ: 参加者の try メソッドを順番に呼び出します。最初の 2 つの参加者 try メソッドは「yes」を返し、参加者 3 は「no」を返します。
キャンセル フェーズ: 成功した参加者に対してキャンセル操作を実行します。注意: キャンセル フェーズの参加者の順序は、試行フェーズの参加者の順序とは逆です。つまり、参加者 2 のキャンセルが最初に呼び出され、次にキャンセルが呼び出されます。参加者 1 の が呼び出されます。
7.2. TCC シナリオのケース
7.2.1. ケース 1: ライブラリ間転送
たとえば、A が B に 100 元を送金し、A と B の口座は異なるサービスにあるというシナリオです。
账户A
try:
try幂等校验
检查余额是否够100元
A账户扣减100元
confirm:
空
cancel:
cancel幂等校验
A账户增加可用余额100元
账户B
try:
空
confirm:
confirm幂等校验
B账户增加100元
cancel:
空
7.2.2. ケース 2: Alipay への出金
たとえば、誰もが Douyin をプレイしたことがあり、友人の中には Douyin で収入があり、その収入を Alipay に出金することができます。
抖音(账户表:余额、冻结金额)
try:
try幂等校验
检查余额是否够100元
抖音账户表余额-100,冻结金额+100
confirm:
confirm幂等校验
抖音账户冻结金额-100
cancel:
cancel幂等校验
抖音账户表余额+100,冻结金额-100
账户B
try:
空
confirm:
confirm幂等校验
调用支付宝打款接口,打款100元(对于商户同一笔订单支付宝接口是支持幂等的)
cancel:
空
7.3. TCC 共通フレームワーク
フレームワーク名 | ギットハブアドレス | 星の数 |
---|---|---|
tcc-トランザクション | https://github.com/changmingxie/tcc-transaction | 4750 |
謙虚に | https://github.com/Dromara/hmily | 2900 |
バイトTCC | https://github.com/liuyangming/ByteTCC | 2450 |
EasyTransaction | https://github.com/QNJR-GROUP/EasyTransaction | 2100 |
7.4. 自社開発の TCC フレームワーク設計アイデア
7.4.1. 関与する役割 (トランザクション開始者、トランザクション参加者、TCC サービス)
(1)、トランザクションイニシエーター(TM)
-
分散トランザクションを開始します。tcc サービスを呼び出して分散トランザクション注文を登録します。
-
ブランチを呼び出す: 各ブランチを順番に呼び出します。
-
結果のレポート: 最後に、トランザクションのすべてのブランチの実行結果を TCC サービスにレポートします。
-
補償インターフェイスを提供します: TCC サービスによって使用され、TCC サービスはこの補償インターフェイスを呼び出して補償操作を実行します。
(2)、取引参加者
-
3 つの方法を提供: 試行、確認、キャンセル
-
3 つのメソッドの冪等性を確保する
-
3つのメソッドで返される結果のステータスコードは成功、失敗、処理の3つだけであり、処理中は不明ステータスに相当し、ステータス不明のものについては補正処理中にリトライが行われます。
(3)、TCCサービス
-
独立したサービスです
-
分散トランザクション注文登録インターフェイスを提供します。 [トランザクション開始者が tcc サービスを呼び出して分散トランザクション注文 (注文ステータス: 0: 処理中、1: 処理成功、2: 処理失敗) を生成し、トランザクション開始者が分散トランザクションを取得するために使用します。注文 注文ID: TID]
-
分散トランザクション結果レポート インターフェイスを提供します: トランザクション開始者が使用する [トランザクション開始者は、トランザクションの実行中にトランザクションの実行結果を TCC サービスに報告します]
-
トランザクション補正操作を提供します。tcc オーダーでステータスが 1 であるオーダーをポーリングするジョブを開始し、補正するためにトランザクション イニシエーターの呼び出しを続けます。最後に、複数の補正の後、このオーダーの最終ステータスは 1 (成功) または 2 になります。 (失敗); それ以外の場合は、処理のために手動介入が必要です
7.4.2. タイミング図
](img/5.jpg)
7.4.3. 自社開発TCCフレームワークの技術ポイント
(1) フレームワークをどこに考慮すべきか
開発者はブランチ内の 3 つのメソッドのコードのみに注意を払う必要があり、残りはフレームワークによって完了する必要があります。
(2)、tccサービスにおけるトランザクション順序テーブルの設計
-
id: 注文ID
-
bus_order_id: ビジネスオーダー ID
-
bus_order_type: ビジネス タイプ (bus_order_id と Bus_order_type は一意である必要があります)
-
request_data: ビジネス リクエスト データ。楽しいビジネス サイドのリクエスト データを含む、json 形式で保存されます。
-
status: ステータス、0: 処理中、100: 処理成功、200: 処理失敗、初期ステータスは 0、最終ステータスは 100 または 200 でなければなりません
(3)、ブランチ内の 3 つのメソッドの冪等設計について
Java の Spring を例に挙げると、ブランチの 3 つのメソッドをインターセプトし、インターセプター内で冪等な操作を実装するインターセプターによって実現できます。
テーブル[分岐メソッド実行記録テーブル:tid、分岐、メソッド(try、confirm、cancel)、status(0:処理中、100:成功、200:失敗)、request_json(リクエストパラメータ)、response_json(応答パラメータ)]
リクエスト パラメーターについて: これは、メソッド リクエスト全体の完全なパラメーターを記録するために使用されます。これにはビジネス パラメーターが含まれており、json 形式で保存できます。
レスポンスパラメータ: ブランチメソッドの実行結果。json 形式で保存されます。
インターセプタでは、ブランチ&メソッドの2つの条件を使用してブランチメソッド実行記録テーブルをクエリし、クエリレコードのステータスが100または200の場合は、response_jsonを直接返します。
(4)、try フェーズは同期であり、他のフェーズは非同期です。
try フェーズがすべて成功した場合は、最後に確認フェーズも成功する必要があります。try フェーズで失敗した場合は、キャンセルを実行する必要があります。最終的には、すべてのキャンセルも成功する必要があります。 try フェーズが完了すると、最終結果はすでにわかっているため、try フェーズ完了後、後続の確認またはキャンセルを非同期で実行できるため、システム全体のパフォーマンスが向上します。
(5)、トランザクションの実行結果を非同期に報告する
イニシエーターは、すべてのブランチの各ステップの実行結果と最終トランザクションの実行結果を tcc サービスに報告し、tcc サービスはそれらをウェアハウスに置きます。これは、オペレーターがトランザクションの実行結果を確認してトラブルシューティングを行うのに便利です。
(6)補償について
TCC サービスに補償ジョブを追加し、定期的に TCC 分散注文テーブルをポーリングし、ステータスが処理中のレコードを取得します。注文テーブル request_data にはリクエスト パラメータが含まれており、request_data を使用してトランザクション イニシエータが提供する補償インターフェイスを呼び出して実行します。注文のステータスが最終(成功または失敗)になるまで、補償操作。
補償は減衰の形式で行われ、同じ次数に対応して、各間隔 (10 秒、20 秒、40 秒、80 秒、160 秒、320 秒) の時間間隔減衰の形式で補償されます。。。
(7)、手動介入
TCC 分散注文が長期間処理されている場合、何度も補正を行っても最終状態に達していません。現時点では、ビジネス上の問題が発生している可能性があり、手動による補正が必要です。このペアの注文レコードについては、開発者に警告を発し、介入を促す監視システムが必要です。
7.5. 概要
TCC トランザクションの処理フローを 2PC の 2 フェーズ コミットと比較すると、2PC は通常クロスデータベース DB レベルにありますが、TCC はアプリケーション レベルにあり、これはアプリケーション レベルでの 2PC の実装であり、実装する必要があります。ビジネス ロジックを通じて達成します。この分散トランザクションの実装の利点は、アプリケーションがデータ操作の粒度を定義できるため、ロックの競合を削減し、スループットを向上できることです。欠点は、アプリケーションにとって非常に煩雑であり、ビジネス ロジックの各ブランチで try、confirm、cancel の 3 つの操作を実装する必要があり、コードの量が比較的多くなることです。
8. シナリオ 4: 信頼できるニュース
8.1. 信頼できるメッセージの結果整合性とは何ですか?
信頼性の高いメッセージの結果整合性スキームとは、トランザクションの開始者がローカル トランザクションを完了してメッセージを送信するときに、トランザクションの参加者 (メッセージのコンシューマー) がメッセージを受信してトランザクションを正常に処理できる必要があることを意味します。トランザクション参加者に送信されます。最終的なトランザクションでは、両当事者が合意に達する必要があります。
ここで重要なポイントが 2 つあります。
-
メッセージ送信者のローカル トランザクションが正常に実行されると、メッセージは正常に配信されます。
-
メッセージ コンシューマは最終的にこのメッセージを消費できるようになり、最終的には分散トランザクションが最終的に合意に達します。
8.2. ビジネスシナリオ: 注文してポイントを送信する
電子商取引では、商品の注文後にポイントをユーザーに送信する必要があるが、注文テーブルとポイントテーブルが別のデータベースにあり、分散トランザクションが発生します。
私たちは信頼できるメッセージでこれに対処します。
-
注文が正常に行われた後にポイントを送信する操作を実現するために mq を使用します
-
製品の注文が正常に完了すると、メッセージが mq に配信され、ポイント システムがそのメッセージを消費してユーザーのポイントを増やします。
ここでは主に、商品を注文して mq? にメッセージを送信する操作を実装する方法について説明します。それぞれの方法の長所と短所は?
8.3. メッセージ配信プロセス: 方法 1
8.3.1. プロセス
-
step1 : ローカルトランザクションを開く
-
step2 : 買い物注文を作成する
-
step3 : メッセージを mq に投稿する
-
step4 : ローカルトランザクションを送信する
この方法は、トランザクションがコミットされる前にメッセージを送信します。
8.3.2. 考えられる問題
-
ステップ 3 で例外が発生しました。その結果、ステップ 4 が失敗し、製品の発注に失敗し、製品の発注業務に直接影響を及ぼしました。
-
ステップ 4 で例外が発生しましたが、他のステップは成功しました。商品の注文は失敗し、メッセージは正常に配信され、ポイントがユーザーに追加されました。
8.4. メッセージ配信プロセス: 方法 2
次にやり方を変えて、取引後にメッセージを送信します。
8.4.1. プロセス
-
step1 : ローカルトランザクションを開く
-
step2 : 買い物注文を作成する
-
step3 : ローカルトランザクションを送信する
-
step4 : mq にメッセージを投稿する
8.4.2. 考えられる問題
ステップ 4 で例外が発生し、他のステップは成功しました。結果として、製品の注文は成功しましたが、メッセージの配信は失敗し、ユーザーによるポイントの追加はありませんでした。
上記の 2 つはより一般的な方法ですが、最も間違いが発生しやすい方法でもあります。
8.5. メッセージ配信プロセス: 方法 3
-
step1 : ローカルトランザクションを開く
-
step2 : 買い物注文を作成する
-
ステップ 3 : メッセージを送信する必要があるレコード t_msg_record をローカル ライブラリに挿入します。
-
step3 : ローカルトランザクションを送信する
-
ステップ5 : タイマーを追加し、t_msg_recordをポーリングし、mqに送信するレコードをポストします。
このメソッドは、データベース トランザクション、ビジネス、およびメッセージ レコードをアトミックな操作として使用します。ビジネスが成功した後は、メッセージ ログが存在する必要があります。最初の 2 つの方法で発生する問題は解決されます。ビジネス システムが比較的単純であれば、この方法を使用できます。
マイクロサービスの場合、上記の方法はあまり良くなく、サービスごとに上記の操作が必要となり、拡張にも向きません。
8.6. メッセージ配信プロセス: 方法 4
メッセージ サービスとメッセージ ライブラリを追加します。これは、メッセージの保存、mq へのメッセージの送信と配信を担当します。
-
step1 : ローカルトランザクションを開く
-
step2 : 買い物注文を作成する
-
ステップ 3 : 現在のトランザクション ライブラリにログを挿入します。一意のビジネス ID (bus_id) を生成し、bus_id を注文に関連付け、現在のトランザクションが存在するライブラリに保存します。
-
step4 : メッセージサービスを呼び出します:bus_idを伝えて、まずメッセージをウェアハウスに入れます、この時点ではメッセージの状態は送信待ちであり、メッセージID(msg_id)を返します。
-
step5 : ローカルトランザクションを送信する
-
step6 : 上記がすべて成功した場合は、メッセージ サービスを呼び出して mq にメッセージを配信します。上記が失敗した場合は、メッセージ サービスを呼び出してメッセージの送信をキャンセルします。
上記の方法は大きく進歩したと考えられますが、考えられる問題を引き続き分析してみましょう。
-
システムにはメッセージサービスが追加されており、商品の発注業務はこのサービスに依存しており、業務への依存度が高いため、メッセージサービスが利用できなくなると業務全体が停止してしまいます。
-
ステップ 6 が失敗した場合、メッセージは送信中の状態になります。このとき、ビジネス側は、ビジネスが正常に実行されたかどうかを確認するためのチェックバック インターフェイス (bus_id クエリ経由) を提供する必要があります。メッセージ サービスは、スケジュールされたメッセージを追加する必要があります。タスクを実行し、送信中のメッセージに対して補償処理を行い、ビジネスが正常に処理されたかどうかを確認し、メッセージが配信されるかキャンセルされるかを決定します。
-
Step4はメッセージサービスに依存するため、メッセージサービスの性能が悪いと、現在の業務のトランザクション投入時間が長くなり、デッドロックが発生しやすくなり、同時実行性能が低下します。通常、トランザクション内でリモート呼び出し処理を行うことはタブーです。リモート呼び出しのパフォーマンスと時間は多くの場合制御不能であり、そのため現在のトランザクションが大規模なトランザクションになり、他の障害が発生します。
8.7. メッセージ配信プロセス: 方法 5
上記の方法で改善を続け、より良い方法が現れました。
-
ステップ 1 : グローバルに一意のビジネス メッセージ ID (bus_msg_id) を生成し、メッセージ サービスを呼び出し、bus_msg_id を伝え、最初にメッセージをウェアハウスに置きます。この時点で、メッセージのステータスは送信保留中であり、メッセージ ID ( msg_id)
-
step2 : ローカルトランザクションを開く
-
step3 : 買い物注文を作成する
-
step4 : 現在のトランザクションライブラリにログを挿入します(step3のビジネスをbus_msg_idに関連付けます)
-
step5 : ローカルトランザクションを送信する
-
step6 : 上記が成功した場合はメッセージサービスを呼び出してmqにメッセージを届ける場合と、上記が失敗した場合はメッセージサービスを呼び出してメッセージの送信をキャンセルする場合があります。
ステップ 6 が失敗した場合、メッセージは送信中の状態になりますが、この時点で、ビジネス パーティは、ビジネスが正常に実行されたかどうかを確認するために (bus_msg_id クエリ経由で) チェックバック インターフェイスを提供する必要があります。
メッセージ サービスは、ステータスが送信保留中のメッセージを補うために新しいスケジュールされたタスクを追加し、ビジネスが正常に処理されたかどうかを確認して、メッセージが配信されるかキャンセルされるかを決定する必要があります。
方法 5 と方法 4 と比較して、より良い点の 1 つは、メッセージ サービスへの呼び出しとメッセージ ランディング操作がトランザクションの外部で実行されることです。この小さな改善は、実際には非常に優れた最適化であり、メッセージ サービスの実行時間を短縮します。 Ali にはメソッド 5 をサポートするメッセージ ミドルウェアRocketMQがあり、それを使用できます。
8.8. メッセージの消費に関するいくつかの質問
繰り返し消費する問題をどう解決するか?
コンシューマーはポーリングして mq サーバーからメッセージをプルし、それを消費します。
メッセージコンシューマーがメッセージを消費するプロセス
-
ステップ 1 : mq からメッセージをプルします
-
step2 : ポイント加算などのローカルビジネスを実行
-
step3 : 消費後、mq からメッセージを削除します。
step2 が成功し step3 が失敗した場合、メッセージは再度 mq から取得され、繰り返し消費される問題が発生するため、消費の冪等性を考慮する必要があります。同じメッセージを複数回消費した場合と 1 回消費した場合の結果は次のようになります。一貫して、冪等性は別のトピックであり、次回詳しく説明します。
9. シナリオ 5: ベストエフォート通知
9.1. Alipay リチャージの場合
ユーザーが Alipay を使用してチャージできるようにする独自の電子商取引システムがある場合、プロセスは次のとおりです。
9.2. ユーザーの支払いプロセス (同期プロセスです)
-
ユーザーはブラウザでリチャージリクエストを開始します -> eコマースサービス
-
電子商取引サービスはリチャージ注文を生成し、ステータスは 0: 支払い保留中 (0: 支払い保留中、100: 支払い成功、200: 支払い失敗) になります。
-
電子商取引サービスは、Alipay に注文情報を要求し、Alipay 注文を生成し、Alipay 支払いリクエスト アドレス (注文情報、支払いが成功した後にユーザーに表示されるページ return_url、および非同期支払い通知アドレス Notice_url) を組み立てます。組み立てられた情報をユーザーに返します
-
ユーザーのブラウザは Alipay 支払いページにジャンプし、支払いを確認します。
-
Alipay は支払い結果を伝達し、return_url を同期的にコールバックします。return_url は支払い結果をユーザーに表示します。
9.3. Alipay は非同期で決済結果を加盟店に通知します
ユーザーの支払いプロセスが完了すると、この時点で Alipay での支払い注文は支払われていますが、電子商取引でのリチャージ注文のステータスはまだ 0 (支払い保留中) であり、この時点では、Alipay から支払い結果が通知されます。通知プロセス中に、ネットワークの問題により Alipay 通知が失敗する場合があります。このとき、Alipay は複数回の減衰再試行を通じてマーチャントに結果を通知するために最善を尽くします。このプロセスはベストエフォート通知タイプです。
Alipay からの通知を受信した後、販売者は冪等な方法でローカル注文を処理し、処理が成功したことを Alipay に通知します。その後、Alipay は通知しなくなります。
9.4. 減衰通知とは何ですか?
たとえば、Alipay は最大 100 回の通知を試行し、各通知の間隔が長くなります。たとえば、最初の失敗後は 10 秒ごとに 2 回目の通知が行われ、2 回目の失敗後は 30 秒ごとに 3 回目の通知が行われ、順番に間隔が増加します。
9.5. Alipay の通知が失敗した場合はどうすればよいですか?
販売者は、率先して Alipay のクエリ インターフェイスを呼び出し、注文の支払いステータスを問い合わせることができます。
9.6. 非同期通知が必要なのはなぜですか?
ユーザーの支払いプロセスに return_url はありませんか? Alipay が正常に支払った後、支払い結果と同期してこのアドレスを呼び出すため、販売者はこの return_url? でローカル注文ステータスを直接処理できます。この方法も可能ですが、ユーザーのネットワークが悪い可能性があり、return_urlの呼び出しが失敗するため、この際、notify_urlの非同期通知で決済結果を加盟店に通知する必要があります。
9.7. ベストエフォート通知タイプは何に使用されますか?
分散トランザクションでは、通話結果がすぐに分からない場合、着信側の業務処理に時間がかかる場合がありますが、着信側の業務処理後にベストエフォート通知により結果を発信者に通知することができます。
9.8. ベストエフォート通知には補償メカニズムが必要です
着信側は発信者に結果を通知するために最善を尽くしますが、極端な場合には失敗する可能性があり、このとき着信側はクエリ インターフェイスを提供する必要があります。
発信者は、長期間結果が分からない業務について積極的に着信先に問い合わせて処理することができる。
9.9. 通知せずに率先して確認することはできますか?
はい、着信側はクエリ インターフェイスを提供し、発信者は事前にクエリを実行することで結果を知ることができますが、通知方法はよりリアルタイムです。
呼び出し先が成功すると、呼び出し元にはすぐに通知されますが、呼び出し元はクエリ メソッドを積極的に採用するため、いつクエリを実行するか? この程度は把握しにくいので、両方を組み合わせた方が良いでしょう。
10. 分散トランザクションの比較分析
さまざまな分散トランザクション ソリューションを検討した結果、さまざまなソリューションの長所と短所がわかりました。
2PCに対する最大の批判は、それがブロッキング プロトコルであるということです。RM はブランチ トランザクションの実行後、TM の決定を待つ必要があり、この時点でサービスはリソースをブロックしてロックします。この設計は、ブロッキング メカニズムと最悪の場合の時間の複雑さの高さにより、トランザクションに関与するサービスの数が増加するにつれて拡張のニーズに適応できず、高い同時実行性と長いサブトランザクション ライフ サイクルに使用するのが困難です (長時間実行されるトランザクション) 分散サービス。
TCCトランザクションの処理フローを 2PC の 2 フェーズ コミットと比較すると、2PC は通常、データベース全体の DB レベルで処理されますが、TCC はアプリケーション レベルで処理され、ビジネス ロジックを通じて実装する必要があります。この分散トランザクションの実装の利点は、アプリケーションがデータ操作の粒度を定義できるため、ロックの競合を削減し、スループットを向上できることです。欠点は、アプリケーションにとって非常に煩雑であり、ビジネス ロジックの各ブランチで 3 つの操作 (try、confirm、cancel) を実装する必要があることです。さらに、その実装は比較的難しく、ネットワーク状態やシステム障害などのさまざまな障害理由に応じて、さまざまなロールバック戦略を実装する必要があります。一般的な使用シナリオ: フル、ログインしてクーポンを送信するなど。
信頼性の高いメッセージ結果整合性トランザクションは、実行サイクルが長く、リアルタイム要件が低いシナリオに適しています。メッセージメカニズムの導入後、同期トランザクション操作はメッセージ実行に基づく非同期操作となり、分散トランザクションにおける同期ブロッキング操作の影響を回避し、2 つのサービスの分離を実現します。一般的な使用シナリオ: サインアップしてポイントを取得、ログインしてクーポンを取得など。
ベストエフォート通知は、分散トランザクションにおける最も低い要件の 1 つであり、結果整合性の時間感度が低い一部のビジネスに適しています。これにより、開始側がビジネスの失敗に対処できるようになり、受信側が通知を受信した後に積極的に失敗を処理できます。開始側に関係なく、通知側が結果をどのように処理するかは、通知側のその後の処理には影響しません。開始側の通知側は、受信側の通知側に結果を検証するためのクエリ実行インターフェイスを提供する必要があります。一般的な使用シナリオ: 銀行通知、支払い結果通知など。
2PC | TCC | 信頼できるニュース | ベストエフォート通知 | |
---|---|---|---|---|
一貫性 | 強い一貫性 | 最終的には一貫性のある | 最終的には一貫性のある | 最終的には一貫性のある |
スループット | 低い | 真ん中 | 高い | 高い |
実装の複雑さ | 簡単 | 災害 | 真ん中 | 簡単 |
11. まとめ
条件が許せば、ローカル トランザクションには単一のデータ ソースを選択するよう最善を尽くします。これにより、ネットワークの相互作用によって引き起こされるパフォーマンスの損失が軽減され、弱いデータの一貫性によって引き起こされるさまざまな問題が回避されるからです。システムが分散トランザクションを頻繁かつ不当に使用する場合、まず全体的な設計の観点から、サービス分割が合理的であるかどうか、結合性が高く結合性が低いかどうかを観察する必要があります。粒度が小さすぎませんか?ネットワークの不確実性により、分散トランザクションは常に業界で問題となっており、私たちは分散トランザクションとスタンドアロン トランザクション ACID を比較することに慣れています。
データベース層の XA、アプリケーション層の TCC、信頼性の高いメッセージ、ベスト エフォート型通知など、どれも分散トランザクションの問題を完全に解決するものではなく、パフォーマンスや一貫性の点でトレードオフを生むだけです。 、および可用性を考慮して、優先順位に基づいていくつかのトレードオフを模索します。