ついに誰かが「TCC 分散トランザクション」の実装原理を説明しました!

ついに誰かが「TCC 分散トランザクション」の実装原理を説明しました!

これまでインターネット上で分散トランザクションに関する記事を数多く目にしてきましたが、そのほとんどは単に分散トランザクションに関するさまざまな技術的ソリューションを紹介するだけのものでした。多くの友人はまだ、分散トランザクションとは何か、プロジェクトでそれをどのように使用するのかを知りません。

[[250247]]

したがって、この記事では、わかりやすい言葉とマニュアルの図、そして電子商取引システムのケースプラクティスを組み合わせて、TCC 分散トランザクションとは何かを説明します。

まず、ここでは Spring Cloud の原則がいくつか関係している可能性があります。よくわからない場合は、前回の記事「インタビューでは Spring Cloud の基本原理について聞かないでください!」を参照してください。

ビジネスシナリオの紹介

まずビジネスシナリオを見てみましょう。支払い注文シナリオを備えた電子商取引システムがあるとします。

注文の支払い後、次の手順を実行する必要があります。

  • 注文のステータスを「支払済み」に変更する

  • 製品在庫の減算

  • 会員ポイントの増額

  • 倉庫に商品を出荷するよう通知するための販売配送注文を作成します

これは比較的現実的な一連の手順であり、電子商取引システムに取り組んだことがあるかどうかに関係なく理解できるはずです。

さらに考える

さて、ビジネス シナリオができたので、さらに一歩進んで、TCC 分散トランザクションの効果を実装する必要があります。

それはどういう意味ですか? つまり、注文サービス - 注文ステータスの変更、在庫サービス - 在庫の減額、ポイントサービス - ポイントの増加、倉庫サービス - 販売配送注文の作成です。

上記の手順は、一緒に成功するか、一緒に失敗するかのいずれかの全体的なトランザクションである必要があります。

たとえば、注文のステータスが「支払済み」に変更されましたが、在庫サービスが在庫を差し引くことができません。その商品の在庫は元々 100 個でしたが、現在 2 個が販売されたため、在庫は 98 個になるはずです。

結果はどうですか? 在庫サービス運用データベースの異常により、在庫数量が100のままです。これは不正行為ではないでしょうか?もちろん、そんなことは許されません!

しかし、TCC 分散トランザクション ソリューションを使用せず、Spring Cloud を使用してこのようなマイクロサービス システムを開発する場合は、次のようなことを行う可能性が高くなります。

上記のプロセスを直感的に表現した次の図を見てみましょう。

したがって、各サービスが統合されたトランザクションを形成することを保証するために、TCC 分散トランザクション メカニズムを使用する必要があります。

上記の手順はすべて成功するはずです。いずれかのサービス操作が失敗した場合、完了した操作を元に戻すためにすべての操作がロールバックされます。

たとえば、在庫サービスが在庫の減算に失敗した場合、注文サービスは注文ステータスの変更操作をキャンセルし、ポイントの増加と出荷通知の 2 つの操作の実行を停止する必要があります。

ここまで述べましたが、いつものように、図をあげます。この図を追うと直感的に感じることができます。

TCC分散トランザクションを実装する

では、すべてのサービスが連携して成功するように、TCC 分散トランザクションをどのように実装すればよいのでしょうか?それとも一緒に失敗しますか?

しばらくお待ちください。段階的に分析します。 Spring Cloud 開発システムを背景として説明しましょう。

TCC実装フェーズ1: 試す

まず、注文サービスのコードは次のようになります。

以前に Spring Cloud Architecture Principles の記事を読んでいて、Spring Cloud についてある程度理解している場合は、上記のコードを理解できるはずです。

実際、注文サービスはローカル データベース操作を完了すると、Spring Cloud の Feign を通じて他のサービスを呼び出します。

しかし、このコードだけでは TCC 分散トランザクションを実装するには不十分ですよね? !心配しないで、みんな。この注文サービスのコードをいくつか変更してみましょう。

まず、上記の注文サービスはステータスを OrderStatus.UPDATING に変更します。

これはどういう意味ですか? つまり、pay() メソッドでは、注文ステータスを直接支払済みに変更しないでください。まず、注文ステータスを「UPDATING」(変更中)に変更します。

このステータスには意味がありません。それは誰かがこのステータスを変更していることを意味します。

次に、在庫サービスによって直接提供されるreduceStock()インターフェースでは、在庫を直接減算しないでください。在庫を凍結することができます。

