H2Databaseを追っかけていたりしたブログ

H2 database のリリースノートを読んだりとか。

H2のクラスタリングを試してみる。

H2では、簡単なクラスタリング機能を持っている。使い方もH2らしく非常に簡単。サーバ(ノード)は2台固定で、障害発生時の復旧は手動。参照系のクエリは1番目のノードに対してのみ実行され、その以外のステートメントは両方のノードに対して実行される(なので、パフォーマンス改善、という観点ではメリットはない)ランダムに値を生成する関数は、ノードごとに違う値が発生してしまうので注意が必要、との事なので、単純にSQLベースのクラスタリングの模様。

また、

When using the cluster modes, result sets are read fully in memory by the client, so that there is no problem if the server dies that executed the query. Result sets must fit in memory on the client side.

とのことなので、普通のサーバモードのH2に繋いだときと、クライアント側のメモリ消費量が変わるのかも。

とりあえず、どんな感じで動くのか試してみる。公式サイトにあるように、同一のサーバ上で、ポートを変えて試してみる。

まず始めに、2台のサーバを起動(embeddedではなく、サーバモードで起動する必要がある)

ノードA
 java -cp ~/bin/h2-1.2.132.jar org.h2.tools.Server -tcp -tcpPort 9101 -baseDir ~/work/baseA
 
 ノードB
 java -cp ~/bin/h2-1.2.132.jar org.h2.tools.Server -tcp -tcpPort 9102 -baseDir ~/work/baseB


で、CreateClusterする。今回、完全にまっさらな状態から始めているが、既にデータベースがある場合は、urlSource側が既存のデータベースを指定する。CreateClusterの中で、最初にurlSourceからurlTargetに対してコピーが実施され、同期がとれた状態でクラスタリングがスタートする。

 java -cp ~/bin/h2-1.2.132.jar org.h2.tools.CreateCluster -urlSource jdbc:h2:tcp://localhost:9101/testdb
  -urlTarget jdbc:h2:tcp://localhost:9102/testdb -user testUser -password testUser -serverList localhost:9101,localhost:9102


これだけで、クラスタリングさせることができる。接続してみる。

 java -cp ~/bin/h2-1.2.132.jar org.h2.tools.Shell -url jdbc:h2:tcp://localhost:9101,localhost:9102/testdb -user testUser -password testUser


接続する側は、urlに二つのサーバとポートを指定してやるだけで、別に普通と変わらない。

 create table hoge(id int not null primary key, txt varchar);
 insert into hoge values (1,'hogehoge');
 insert into hoge values (2,'hogehoge');


ここで、一つ目のサーバ(ノードA)をkillする。

 select * from hoge;
 insert into hoge values (3,'hogehoge');


特に変化なく使い続ける事ができる。

では、サーバを復旧させる。まず、落ちたサーバのベースディレクトリをまっさらにして(別に、新しいディレクトリをbaseDirとして指定するのでもいいのだけれど) 、起動する。

ノードA
 java -cp ~/bin/h2-1.2.132.jar org.h2.tools.Server -tcp -tcpPort 9101 -baseDir ~/work/baseA

起動したら、CreateClusterで、生き残っていた方を、urlSourceとして指定して実行する(最初に実行した時と、urlSource/urlTargetの指定が逆になっている。これで生き残っていた方と、まっさらの新しい方とが同期される)

 java -cp ~/bin/h2-1.2.132.jar org.h2.tools.CreateCluster -urlSource jdbc:h2:tcp://localhost:9102/testdb
  -urlTarget jdbc:h2:tcp://localhost:9101/testdb -user testUser -password testUser -serverList localhost:9101,localhost:9102

クライアントの方は、変わらず使い続ける事ができる。

 select * from hoge;

しかし、次にノードBをkillすると、以下のExceptionが発生する。

Error: org.h2.jdbc.JdbcSQLException: 接続が壊れています: "session closed"
Connection is broken: "session closed" [90067-132]

こうなると、接続し直す必要がある...が、現実的に、クラスタリングしていて、1台落ちて、復旧させて、そこからもう1台の方が落ちてというシチュエーションで、いったん接続し直さなければならないくらいは、許容できる範囲内だと思う。APサーバで使っていれば、自動で再接続もされるだろうし。ここらへんが許容できないシステムであれば、H2ではなく別のデータベースを選択するべき。