2フェーズコミット

1. はじめに

ASTERIAではDBMSの2フェーズコミットをサポートしています。フローでデータベースの2フェーズコミットを使用するには、RDBコネクションの設定で「XA対応」プロパティを「はい」にします。これだけで使用を開始することができますが、2フェーズコミットでの正しい運用設計が無いと障害発生時に回復に時間がかかったり回復可能なデータを失ったりする可能性があります。

今回は、運用設計の参考として2フェーズコミットそのものについて解説し、ASTERIAでの実装について説明します。

2. 2フェーズコミットとは

2フェーズコミットとは、複数のデータベースに対する更新処理において相互のデータ整合性を確保しながらトランザクションを実行する手法のことです。

commitの前にprepareという手順を入れることによって、複数データベース更新時にそのうちのひとつだけがcommitされて他がrollbackされるといったような不整合が発生することを防ぎます。

2.1. 2フェーズコミットの手順

まず1フェーズコミットと2フェーズコミットのcommit時の手順の違いを簡略化した図に示します。

図1 1フェーズコミット(フローの場合RDBコネクションの「XA対応」が「いいえ」)
1フェーズコミット(フローの場合RDBコネクションの「XA対応=false」)

 

図2 2フェーズコミット(フローの場合RDBコネクションの「XA対応」が「はい」)

 

2フェーズコミット(フローの場合RDBコネクションの「XA対応=true」)

 

図2のように2フェーズコミットの場合はcommitを発行する前にそれぞれのDBMSに対してprepareを発行します。そしてすべてのDBMSに対するprepareが成功した場合にのみcommitが発行されます。

このように1フェーズコミットと2フェーズコミットの手順の違いはcommitの前にprepareが入るかどうかです。処理の途中で障害が発生したケースを考えてみると、1フェーズコミットではDBMS1のcommitを行った後にDBMS2の障害が発覚する、つまりDBMS2のcommitが行えずにデータの不整合が発生する可能性があるのに対し、2フェーズコミットではcommitの前にDBMS1、DBMS2の双方に対してprepareが発行されているのでその時点でどちらのDBMSにも問題がないことが確認されています。commitはprepareの直後、ほとんど時間をおかずに連続して行われるのでその間に障害が発生する可能性は極めて低く、データ整合性の保証度合が向上します。

メモ

ユニーク制約違反やデータ長違反などの更新SQLの実行でエラーが発生した場合は、その時点ですべてのDBMSに対してrollbackが発行されるので1フェーズコミットの場合でも2フェーズコミットの場合でも処理内容に違いはありません。

つまり、通常のSQLの実行で発生しうるエラーに対しては1フェーズコミットでも十分に対処可能です。2フェーズコミットに優位があるのは主にネットワーク障害やハードウェア障害などの不測の事態に対してです。

この生存確認の機能だけでも2フェーズコミットの信頼性は1フェーズコミットに比べてはるかに高いと言えます。しかし、これだけではデータ不整合の発生する可能性を減らしてはいても依然としてそれが発生する可能性は残ります。prepareには生存確認以上の重要な機能があり、その機能によって万が一の障害発生時のデータ不整合の回避と回復が担保されています。次節ではprepareの重要な役割を説明します。

2.2. prepareの役割

DBMSの生存確認以外のprepareの重要な機能、それはprepareを発行するとトランザクション情報がディスクに保存され、再接続後に処理を再開できるという点です。これによって1フェーズコミットと2フェーズコミットの処理において、先の図では表現されなかった次のような大きな違いが生まれます。

  • 2フェーズコミットでは、prepare後にセッションが切れてもトランザクション情報はディスクに保存されているので、再接続後にトランザクションの継続(commitまたはrollback)が可能。
    1フェーズコミットでは、セッションが切れた場合はそのトランザクションはそれ以上の続行が不可能。
  • prepareによって保存されたトランザクション情報はDBMSをシャットダウンしても保持されるので、DBMS再起動後に再接続してトランザクションを継続することも可能。

つまり、ネットワークやアプリケーションに一時的な障害が発生してトランザクションが中断してしまった場合、あるいはDBMSサーバーに突然の電源断やディスク容量不足のような物理的な障害が発生した場合でも、2フェーズコミットであれば復旧後にトランザクションの整合性を回復させることができます。

ASTERIAでの2フェーズコミットはこうした障害の際にも複数のDBMS間の整合性を維持したリカバリーを自動的に行います。

2.3. XAとは

冒頭で、ASTERIAで2フェーズコミットを行うにはRDBコネクションの「XA対応」プロパティを「はい」にすると説明しました。この「XA」とは、2フェーズコミットを行うための仕様(インターフェース)を定めたものです。概念的には「JDBC」や「JMS」などと同レベルの用語となります。

JDBC対応のデータベースであればJavaからDBMSの種別を意識せずにJDBCインターフェースを介してプログラミングを行うことができるのと同様に、XA対応のデータベースであればXAインターフェースを介してDBMSの種別を意識せずにプログラミングを行うことができます。

