TCCパターンとSagaパターンでマイクロサービスのトランザクションをまとめてみた

こんにちわ、サイト管理者のわかっち (@wakatchi_tech) です。

質問者

マイクロサービスでシステム作ったらトランザクション管理がしんどいです。

こんな質問をいただきました。

マイクロサービスアーキテクチャでシステムを構築した際、更新対象が複数のサービスをまたがる場合は、トランザクションの扱いが途端に難しくなります。なかでも、障害発生時に各サービス間の処理をロールバックするためには補償(補正)トランザクションが必要になり、複雑なトランザクション制御が求められます。

補償トランザクションとは、処理の途中で失敗した場合に、それを取り消すことで実行結果を打ち消す処理のことです。補償トランザクションの実装は、打ち消す処理を提供するサービスと、それを呼び出すサービスの双方に負担があり、設計や実装が複雑になりがちです。

トランザクションには、1つのトランザクション内で1つのリソース(DBなど)処理のみ行うローカルトランザクションと、1つのトランザクション内で複数のリソース処理を行うグローバルトランザクションがあります。グローバルトランザクションは分散トランザクションとも呼ばれ、その実装としてはX/Open XAやWS-Transactionなどが知られています。

マイクロサービスアーキテクチャは、ローカルトランザクションを勧める一方で、グローバルトランザクション(分散トランザクション)は推奨しません。分散トランザクションは、複雑で不具合の原因になる可能性が高いためです。マイクロサービスアーキテクチャで推奨しているのは、分散トランザクションではなく、複数リソースの結果整合性を利用することです。複数リソースの結果整合性を利用する方法として、TCC(Try-Confirm/Cancel)パターンとSagaパターンと呼ばれるアーキテクチャがあります。

この記事は、TCCパターンとSagaパターンが、マイクロサービスのトランザクション特性に合わせてどう使われるかをまとめていきます。

マイクロサービスをまたがるトランザクションのタイプ

マイクロサービスをまたがるトランザクションは、サービス連携方法とサービス間の関連付けで分類できます。サービス連携方法には、リクエスト・リプライイベントドリブンの2つの方式があります。サービス間の関連付けには、オーケストレーション(中央集権型)コレオグラフィ(分散型)があります。さて、それぞれどのような特徴があるのでしょうか。

サービス連携の方式

リクエスト・リプライ

  • REST通信による連携方式です。
  • 自身の処理の一部を、他のサービスに依頼します。

イベントドリブン

  • イベントの発生によって特定のサービス処理が駆動される連携方式です。
  • 既に発生した事柄を他のサービスに通知することで、発生した事象に応じた処理を実行させます。

サービス間の関連付け

オーケストレーション

  • 中央の指揮者がサービスの呼び出しをコントロールします。
  • 各サービスは中央からのリクエストによってロジックを実行し、実行結果をレスポンスとして中央に返す、リクエスト・リプライの方式になります。
  • 同期通信に適しています。

コレオグラフィ

個々のサービスが自律的に動き、あらかじめ定義された他のサービスに働きかけます。

  • 個々のサービスは、定められた条件に従って自律して稼動し、条件に合致した他のサービスにデータを送ります。
  • 非同期通信に適しています。

サービス連携の方式方法を縦軸、サービス間の関連付けを横軸にトランザクションのタイプを分類すると、TCCパターンとSagaパターンをこのように図示できます。

それでは、TCCパターンとSagaパターンとはどのようなものでしょうか。

TCCパターン

TCCパターンはTry operations, Confirmation, and Cancellationの略で、コーディネーターとサービス群で構成するアーキテクチャです。TCCパターンは、アメリカで発表された論文をもとにしたアーキテクチャで、一部のECサイトやクラウドベンダでは実装されているようです。

わかっち

論文「Life beyond Distributed Transactions」では、Tentative(暫定)-Confirm/Cancelとなっているけど、今ではTentativeはTryと表現することが多いようだね。

TCCパターンによるオーケストレーション

コーディネーターに該当するサービスは、サービス群を呼び出しながら一連の処理を行います。サブルーチンを呼び出しながら処理するプログラムのイメージに似ています。

TCCパターンは、TryフェーズとConfirm/Cancelフェーズの2フェーズによってトランザクションを制御します。

Tryフェーズ

  1. コーディネータが各サービスに要求し、仮の状態を登録させます。

