そんなトランザクションマネージャで大丈夫か?

37
そんなトランザクション マネージャで大丈夫か? @takezoen BizReach,Inc.

Upload: takezoe

Post on 25-May-2015

9.599 views

Category:

Software


0 download

TRANSCRIPT

そんなトランザクションマネージャで大丈夫か?

@takezoenBizReach,Inc.

JTA、使っていますよね?

● JavaEEサーバ● Seasar2● Spring Framework

トランザクションマネージャの役割

● 複数のリソースを1つのトランザクションで処理する

● トランザクションに参加するリソースの整合性を保証する

たとえば...

● 複数のDBに対する処理● DBに対する処理とJMSによるメッセージ送信

DB DB

プログラム

DB MQ

プログラム

参照・更新メッセージ送信・受信参照・更新 参照・更新

1トランザクションで処理する

以下のどちらかであることを保証する

● すべてのリソースがコミットされる● すべてのリソースがロールバックされる

どうやって保証しているのか?

2フェーズコミット

リソース1 リソース2トランザクションマネージャ

プログラム

commit

prepare?

commit

prepare?

commit

2フェーズコミット

● 全てのリソースがprepareに対してOKを返した場合のみcommitする

● どれか1つでもprepareに対してNGを返した場合は全てのリソースをrollbackする

2フェーズコミット

● XADataSourceが必要● XADataSourceの実装はJDBCドライバによっ

て提供される● 非XAリソースをラップしてエミュレーションする

機能を持っている場合もある

XAトランザクションのSQL(MySQLの場合)

mysql> XA START 'xatest';Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO account VALUES(1, 'takezoe');Query OK, 1 row affected (0.04 sec)

mysql> XA END 'xatest';Query OK, 0 rows affected (0.00 sec)

mysql> XA PREPARE 'xatest';Query OK, 0 rows affected (0.00 sec)

mysql> XA COMMIT 'xatest';Query OK, 0 rows affected (0.00 sec)

様々な最適化

● リソースが1つの場合は1フェーズでcommitする● 最後のリソースはprepareせずにcommitする● 非XAリソースでも1つだけならJTAトランザク

ションに参加可能

めでたしめでたし

ちょっと待った!!

ここからが本題です

途中で落ちたらどうなるの?

不整合が発生してしまう

● リソース側にトランザクションが残ってしまう● 一部のリソースだけがコミットされた状態になっ

てしまう

リカバリマネージャ

● トランザクションマネージャはトランザクションの状態をトランザクションログに出力している

● リカバリマネージャはトランザクションログを見て不正なトランザクションを自動的にリカバリする

リカバリマネージャ

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

リカバリマネージャ

トランザクションログ

トランザクションの状態を書き込み

残ってしまっているトランザクションがないか

定期的にチェック

残ってしまっているトランザクションを検出した場合はリカバリを実行

誤検出しないよう、トランザクションマネージャの管理下になく、かつ一定時間ステータスが変わっていないもの、というようなチェックを行っている

トランザクションのリカバリとは?

● リソース側に残っているトランザクションをrollbackまたはcommitのどちらかに倒す

● 基本的には安全サイド(rollback)に倒す● すでに1つでもリソースをcommitしてしまってい

る場合は全部commitする

どこで落ちたかでリカバリ方法が異なる

リソース1 リソース2トランザクションマネージャ

プログラム

commit

prepare?

commit

prepare?

commit

ここで落ちた場合は両方rollbackする

ここで落ちた場合はリソース2をcommitする

リカバリマネージャがあれば安心

リカバリマネージャがあれば安心

ではありません

リカバリマネージャではリカバリできないケースがあります

トランザクションログが壊れた場合ヽ(‘ ∇‘ )ノ

● リソースに対する操作を行ってからトランザクションログを書き込み前に死んだ場合

● トランザクションログのファイル書き込み中に死んだ場合

リソース側に残ってしまったトランザクションを手動でcommitまたは

rollbackする必要があります

手動リカバリ(MySQLの場合)mysql> XA RECOVER;+----------+--------------+--------------+--------+| formatID | gtrid_length | bqual_length | data |+----------+--------------+--------------+--------+| 1 | 6 | 0 | xatest |+----------+--------------+--------------+--------+

1 row in set (0.00 sec)

mysql> XA ROLLBACK 'xatest';Query OK, 0 rows affected (0.00 sec)

mysql> XA RECOVER;Empty set (0.00 sec)

XAトランザクションが残ってしまっている

他のリソースの状態をトランザクションIDで突き合せてcommitするべきかrollbackするべきか判断し、トランザクションをリカバリする

残ってしまっていたXAトランザクションが消えた

めでたしめでたし

ちょっと待った!!

Seasar2やSpringを使っている場合

Seasar2

● トランザクションログを書いていない● もちろん自動リカバリ機能もない

Seasar2

● なんちゃってXADataSource<component name="xaDataSource" class="org.seasar.extension.dbcp.impl.XADataSourceImpl"> <property name="driverClassName">"oracle.jdbc.driver.OracleDriver"</property> <property name="URL">"jdbc:oracle:thin:@xxx:1521:yyy"</property> <property name="user">"aaa"</property> <property name="password">"bbb"</property></component>

Seasar2のサンプルなどにはこういった設定例が紹介されているが、これはSeasar2側で用意しているXADataSourceのなんちゃって実装で、通常の java.sql.ConnectionをラップしてXAの動作をエミュレートするもの。

Seasar2● 2フェーズコミットを行うのであればJDBCドライバが提供し

ているXADataSourceの実装を使うべき○ com.mysql.jdbc.jdbc2.optional.MysqlXADataSource○ org.postgresql.xa.PGXADataSource

<component name="xaDataSource" class="org.postgresql.xa.PGXADataSource"> <property name="serverName">"localhost"</property>

<property name="databaseName">"TEST"</property><property name="user">"xxxx"</property><property name="password">"xxxx"</property>

</component>

Spring Framework

● 自前ではJTA対応のトランザクションマネージャの実装は持っていない

● JTA対応のトランザクションマネージャをSpring上で使用するためのアダプタが用意されている

● 2フェーズコミットを使用するにはJavaEEサーバもしくはスタンドアロンのJTA実装と組み合わせて使用する必要がある

2フェーズコミットを行う場合はAPサーバのトランザクションマネージャを

使ったほうが安全です

まとめ

まとめ

● 2フェーズコミットを行う場合、手動でのリカバリが必要になるケースが存在するということを意識しておきましょう

● 2フェーズコミットを行う場合はなるべくJavaEEサーバのトランザクションマネージャを使うことをおすすめします

● そもそも2フェーズコミットを行わなくても済むのであればそのほうがよいです

● 分散トランザクションはさらに危険がいっぱいなので近づかないようにしましょうw

おわり