たとえば、元の在庫数量が 100 の場合、この在庫を 100 - 2 = 98 だけ減算しないでください。

販売可能な在庫を 100 - 2 = 98 に設定すれば問題ありません。その後、別のブロックされた在庫フィールドに 2 を設定します。つまり、2つの株が凍結されます。

同じことがポイント サービスの addCredit() インターフェイスにも当てはまります。ユーザーにメンバーシップポイントを直接追加しないでください。まず、ポイント テーブル内の事前に増分されたポイント フィールドにポイントを追加できます。

たとえば、ユーザーのポイントが元々 1190 で、それを 10 ポイント増やしたい場合、単に 1190 + 10 = 1200 ポイントと書かないでください。

クレジットを 1190 のままにして、prepare_add_credit フィールドなどの事前追加フィールドに値 10 を設定すると、追加する準備ができているクレジットが 10 個あることを示すことができます。

倉庫保管サービスの saleDelivery() インターフェースについても同様です。最初に販売配送注文を作成できますが、この販売配送注文のステータスは「不明」です。

つまり、販売配送注文は作成されたばかりで、そのステータスはまだ確定していません。

上記のインターフェースを変換するプロセスは、実際には、いわゆる TCC 分散トランザクションの最初の T で表されるステージ、つまり Try ステージです。

上記のプロセスをまとめると、TCC 分散トランザクションを実装する場合、まず、業務のメイン プロセスと各インターフェイスが提供する業務の意味は、業務操作を直接完了することではなく、Try 操作を完了することです。

この操作には通常、リソースのロック、予約ステータスの設定、一部のデータの凍結などが含まれます。

下の図と上のテキストを組み合わせて、全体のプロセスを見てみましょう。

TCC実装フェーズ2: 確認

すると、2つの状況に分かれます。最初の状況はより理想的です。つまり、各サービスが独自の Try 操作を実行し、正常に実行されます。ビンゴ!

この時点で、後続の実行を促進するために、TCC 分散トランザクション フレームワークに依存する必要があります。 ここで簡単に注意しておきたいのは、TCC 分散トランザクションを試してみたい場合は、国内のオープンソース ByteTCC、Himly、TCC-transaction などの TCC 分散トランザクション フレームワークを導入する必要があるということです。

そうでなければ、各ステージの実行状況を感知し、次のステージに実行を進める機能を手作業で実装するのは複雑すぎて困難です。

各サービスに TCC 分散トランザクション フレームワークを導入すると、注文サービスに組み込まれた TCC 分散トランザクション フレームワークは、各サービスの Try 操作が成功したことを検知できます。

この時点で、TCC 分散トランザクション フレームワークは、TCC の次のステージである最初の C ステージ (確認ステージ) へのエントリを制御します。

この段階を達成するには、各サービスにさらにコードを追加する必要があります。 たとえば、注文サービスでは、注文ステータスを正式に「支払済み」に設定する確認ロジックを追加できます。 これはおそらく次のようになります。

在庫サービスも同様です。 ReduceStock() インターフェースの確認ロジックを提供する InventoryServiceConfirm クラスを持つことができます。ここで、以前に凍結された在庫フィールドの 2 つの在庫が 0 に減少します。

この場合、販売可能な在庫はすでに 98 個になっており、凍結在庫 2 個がなくなったため、在庫減額は正式に完了します。

ポイントサービスも同様です。ポイント サービスに CreditServiceConfirm クラスを提供できます。このクラスには addCredit() インターフェイスの確認ロジックが含まれており、事前に追加されたフィールドの 10 ポイントを差し引いて実際のメンバー ポイント フィールドに追加し、1190 ポイントから 1120 ポイントに変更します。

倉庫サービスでも同様です。倉庫サービスで WmsServiceConfirm クラスを提供でき、saleDelivery() インターフェイスの Confirm ロジックを提供して、販売配送注文のステータスを正式に「作成済み」に変更できます。これにより、倉庫管理者は、以前の中間状態「不明」のままにするのではなく、販売配送注文を表示して使用できるようになります。

上記のサービスの確認ロジックが実装されました。注文サービスの TCC 分散トランザクション フレームワークは、各サービスの Try フェーズが成功したことを検知すると、各サービスの確認ロジックを実行します。

注文サービスの TCC トランザクション フレームワークは、他のサービスの TCC トランザクション フレームワークと通信し、各サービスの確認ロジックを順番に呼び出す役割を担います。これで、各サービスのすべてのビジネスロジックの実行が正式に完了します。