Confirm/Cancelフェーズ

  1. サービスの仮登録が全て完了した場合、サービスに正式登録を要求し、一連の処理が成功した旨を呼び出し元に返します。
  2. Tryフェーズでいずれかのサービスがタイムアウトしたり登録できなかった場合、コーディネーターはキャンセル要求を送信します。
  3. いずれかのサービスがタイムアウトしたり確定できなかった場合、コーディネーターは、成功するまで確認を再試行するか、一定回数再試行した後でバッチ処理、または、手動により修正します。

TCCパターンによるコレオグラフィ

TCCパターンによるコレオグラフィは、コーディネータから呼び出されたサービスが、さらに別のサービスを呼び出す(ネストしたサービスの呼び出し)ケースが該当します。ネストして呼び出されたサービスのトランザクション制御は、オーケストレーションと同様です。

TCCパターンを実装する際の留意点

Try/Confirm/CancelのAPIを実装する

TCCパターンでは、一連の処理を制御するコーディネーター(オーケストレーター)を用意し、複数リソース(サービス)の呼び出し制御を実装します。呼び出されるサービスは、Try/Confirm/Cancelの3つのAPIを実装する必要があります。

処理完了に2倍かかることがある

TCCパターンは、処理完了に2倍かかる場合があるので注意が必要です。これは、TCCパターンでは各サービス間で2回通信し、すべてのサービスからの試行要求の応答を受信したときにのみ確認フェーズを開始するためです。

サービスを最終状態ではなく仮(保留)状態を経由する

TCCパターンは、サービスを最終状態ではなく仮(保留)状態を経由するという特徴があり、キャンセル処理が簡単です。例えば、電子メールサービスの送信要求では、電子メールを送信準備としてマークし、確認要求で電子メールが送信されます。それに対応するキャンセル要求はマークするだけになります。

後述するSagaパターンは、トランザクションによって電子メールが送信され、対応する補償トランザクションで取消を説明する別の電子メールが送信されることになります。

Sagaパターン

Sagaパターンはイベント駆動のアーキテクチャです。Sagaパターンはマイクロサービス特有のものではなく、SOAでも採用されていたアーキテクチャです。また、Sagaパターンの元になる考え方は古く、1987年の論文が元になっています。

Sagaパターンは、ロールバックを行うことができない代わりに、補償という考え方を提供しています。ロールバックを行うことができないので、代わりにインタラクションの操作を逆向きにした取り消し操作により、擬似的なロールバックを行います。

Sagaパターンは以下の流れで処理します。

Sagaパターンの処理の流れ

  1. サービスは処理を行い、次のサービスに新しいイベントを送信します(下図の1、2)
  2. イベントを受信したサービスは、処理を行い、次のサービスに新しいイベントを送信します(下図の3、4)
  3. 分散トランザクションのロールバックは自動ではありません。別の操作/イベントを実装する必要があります(下図のa〜d)

【出展】

マイクロサービスとサービス・メッシュ(Istioが求められる背景) | Think IT(シンクイット)

マイクロサービスによる巨大な超分散システムの運用管理ソリューションとして注目されているIstioが必要とされる背景を解説します。

Sagaパターンによるオーケストレーション

オーケストレーションによるSagaパターンのアプローチは、コーディネーターとなるサービスが、Sagaの意思決定とビジネスロジックの順序付けを集中化します。各サービスに何をすべきか、いつ行うのかをコントロールするコーディネーター(Sagaオーケストレーター)を定義します。コーディネーターは、どのサービスを実行すべきかをMQのイベント/戻りイベントで各サービスと通信します。

なお、コーディネーターの各サービスへの要求にはREST通信の場合もあります。処理結果は、MQの戻りイベントで待ち受けます。

ユーザの注文を受注する簡単なシーケンス

  1. コーディネーター(受注サービス、Sagaオーケストレーター)は、注文のリクエストを受けると受注データ作成のトランザクションを開始し、受注データを仮登録します。
  2. コーディネーターは在庫サービスに注文イベントを送信します。
  3. 在庫サービスは注文イベントを待ち受け、在庫を更新し、引当完了のイベントで応答します。
  4. コーディネーターは引き当て完了のイベントを待ち受け、顧客サービスに支払い実行のイベントを送信します。
  5. 顧客サービスは支払い実行のイベントを待ち受け、決済を処理し、決済完了のイベントで応答します。
  6. コーディネータは決済完了のイベントを待ち受け、受注を確定します。