ただしASTERIAではDBMSがXAをサポートしていてもASTERIA側での対応が行われていないものはXAを使用することができません。(RDBコネクションの編集で「XA対応」プロパティで「はい」として保存しようとしてもエラーになります。)

ASTERIA WARP 4.5.1以降においてXA対応が行われているDBMSは以下の通りです。

  • Oracle9以降(thinドライバのみ)
  • SQLServer2000以降
  • DB2 9以降(type2ドライバのみ)
  • MySQL 5.0以降
  • PostgreSQL 8.2以降

メモ

今回の説明では触れていませんがXAではトランザクション開始時の処理手順についても定められています。

厳密にはトランザクション開始時にトランザクションID(Xid)が取得され、以降のトランザクションはトランザクションIDによって管理されます。再接続もトランザクションIDを元に行われます。

3. ASTERIAにおけるリカバリー処理

ここでは、ASTERIAにおけるリカバリー処理を説明します。

ASTERIAでは、リカバリー処理はトランザクションマネージャーとリカバリーマネージャーによって管理されています。

3.1. トランザクションマネージャー

トランザクションマネージャーは、フローにおけるトランザクション処理全体を管理し、トランザクションを適切にcommitまたはrollbackすることが主な役割です。2フェーズコミット使用時にトランザクション処理のエラーを検知すると、そのトランザクションをリカバリーマネージャーに渡します。1フェーズコミットの場合はこのリカバリー処理が発生することはありません。

2フェーズコミットと1フェーズコミットの処理の違いはすべてトランザクションマネージャーが吸収するので、フロー作成者やコンポーネント開発者はフロー実行時にどちらのトランザクションが使用されるかについて意識する必要はありません。

内部的には2フェーズコミットの場合はトランザクションの状態が逐次ファイルに保存され、リカバリー処理ははそれを元に行われます。

トランザクションマネージャーについては、フローサービスマニュアルのトランザクションも併せて参照してください。

3.2. リカバリーマネージャー

リカバリーマネージャーは2フェーズコミット使用時に必要となったリカバリー処理を実行します。フロー内で実行されるトランザクションがすべて1フェーズコミットの場合、リカバリーマネージャーは何もしません。

リカバリー処理が必要となるのは障害発生時のみなので、リカバリーマネージャーが仕事をすることはほとんどありません。

3.3. トランザクションの動作

次に、フローの実行中にどのようなエラーや障害が発生したかによって、1フェーズコミットと2フェーズコミットのトランザクションの動作がどうなるのかを説明します。

3.3.1. フローが正常に終了した場合

トランザクションが正常に終了した場合、つまりすべてのDBMSに対するcommitに成功した場合は、リカバリー処理が必要ないため1フェーズコミットと2フェーズコミットの動作に差異はありません。

3.3.2. フロー内の処理がエラーとなった場合

フロー内でRDBPutコンポーネントやSQLCallコンポーネントによる更新SQLの実行がエラーとなった場合、例えばInsert処理におけるキー違反などが起きた場合は、それ以前に実行されたすべてのDBMSに対する更新がrollbackされて終了するのでトランザクション処理のリカバリーは必要ありません。FileGetコンポーネントでファイルが見つからないなど、DBMSの処理以外でエラーとなった場合も同様です。

この場合も1フェーズコミットと2フェーズコミットの動作に差異はありません。つまり通常範囲で起こりえるほとんどのエラーケースではリカバリー処理は不要であり、1フェーズコミットと2フェーズコミットのどちらのトランザクションを使用した場合でも結果は同じです。

3.3.3. ネットワーク障害、またはDBMS障害が発生した場合

フローの実行途中でネットワーク障害またはDBMSの障害が発生した場合は、ASTERIAサーバーとDBMSの間の通信処理においてエラーが発生することになります。この場合はリカバリー処理が必要です。こうした障害は図2のシーケンス図における「更新SQL発行」「prepare」「commit」いずれのタイミングでも発生する可能性があります。先にも述べたとおり「更新SQL発行」でエラーとなっただけであればリカバリーの対象とはなりませんが、このケースではそれに続くrollbackの実行もDBMSと通信できずにエラーとなります。

1フェーズコミットの場合、それ以上処理が継続できないので、そこでトランザクションが破棄されます。したがって、1つのDBMSに対してcommitを発行した後に障害が発生した場合はそこでデータ不整合が発生することになります。

2フェーズコミットの場合、トランザクションはそこでリカバリーマネージャーに渡され、リカバリーマネージャーによって適切にリカバリー処理が行われます。リカバリー処理の詳細については「3.4.リカバリーの実行」で説明します。

ネットワーク障害の場合は障害発生以降のすべての通信がエラーとなるので、すべてのDBMSに対するトランザクションがリカバリー対象となりますが、DBMS障害の場合はエラーとなったDBMSへのトランザクションのみがリカバリー対象となります。

例えばDBMS1、DBMS2、DBMS3の3つのDBMSへの更新を行っていて処理途中にDBMS2に障害が発生した場合はDBMS1、DBMS3に対するトランザクションはrollbackされ、DBMS2のみがリカバリーマネージャーに渡されます。

図3 リカバリーが必要な障害の例
リカバリーが必要な障害の例

 

