1. ホーム
  2. データベース
  3. マイサク

MySQL XAが分散型トランザクションを実装する方法を1記事にまとめました。

2022-01-07 01:27:31

前書き

MySQL がスタンドアロン トランザクションをうまくサポートしていることは間違いありませんが、では、複数のノードが関与する分散システムにおいて MySQL はどのように分散トランザクションを実装しているのでしょうか。例えば、外部からのリクエストを受け付け、そのリクエストを実行するために他の複数の内部システムにアクセスするビジネスシステムが開発されたとします。実行時には複数のデータベース(D1,D2,D3)の値を同時に更新する必要があります。このとき、システムは整合性のある状態、つまり3つのデータベースの値が同時に正常に更新されるか、全く更新されないかのどちらかでなければならないので、D1,D2,D3の値を同時に更新する必要がある。そうでないと、サブシステムにおいて、ある命令は成功し、ある命令はまだ実行されていないという結果になる。これは、結果の理解に混乱を招く。

では、MySQLはどのようにして、複数のMySQLデータベース間で更新の一貫性を実現しているのでしょうか。それが MySQL XA であり、XA 仕様の 2 フェーズコミットプロトコルをサポートすることで MySQL は複数のデータベースの運用を可能にしているのです。

XAプロトコル

XA仕様は、DTPモデルの2つのモジュール、トランザクションマネージャとリソースマネージャの通信方法に関する規約である。


各モジュールの役割は以下の通りです。

  • AP(Application Program)。トランザクションの境界を定義し(トランザクションの開始と終了を定義し)、トランザクションの境界内のリソースにアクセスするアプリケーション。
  • RM (Resource Manger) リソースマネージャー:共有リソースを管理し、外部アクセスインタフェースを提供する。外部プログラムがデータベースなどの共有リソースにアクセスする際に使用される。また、RMはトランザクションをロールバックする機能を持つ。
  • TM(Transaction Manager)トランザクション・マネージャー。TMは、分散トランザクションのオーケストレーターです。各RMと通信し、グローバルトランザクションの管理、トランザクション固有識別子の割り当て、トランザクション実行状況の監視、トランザクションのコミット、ロールバック、障害回復などを担当する。

一見すると分かりにくいが、アーキテクチャを要約すると、アプリケーションはリソースマネージャが提供する共有リソースにアクセスして利用し、トランザクションマネージャが提供するトランザクションインタフェース(TXインタフェース)を通じて、トランザクション操作を定義する。トランザクションマネージャとリソース管理は、XA仕様に基づく2相コミットプロトコルを強制的に実行する。
XA仕様のフローを下図に示す。

  • アプリケーションAPは、トランザクションマネージャTMに対してトランザクション要求を開始する。
  • TMはxa_open()を呼び出し、リソースマネージャとのセッションを確立します。
  • TMはxa_start()を呼び出して、トランザクションブランチの開始をマークする。
  • APはリソースマネージャRMにアクセスし、レコードの挿入操作などのアクションを定義する
  • TMはトランザクションブランチの終了を示すためにxa_end()を呼び出す。
  • TMはxa_prepare()を呼び出し、RMにトランザクションブランチのコミット準備ができたことを通知します。これは実際には、2相コミットのコミット要求フェーズです。
  • TMはxa_commit()を呼び出して、RMにトランザクションブランチをコミットするよう通知する。これは2相コミットのコミット実行フェーズである。
  • TMはxa_closeを呼び出して、RMとのセッションを管理する。
    • これらのインターフェースは順番に実行されなければならず、例えば、xa_startインターフェースはxa_endの前に実行されなければならない。また、トランザクションマネージャはトランザクションの分岐をマークするだけで、トランザクションを実行しないことに注意することが重要である。トランザクション操作は、最終的にはアプリケーションがリソースマネージャに通知することによって行われる。また、XAインターフェイスを要約してみましょう。
  • xa_start: トランザクションブランチを開く、または再開する役割を担い、呼び出したスレッドにXIDを管理する。
  • xa_end: 現在のスレッドをトランザクションブランチから切り離す役割を果たす。
  • xa_prepare: トランザクションブランチをコミットする準備ができているかどうかをRMに問い合わせる担当 xa_commit: トランザクションブランチをコミットするようRMに通知する担当
  • xa_rollback: トランザクションブランチをロールバックするようRMに通知する。

MySQL XA による分散トランザクションの実装方法

MysqlのXAトランザクションには、主にストレージエンジンとバイナリログの調整に使用される内部XAトランザクションと、外部の分散トランザクション(複数のデータベースで実装される分散トランザクションなど)に参加できる外部トランザクションがあり、ここでは外部トランザクションを中心に解説します。

注:分散トランザクションは、MySQL では分離レベルが Serializable に設定されている場合のみ利用可能です。
MySQLのXA構文は次のとおりです。

XA {START|BEGIN} xid [JOIN|RESUME]
XA PREPARE xid
XA END xid
XA COMMIT xid [ONE PHASE]
XA ROLLBACK xid
XA RECOVER[CONVERT XID ]


ここで、xidはトランザクションブランチを一意に表すためのトランザクションIDとして使用され、各トランザクションブランチはidを持つ。
まず、XA機能が有効になっていることを確認します。


分離レベルをserializableに設定する


実行結果

まず "XA START 'xid'" コマンドを呼び出して XA トランザクションを ACTIVATE 状態にし、トランザクションを構成する複数の SQL 文を実行します(例: update
t1 set c1 = 'a' where id=1)、つまりトランザクションの境界を指定することである。次に "XA END 'xid'" を呼び出して、トランザクションを IDLE 状態にする、つまりトランザクションの境界を終了させます。

次に、IDLE 状態の XA トランザクションでは、"XA PREPARE" コマンドまたは "XA COMMIT...ONE PHASE" コマンドを実行すると、XA
PREPAREを使用して、2フェーズコミットプロトコルのコミット要求フェーズを実行します。XA RECOVER"コマンドを実行すると、PREPARED状態のすべてのXAトランザクションが一覧表示されます。
COMMIT...ONE PHASE は、トランザクションの準備とコミット、つまり 1 段階のプロトコルに変換して、トランザクションを直接コミットするために使用されます。

最後に、"XA COMMIT" を呼び出してトランザクションをコミットします(または "XA ROLLBACK" を呼び出してトランザクションをロールバックします)。これにより、グローバル・トランザクションの一貫性が保たれます。


上記のフローからわかるように、MySQLデータベースの分散トランザクションにおいて、MySQLの役割は実際にはXAトランザクションプロセスにおけるRMであり、TMはMySQLサーバに接続するクライアントである。通常、分散トランザクションには少なくとも2つのRMが関与しており、MySQLがXAプロトコルをサポートすると言うことは、RMとしてのmysqlについて話しているのであり、XAプロトコルにおいてRMが持つべき機能をMySQLが実装していることを意味しています。

MySQL XAで分散型トランザクションを実装する方法についての説明は以上です。MySQL XA による分散トランザクションの詳細については、Script House の過去の記事を検索するか、以下の記事を引き続き参照してください。