同様に、全員がプロセス全体を把握できるように、次の図を示します。

TCC実装フェーズ3: キャンセル

さて、これは比較的正常な状況ですが、異常な状況だったらどうなるでしょうか?

たとえば、ポイント サービスなどの Try ステージで実行に失敗した場合はどうなるでしょうか?

注文サービス内の TCC トランザクション フレームワークはこれを感知し、TCC 分散トランザクション全体をロールバックすることを決定できます。

つまり、各サービスの 2 番目の C フェーズであるキャンセル フェーズが実行されます。 同様に、このキャンセル ステージを実装するには、各サービスでコードを追加する必要があります。

まず、注文サービスは OrderServiceCancel クラスを提供する必要があります。このクラスには、pay() インターフェイスのキャンセル ロジックが含まれており、注文のステータスを「CANCELED」に設定できます。つまり、注文のステータスはキャンセルされます。

在庫サービスでも同様です。凍結在庫から 2 を差し引いて販売可能な在庫に戻す、つまり 98 + 2 = 100 という、reduceStock() のキャンセル ロジックを提供できます。

ポイント サービスでは、ポイント フィールドに事前に追加された 10 ポイントを差し引くために、addCredit() インターフェイスのキャンセル ロジックも提供する必要があります。

倉庫管理サービスでは、販売配送注文のステータスを「CANCELED」に変更してキャンセルされたことを示すために、saleDelivery() インターフェイスのキャンセル ロジックも提供する必要があります。

このとき、注文サービスの TCC 分散トランザクション フレームワークは、いずれかのサービスの Try ロジックが失敗したことを感知すると、各サービスの TCC 分散トランザクション フレームワークと通信し、各サービスの Cancel ロジックを呼び出します。

下の図を見て直感的に感じてみましょう。

要約と考察

さて、兄弟たち、これについて話した後、基本的に誰もが TCC 分散トランザクションが何であるかを知るはずです。

要約すると、TCC 分散トランザクションを操作したい場合は、 まず特定の TCC 分散トランザクション フレームワークを選択し、その後各サービスでこの TCC 分散トランザクション フレームワークを実行する必要があります。

次に、元のインターフェースを Try-Confirm-Cancel の 3 つのロジックに変換する必要があります。

  • まず、サービス呼び出しリンクは Try ロジックを順番に実行します。

  • すべてが正常であれば、TCC 分散トランザクション フレームワークは確認ロジックの実行を続行し、トランザクション全体を完了します。

  • サービスの Try ロジックに問題がある場合、TCC 分散トランザクション フレームワークはそれを検出し、各サービスの Cancel ロジックの実行を進めて、以前に実行されたさまざまな操作をキャンセルします。

これはいわゆるTCC分散トランザクションです。 TCC 分散トランザクションの核となる考え方は、簡単に言えば、次のような状況に遭遇したときです。

  • サービスのデータベースがダウンしています。

  • サービスがクラッシュしました。

  • そのサービスの Redis、Elasticsearch、MQ などのインフラストラクチャに障害が発生しました。

  • 在庫不足など、一部のリソースが不足しています。

まずは試してみましょう。ビジネスロジックを完了しないでください。まずは試してみて、各サービスが基本的に正常に動作できるかどうか、必要なリソースを最初に凍結できるかどうかを確認します。

すべての Try 操作が正常である場合、つまり、基盤となるデータベース、Redis、Elasticsearch、および MQ はすべてデータを書き込むことができ、使用する必要があるリソースが予約されています (インベントリの一部を凍結するなど)。

次に、各サービスの確認ロジックを実行します。基本的に、Confirm は分散トランザクションの完了を高い確率で保証できます。

たとえば、基盤となるデータベースに障害が発生したり、Redis に障害が発生したりして、Try フェーズでサービスが失敗した場合はどうなるでしょうか。

このとき、各サービスのCancelロジックが自動的に実行され、以前のTryロジックがロールバックされます。すべてのサービスは、設計されたビジネス ロジックを実行してはなりません。一緒に成功するか、一緒に失敗するかを決めましょう。

ちょっと待ってください、質問は思いつきましたか? 注文サービスが突然ハングアップして再起動するなど、予期しない状況が発生した場合、TCC 分散トランザクション フレームワークは、以前に完了していなかった分散トランザクションが引き続き実行されるようにどのように保証しますか?