Sagaパターンによるコレオグラフィ

Sagaパターンのコレオグラフィでは、各サービスは他のサービスのイベントを生成したり待ち受けたりして、処理するべきかどうかを決定します。コレオグラフィは、各サービスが単一のローカルトランザクションになります。 最初のトランザクションは、システム操作に対応する外部要求によって開始され、その後の各ステップは、前のトランザクションの完了によってトリガーされます。

ユーザの注文を受注する簡単なシーケンス

  1. コーディネーター(受注サービス、Sagaオーケストレーター)は、注文のリクエストを受けると受注データ作成のトランザクションを開始し、受注データを仮登録します。
  2. コーディネーターは在庫サービスに注文イベントを送信します。
  3. 在庫サービスは注文イベントを待ち受け、在庫を更新し、引当完了のイベントを送信します。
  4. 顧客サービスは引当完了のイベントを待ち受け、決済を処理し、決済完了のイベントを送信します。
  5. コーディネータは決済完了のイベントを待ち受け、受注を確定します。

なお、注文の状態を追跡する必要がある場合、受注サービスはすべてのイベントを監視してその状態を更新する場合があります。

Sagaパターンのロールバック

例えば、取引中に決済が失敗した場合は、処理を取り消すためのイベントを発行してロールバックを図ります。

Sagaパターンのロールバック

  1. 顧客サービスは 決済エラーのイベントを送信します。
  2. 受注サービスと在庫サービスの両方が決済エラーのイベントを待ち受けます。
    • 在庫サービスは引当済みの在庫を取り消します。
    • 受注サービスは、受注の状態を失敗として更新します。

イベントを受信するすべての消費者(Consumer)が参照するトランザクションをすぐに知ることができるように、発生するイベントに各トランザクションに共通の識別子を定義することが重要になります。

Sagaパターンを実装する際の留意点

Sagaパターンによる処理は、イベントを消費(Consume)することが起点となり、別のイベントを発行(Publish)することで、次のサービスに処理が伝搬されます。一連の処理はこれをチェーンし、最後の処理が一番最初の処理に完了イベントをPublishして終了します。Publishするイベントは、リトライを考慮し、各サービスが管理するデータベースにも保持します。

【出展】

https://www.nginx.com/blog/event-driven-data-management-microservices/

Sagaパターンはサービス間は疎結合で柔軟であり、ビジネスロジックへの影響が局所化される点では、TCCパターンよりも優れていると言えます。一方で、補償トランザクションの実現可能性を考慮する必要があり、チェーンが長くなり過ぎないよう注意が必要です。

まとめ

今回は、TCCパターンとSagaパターンという、なかなか聞き慣れないアーキテクチャに触れてみました。いかがだったでしょうか?一部の先進的な企業から情報が発信されつつありますが、まだこれらパターンの導入事例は少なく、まだ普及段階ではないかもしれません。

昨今はKubernetesによるコンテナオーケストレーションやistioなどによるサービスメッシュが普及してきており、マイクロサービスアーキテクチャの導入が比較的容易になりつつありますが、それら技術はトランザクション制御を容易にするものではありません。マイクロサービスアーキテクチャの実現に向けては、引き続きトランザクションには十分な考慮が必要になるでしょう。

わかっち

特に基幹システムのマイクロサービス化に向けては、トランザクション制御が極めて重要になるよ

本記事が、マイクロサービス導入に向けて少しでもお役に立てれば幸いです。

最後までお読みいただき、ありがとうございました!

WordPressでブログを始めるならXserver

取り急ぎブログを始めるなら、レンタルサーバでWordPressを構築することをおすすめします。
サーバの構築が不要のため、レンタルサーバを契約後すぐにWordPressでブログを始められます。

そしてレンタルサーバは、国内シェアNo.1、サーバ速度No.1のXserverがおすすめです!


ドメイン取得ならXserver Domain国内最安値!取得も更新も!ドメイン名取得サービス
未経験から初めてのプラグラミングで副業Web制作を勉強・学習して短期間でWeb制作の副業ができるようになる講座。Web制作副業のお仕事を必ずGET!