3.3.4. ASTERIAの障害の場合

フローの実行途中になんらかの理由によりASTERIAサーバーが異常終了する場合があります。

1フェーズコミットの場合、この場合の動作は不定です。ASTERIA側で実行可能なリカバリー処理は何もないので、DBMS側で不正となったセッションを強制終了するなどの操作が必要になることがあります。 DBMSによってはこのリカバリー処理を自動で行ってくれることもありますが、通常は手動でのリカバリー操作が必要です。

2フェーズコミットの場合は処理途中で中断されたトランザクション情報を保存したファイルが残っているので、ASTERIAサーバー再起動時にリカバリーが自動的に実行されます。

3.4. リカバリーの実行

リカバリーマネージャーでリカバリー処理が実行されるタイミングと処理内容は以下の通りです。

トランザクションマネージャーからリカバリー処理が渡された場合

フローサービス管理コンソールの「設定」-「サービス」-「フロー」-「フローエンジン」画面の「リカバリーインターバル」で指定した秒数が経過した後、リカバリー処理が実行されます。リカバリー処理に失敗した場合は「リカバリーリトライ回数」に達するまで間隔を置いて再試行されます。

中断されたトランザクションが残っている場合

フロー実行中にASTERIAサーバーが異常終了した場合や、リトライ待機中のトランザクションが残っていた場合はASTERIAサーバーの起動時にリカバリー処理が実行されます。この場合リカバリー処理が実行されるのは1度だけでリトライは実行されません。

リカバリーに成功した場合や既定の回数のリトライを行っても成功しなかった場合はフローサービス管理コンソールの「リカバリーのメール通知」の設定によってメール通知されます。リカバリーが実行された場合は詳細な実行内容がFlowService.logに出力されます。

メモ

リカバリー処理とは通常は再接続後のrollbackですが、他のDBMSへのcommitが成功した後に障害が発生した場合は整合性を維持するためにcommitが実行されます。

場合によっては再接続時にはDBMS側で何らかのリカバリー処理が行われていてASTERIA側でのリカバリー処理が不要になり、実行できないことがあります。その場合はリカバリーが成功したとみなして処理を完了します。

3.5. 手動でのリカバリー

障害が早期に回復した場合は上記のリカバリーマネージャーによって自動的にトランザクションがリカバリーされることが期待できます。しかし、既定回数のリトライ実行終了までに障害から回復しなかった場合は手動でのリカバリーが必要な場合があります。

このような場合は、DBMS側での調査や作業となるため、DBMSに付属する管理ツールを用いてリカバリー処理を行うことが多いですが、flow-ctrlのxaコマンドを用いてリカバリーを実行することも可能です。

xaコマンドはJavaのXAインターフェースの実装クラスであるXAResourceのメソッドを直接実行するコマンドです。

以下にXAResourceのメソッド実行によるトランザクションの状態遷移を示します。

図4 トランザクションの状態遷移
XAResource2.png

 

xaコマンドではstart以外のメソッドを発行することができます。recoverメソッドでトランザクション一覧を取得し、それからトランザクションIDを指定して他のメソッドを発行することが可能です。

xaコマンドで、ASTERIA以外のアプリケーションが実行中のトランザクションに対して、コマンドを発行しないでください。

トランザクションがASTERIAサーバーによって実行されているものであるかどうかはlist transactionコマンドやshow transactionコマンドで確認できます。

4. DBMS固有のトピック

各DBMSベンダーのXAインターフェースの実装はそれぞれのベンダーが配布するJDBCドライバに含まれています。現状ではXAの実装はJDBCほど安定していないので、2フェーズコミットを使用する場合はできるだけ新しいバージョンのJDBCドライバを使用することをお勧めします。

以下にいくつかのDBMSに固有のトピックを記載しますが、これらは保証された内容ではありません。

マイナーバージョンやサービスパック(パッチ)の差によっても動作が異なることがあるので使用の際には必ず製品のマニュアルを参照してください。

SQLServer 2000以降

SQLServerには標準ではサーバー側にXA用のモジュールがインストールされていません。XA用のモジュールはストアドプロシージャとして提供されているのでインストールするためには管理ツール等からスクリプトを実行する必要があります。

Oracle 9i以降(thinドライバのみ)

Oracle9i、10gではXAインターフェースのrecoverコマンドを実行するためには以下の権限付与が必要です。

grant select on dba_pending_transactions to user;
grant execute on dba_system to user;

recoverコマンドが使用できずともASTERIAにおける2フェーズコミット、およびそのリカバリー処理は実行可能なので上記grant文の実行は必須ではありませんが、リカバリー処理実行時に警告が出力されるので可能であれば実行しておくことをお勧めします。

DB2 9以降(type2ドライバのみ)
ASTERIAのDB2での2フェーズコミットはJDBCのAppドライバを使用する場合のみサポートしています。Thinドライバではサポートされていません。
この記事は役に立ちましたか?
0人中0人がこの記事が役に立ったと言っています
    キーワード:
  • フローサービス
  • 技術資料
他にご質問がございましたら、リクエストを送信してください

このセクションの記事

他のキーワードで検索する