したがって、TCC トランザクション フレームワークでは、いくつかの分散トランザクション アクティビティ ログを記録する必要があります。これらのログは、ディスク上のログ ファイルまたはデータベースに記録できます。分散トランザクション実行のさまざまな段階と状態を保存します。

問題はまだ終わっていない。サービスのキャンセルまたは確認ロジックの実行が常に失敗した場合はどうなりますか?

それも簡単です。 TCC トランザクション フレームワークは、アクティビティ ログを通じて各サービスのステータスを記録します。 たとえば、サービスのキャンセルまたは確認が成功しなかったことがわかった場合、キャンセルまたは確認ロジックの呼び出しを再試行し続け、成功することを確認します。

もちろん、コードにバグがなく、十分なテストが行​​われており、基本的に Try ステージが試行されている場合は、通常、Confirm と Cancel は成功します。

最後に、分散トランザクションをビジネスに追加した後の実行プロセス全体を示す別の図を示します。

実際、多くの大企業は、当社のように社内使用のために独自の TCC 分散トランザクション フレームワークを開発しています。

ただし、会社が TCC 分散トランザクション フレームワークを開発していない場合は、通常、オープン ソース フレームワークを選択します。

ここで、ByteTCC、TCC-transaction、Himly など、すべて我が国のオープンソースであるいくつかの優れたフレームワークをお勧めします。

興味がある方は、GitHub アドレスにアクセスして、使用方法や Spring Cloud や Dubbo などのサービス フレームワークとの統合方法を学んでください。

これらのフレームワークをシステムに統合すれば、前述の素晴らしい TCC 分散トランザクション効果を簡単に実現できます。

次に、信頼性の高いメッセージ最終整合性ソリューションによって実装される分散トランザクションについて説明し、このソリューションを使用した実際の運用で遭遇する高可用性保証アーキテクチャについても説明します。

最終的に一貫性のある分散トランザクションは、実際の運用環境で 99.99% の高可用性をどのように保証するのでしょうか?

上記では、TCC 分散トランザクションについて説明しました。一般的なマイクロサービス システムでは、ほとんどのインターフェース呼び出しは同期的です。つまり、1 つのサービスが別のサービスのインターフェースを直接呼び出します。

現時点では、さまざまなインターフェースの呼び出しが同時に成功するか、同時にロールバックされるようにするには、TCC 分散トランザクション ソリューションを使用する方が適切です。

ただし、実際のシステム開発プロセスでは、サービス間の呼び出しが非同期になる場合があります。 つまり、サービスは MQ、つまり RocketMQ、RabbitMQ、Kafka、ActiveMQ などのメッセージ ミドルウェアにメッセージを送信します。

次に、別のサービスが MQ からメッセージを消費して処理します。これは MQ に基づく非同期呼び出しになります。

では、この MQ ベースの非同期呼び出しでは、サービス間の分散トランザクションをどのように保証すればよいのでしょうか? 言い換えれば、MQ に基づいて非同期呼び出しを実装する複数のサービスのビジネス ロジックが、一緒に成功するか、一緒に失敗するかのどちらかになることを期待しています。

現時点では、分散トランザクションを実装するには、信頼性の高いメッセージ最終一貫性ソリューションを使用する必要があります。

上の図からわかるように、高同時実行性や高可用性などのさまざまな技術的課題を考慮せず、「信頼性の高いメッセージング」と「最終的な一貫性」という 2 つの観点だけを考慮すると、この分散トランザクション ソリューションは比較的単純です。

信頼性の高いメッセージ最終整合性ソリューションの中核プロセス

①上流サービス配信メッセージ

信頼性の高いメッセージの結果整合性ソリューションを実装する場合は、通常、信頼性の高いメッセージ サービスを自分で作成し、ビジネス ロジックを実装します。

まず、 アップストリーム サービスは信頼できるメッセージング サービスにメッセージを送信する必要があります。 簡単に言えば、このメッセージは、いくつかの対応するリクエスト パラメータを含むダウンストリーム サービスのインターフェイスへの呼び出しと考えることができます。

次に、 信頼できるメッセージング サービスは、このメッセージを「確認待ち」のステータスで独自のデータベースに保存する必要があります。

その後、 アップストリーム サービスは独自のローカル データベース操作を実行し、独自の実行結果に基づいて信頼性の高いメッセージング サービス インターフェイスを再度呼び出すことができます。

ローカル データベース操作が正常に実行された場合、信頼できるメッセージング サービスに接続してメッセージを確認します。ローカル データベース操作が失敗した場合、信頼できるメッセージング サービスにメッセージを削除するように要求されます。

確認済みのメッセージの場合、信頼性の高いメッセージング サービスはデータベース内のメッセージ ステータスを「送信済み」に更新し、メッセージを MQ に送信します。

ここで重要なポイントは、データベース内のメッセージ ステータスを更新し、メッセージを MQ に配信することです。これら 2 つの操作を 1 つのメソッドにまとめ、ローカル トランザクションを開始する必要があります。

それはどういう意味ですか? データベース内のメッセージ ステータスの更新が失敗した場合、例外がスローされ、メッセージは MQ に配信されずに終了します。 MQ 配信がエラーで失敗した場合、例外がスローされ、ローカル データベース トランザクションがロールバックされます。これら 2 つの操作は同時に成功するか、同時に失敗するかのいずれかになります。

アップストリーム サービスがメッセージを削除するように通知している場合、信頼性の高いメッセージング サービスはメッセージを削除する必要があります。

② 下流サービスがメッセージを受信する

ダウンストリーム サービスは、MQ からのメッセージを消費するのを待機するだけです。メッセージが消費されると、独自のローカル データベースが操作されます。

操作が成功した場合、処理が成功したことが信頼できるメッセージング サービスに通知され、信頼できるメッセージング サービスはメッセージのステータスを「完了」に設定します。

③上流サービスによるメッセージの100%確実な配信をどのように保証するか?

皆さんは上記のコアプロセスを読んでいますが、大きな疑問は、上記のメッセージ配信プロセスのいずれかのリンクで問題が発生した場合にはどうすればよいかということです。

上流サービスから下流サービスへのメッセージの 100% 確実な配信をどのように保証できるでしょうか?心配しないで、一つずつ分析してみましょう。

アップストリーム サービスが信頼できるメッセージング サービスに保留中の確認メッセージを送信するときにエラーが発生しても問題ありません。上流サービスは呼び出し例外を検出できるため、次のプロセスを実行する必要はありません。これは大丈夫です。

アップストリーム サービスがローカル データベースを操作した後、信頼できるメッセージ サービスにメッセージの確認または削除を通知するときに問題が発生する場合。

たとえば、通知が成功しなかった、実行が成功しなかった、信頼できるメッセージング サービスが MQ にメッセージを配信できなかったなどです。この一連の手順で何か問題が発生した場合はどうすればよいですか?

このような場合、メッセージは信頼できるメッセージング サービスのデータベース内で常に「確認待ち」の状態になるため、これはあまり問題ではありません。

この時点で、信頼性の高いメッセージング サービスで定期的に実行され、各メッセージのステータスを継続的にチェックするバックグラウンド スレッドを開発します。

「確認待ち」状態のままの場合は、メッセージに何らかの問題があるとみなされます。 この時点で、上流サービスによって提供されるインターフェースをコールバックして、「このメッセージに対応するデータベース操作は正常に実行されましたか?」と尋ねることができます。

アップストリーム サービスが実行が成功したと応答すると、信頼性の高いメッセージング サービスはメッセージのステータスを「送信済み」に変更し、メッセージを MQ に配信します。

アップストリーム サービスが実行が成功しなかったと応答した場合、信頼性の高いメッセージング サービスはデータベースからメッセージを削除できます。

このメカニズムにより、信頼性の高いメッセージング サービスが MQ へのメッセージの配信を確実に完了しようとすることが保証されます。

④下流サービスによるメッセージの100%確実な受信をどのように保証するか?

ダウンストリーム サービスの消費メッセージに問題があり、消費されない場合はどうなりますか?あるいは、ダウンストリーム サービスがメッセージを処理できない場合はどうなりますか?

実際のところ、それは問題ではありません。信頼性の高いメッセージング サービスでバックグラウンド スレッドを開発して、メッセージのステータスを継続的に確認できます。

メッセージのステータスが常に「送信済み」で、「完了」に変わらない場合は、ダウンストリーム サービスがメッセージを正常に処理したことがないことを意味します。

この時点で、信頼性の高いメッセージング サービスはメッセージを MQ に再度配信し、ダウンストリーム サービスがメッセージを再度処理できるようにします。

ダウンストリーム サービスのインターフェイス ロジックがべき等性を実装し、メッセージが複数回処理されることを保証する限り、重複データは挿入されません。

⑤RocketMQ をベースに信頼性の高いメッセージ結果整合性ソリューションを実装するにはどうすればよいでしょうか?

上記の一般的なソリューション設計では、信頼性の高いメッセージ サービスのさまざまな自己チェック メカニズムに完全に依存して、次の点を保証します。

  • アップストリーム サービスのデータベース操作が失敗した場合、 ダウンストリーム サービスは通知を受信しません。

  • 上流サービスのデータベース操作が成功した場合、 信頼性の高いメッセージング サービスは、呼び出しメッセージが下流サービスに配信されることを保証し、下流サービスがメッセージを正常に処理することを保証します。

このメカニズムは、MQ 非同期呼び出し/通知に基づいて、サービス間の分散トランザクション保護を保証します。 実際、Alibaba のオープンソース RocketMQ は信頼性の高いメッセージング サービスのすべての機能を実装しており、その中核となる考え方は上記と同様です。

ただし、高い同時実行性、高可用性、高パフォーマンスを確保するために、RocketMQ はより複雑なアーキテクチャを実装しており、これは優れています。 興味のある学生は、RocketMQ の分散トランザクションのサポートを確認できます。

信頼性の高いメッセージ最終的一貫性ソリューションの高可用性と実稼働実践

背景

多くの学生は上記の計画やアイデアが何であるかを知っているはずであり、私たちは主にこの一連の理論的アイデアの基礎を築きます。

実際に本番環境に導入する際に、高同時実行シナリオがない場合は、上記のアイデアを参考にして、特定の MQ ミドルウェアをベースにした信頼性の高いメッセージング サービスを開発できます。

同時実行性の高いシナリオの場合、上記のプロセスは RocketMQ の分散トランザクション サポートを使用して実装できます。

本日、皆さんにお伝えしたい中心的なトピックの 1 つは、このソリューションがどのようにして 99.99% の高可用性を確保できるかということです。

このソリューションで高可用性を確保するための最大の依存ポイントは、MQ の高可用性であることがわかったはずです。

RabbitMQ、RocketMQ、Kafka など、どの MQ ミドルウェアにも、高可用性を保証するメカニズムの完全なセットが備わっています。

したがって、大企業で信頼性の高いメッセージ最終整合性ソリューションを使用する場合、通常、MQ の高可用性を確保するために企業のインフラストラクチャ チームに依存します。

言い換えれば、MQ の 99.99% の高可用性を保証でき、MQ クラスターの全体的なダウンタイムが原因で会社のビジネス システムのすべての分散トランザクションの実行が失敗するようなことが決して起こらない Brothers チームを誰もが信頼すべきです。

しかし現実は残酷だ。多くの中小企業、さらには一部の中規模および大規模企業でも、MQ クラスターの全体的な障害のシナリオに多かれ少なかれ遭遇しています。

MQ が完全に利用できなくなると、ビジネス システム内のさまざまなサービスが MQ を介してメッセージを配信できなくなり、ビジネス プロセスが中断されます。

例えば、最近、電子商取引事業も手掛けている友人の会社では、社内のマシンに導入されている MQ ミドルウェアのクラスタ全体が故障して利用できなくなり、MQ に依存するすべての分散トランザクションが実行できなくなり、多数の業務プロセスが中断するという事態に遭遇しました。

この場合、この分散トランザクション ソリューションに高可用性保証メカニズムを実装する必要があります。

KVストレージキューサポートに基づく高可用性低下ソリューション

下の写真をご覧ください。これは、私がかつて指導した友人の会社が、信頼性の高いメッセージ最終一貫性ソリューションのために設計した、高可用性保証劣化メカニズムです。

このメカニズムはそれほど複雑ではなく、友人の会社の高可用性シナリオをシンプルかつ効果的に保証できます。 MQ ミドルウェアに障害が発生すると、自動的にバックアップ ソリューションにダウングレードされます。

① MQクライアントコンポーネントの自己カプセル化と障害認識

まず、MQ の障害を自動的に感知し、ダウングレードを自動的に完了させたい場合は、MQ クライアントをパッケージ化して、会社の Nexus プライベート サーバーに公開する必要があります。

次に、MQ の劣化をサポートする必要がある会社のビジネス サービスはすべて、この自己カプセル化されたコンポーネントを使用して MQ にメッセージを送信し、MQ からのメッセージを消費します。

独自のカプセル化された MQ クライアント コンポーネントでは、MQ への書き込み状況に基づいて MQ に障害があるかどうかを判断できます。

たとえば、10 回連続して MQ にメッセージを配信しようとしても例外またはエラー メッセージが表示されたり、ネットワークに到達できない場合は、MQ に障害があることを意味します。この場合、システムは自動的に問題を感知し、ダウングレード スイッチをトリガーできます。

② KVストレージのキューに基づくダウングレードソリューション

MQ がクラッシュしてもメッセージの配信を継続したい場合は、MQ の代替を見つける必要があります。

たとえば、私の友人の会社では同時実行シナリオは多くなく、メッセージの量も非常に少ないのですが、可用性の要件は高くなっています。このとき、Redis などの KV ストレージのキューを代替として使用できます。

Redis 自体はキュー関数とさまざまなキューのようなデータ構造をサポートしているため、KV ストレージ形式でキュー データ構造にメッセージを書き込むことができます。

PS: Redis のデータ保存形式、サポートされているデータ構造などに関する基本的な知識については、ご自身でご確認ください。インターネット上にはたくさんあります。

ただし、ここでは注意しなければならない大きな落とし穴がいくつかあります。

まず、 KV ストレージ コレクション データ構造の場合、あまり多くのデータを書き込まないことをお勧めします。そうしないと、値が大きくなり、深刻な結果を招くことになります。

したがって、Redis にキーを作成して、このデータ構造にメッセージを書き込み続けることは絶対にしないでください。これは絶対に不可能です。

2 番目に、 少数のキーに対応するデータをデータ構造に継続的に書き込んではなりません。そうすると、ホット キー (つまり、一部のキーが特にホット) が生成されます。

一般的に、KV クラスターはハッシュ化され、キーに基づいてさまざまなマシンに配布されることを知っておく必要があります。常に少数のキーを書き込むと、KV クラスター内のマシンへのアクセスが多すぎて負荷が大きくなりすぎます。

上記の考慮事項に基づいて、当時私が設計したソリューションは次のとおりです。

  • 毎日のメッセージ量に応じて、数百のキューが KV ストレージ内に固定的に分割され、数百の対応するキーが割り当てられます。

  • これにより、各キーに対応するデータ構造に過剰なメッセージが書き込まれず、少数のキーが頻繁に書き込まれないことが保証されます。

  • MQ 障害が発生すると、信頼性の高いメッセージング サービスはハッシュ アルゴリズムを使用して、各メッセージを数百の固定キーに対応する KV ストレージのキューに均等に書き込むことができます。

同時に、ZK を通じてダウングレード スイッチをトリガーする必要があり、MQ でのシステム全体の読み取りと書き込みが即座にダウングレードされます。

③ 下流サービス消費MQ劣化認識

ダウンストリーム サービスは、自己カプセル化されたコンポーネントを通じて MQ を消費します。コンポーネントは、ZK から劣化スイッチがオンになっていることを感知すると、まず MQ からのデータを引き続き使用できるかどうかを判断します。

それでもうまくいかない場合は、複数のスレッドを開始して、KV ストレージ内の数百のプリセット キューから同時にデータを取得します。

データが取得されるたびに、下流のサービスのビジネス ロジックに渡されて実行されます。 このメカニズムにより、MQ に障害が発生した場合に自動障害認識と自動劣化が実現されます。システムの負荷と同時実行性がそれほど高くない場合は、通常、このソリューションを使用しても問題はありません。

実稼働実装のプロセスには、多数の災害復旧訓練と実際の実稼働障害発生時のパフォーマンスが含まれるため、MQ に障害が発生した場合でもビジネス プロセスが自動的に実行され続けることが効果的に保証されます。

④障害の自動回復

ダウングレード スイッチがオンになっている場合、自己カプセル化されたコンポーネントはスレッドを開始し、定期的に MQ にメッセージを配信して回復したかどうかを確認する必要があります。

MQ が回復し、メッセージを正常に配信できる場合は、ZK を通じてダウングレード スイッチをオフにすることができ、その後、信頼性の高いメッセージ サービスが引き続き MQ にメッセージを配信します。ダウンストリーム サービスは、KV ストレージのキューにデータがないことを確認した後、MQ からのメッセージの消費に戻ることができます。

⑤事業内容の詳細

上記のソリューションは、普遍的なダウングレードソリューションですが、具体的な実装は各企業の異なるビジネスの詳細に基づいて決定する必要があります。多くの詳細は記事に反映できません。

たとえば、メッセージの順序を確保したいですか?ビジネスのダイナミクスに基づいて大量のキーを生成する必要はありますか?等

さらに、このソリューションを実装するには一定のコストがかかるため、会社のインフラストラクチャ チームにできる限り働きかけて、MQ の 99.99% の可用性を確保し、ダウンタイムを回避することをお勧めします。

次に、高可用性に対する企業の実際の需要によって異なります。時折の MQ ダウンタイムが問題なく許容できる場合は、このダウングレード ソリューションを実装する必要はありません。

ただし、企業のリーダーが、MQ ミドルウェアがダウンした後もビジネス システム プロセスを継続して実行する必要があると考えている場合は、この記事で説明したような高可用性の低下ソリューションを検討する必要があります。

最後に、一部の企業が 1 秒あたり数万または数十万の高同時リクエストに関与している場合、MQ のデグラデーション プランはより複雑になるように設計され、実現するのは決して簡単ではありません。

Chinese Huperzine: 10 年以上の BAT アーキテクチャ経験、一流インターネット企業のテクニカル ディレクター。数百人のチームを率いて、数億のトラフィックを処理する複数の高同時実行システムを開発しました。長年の研究で蓄積してきた研究論文や経験の要約を文書にまとめましたので、皆様にご紹介したいと思います。 WeChat 公開アカウント: Shishan’s Architecture Notes (ID: shishan100)。

<<:  テンセントクラウドは、企業が低コストでシームレスにクラウドに移行できるよう支援する新世代のデータベースをリリースした。

>>:  クラウドへの移行は議論の余地のない事実ですが、本当にコストはゼロなのでしょうか?

推薦する

SEOがユーザーエクスペリエンスに影響を与えないようにする

SEO がユーザー エクスペリエンスに影響を与えないようにしてください。Web サイトを構築する人は...

B2C医療電子商取引 - ブルーオーシャンにおける問題と解決策

正式な B2C 医薬品電子商取引は、2005 年に正式に人々の視界に入り始めました (単一ページ入札...

ウェブサイトの目標はSEOの旅の始まりです

私たちウェブマスターは皆、SEO がインターネット マーケティングの推進力であることを知っています。...

ニュースソースのソフト記事は悲惨なことになるかもしれない。Baiduは低品質のニュースサイトに対処する

みなさんこんにちは。私はMuzi Chengzhouです。ソフト記事の役割は誰もが知っています。A5...

現在の外部リンクがまだ有効かどうか、また外部リンクの作成方法を説明する図

まず、この記事を書くと、特定のウェブサイトの利益に関わる可能性がありますが、何があっても、SEO 最...

デジタル産業を支援し、インテリジェントな未来をつなぐ――西安航空基地企業「ファーウェイ参入」デジタル変革社長クラス

[51CTO.comからのオリジナル記事]現在、疫病と政治環境の影響により、多くの不確定要素が重なり...

インターネット化粧品ブランドは、B2C 電子商取引の道をどう進むべきでしょうか?

多くの Taobao ブランドとは異なり、Youzishe は自らを「インターネット ブランド」と呼...

CCTVと衛星テレビの広告入札が過去最高を記録、動画ウェブサイトは引き続き収益をあげている

CCTV と衛星テレビの広告入札が過去最高を記録し、動画ウェブサイトは引き続き収益を上げている (T...

Godaddy-エコノミーホスティング年間支払い 12 ドル (100G ハードドライブ)

godaddy からわずか 12 ドルで、PayPal、クレジットカード、Alipay をサポートす...

Vipshop の暴露: 自社にとっても競合他社にとっても再現が難しいフラッシュセールの神話

テンセントテクノロジー胡向報が6月7日に報じた。同社は赤字で上場し、株価は発行価格を下回り、機関投資...

ベストプラクティスを使用してクラウドリカバリ戦略を構築する方法

[[387865]]クラウド復旧戦略を構築することで、クラウド コンピューティング サービスを導入し...

Baiduスナップショットの不完全なキャプチャ事例の分析

Baidu は長い間、ポータル サイトのホームページのスナップショットのキャプチャが不完全であるとい...

ガンジの「離反者」が元雇用主を標的に:アント短期レンタルの内部抗争が暴露される

テンセントテクノロジー胡向報が1月8日に報じた。今年1月6日、Ganji.comの元幹部である王連涛...

企業の口コミマーケティングプロモーション戦略

オンラインプロモーションの最高レベルは、自分でプロモーションをしなくても、人気とトラフィックが上がり...