先ほど、InfinispanのEmbedded Modeでクラスタを構成してみましたが、今度はInfinispanのServer Moduleでクラスタを構成してみます。
Infinispan Serverでクラスタを組む際でも、選択するCacheのモードはEmbeddedと同じくReplicated Mode、Distribution Mode、Invalidation Mode、そしてLocal Modeになります。
ただ、それはInfinispan Server間で構成するクラスタの話であって、そのクラスタにアクセスする際のクライアントはまた別の話になります。
以前紹介した通り、Infinispan Serverへのアクセス方法はHot Rod、Memcached、REST、WebSocketがありますが、今回はHot Rodを使ってクラスタにアクセスしてみます。
Infinispan Serverのダウンロードと展開
Infinispan Serverは、こちらからダウンロードします。
http://infinispan.org/download/
今回は、Infinspan Server 7.0.2.Finalを使用します。
ダウンロードしたら、unzipしましょう。
$ unzip infinispan-server-7.0.2.Final-bin.zip
今回は、Infinispan Serverを3つ起動しようと思うので、展開されたInfinispan Serverをコピーして3つにします。
$ cp -Rp infinispan-server-7.0.2.Final infinispan-server-7.0.2.Final-2 $ cp -Rp infinispan-server-7.0.2.Final infinispan-server-7.0.2.Final-3
というわけで、今回はInfinispan Serverを3つのNodeでクラスタを構成します。
クラスタの構成自体はそれほど手を加えず、デフォルトで登録されているこちらのCacheを使用することにします。
*infinispan-server-7.0.2.Final/standalone/configuration/clustered.xmlより抜粋
<distributed-cache name="namedCache" mode="SYNC" start="EAGER"/>
Distributed Cacheですね。
サーバの起動
展開したサーバを、それぞれ起動していきます。単純に起動してしまうと、Node名およびポートが衝突してしまうので、起動パラメータで調整します。
# Node 1 $ infinispan-server-7.0.2.Final/bin/clustered.sh -Djboss.node.name=node1 # Node 2 $ infinispan-server-7.0.2.Final/bin/clustered.sh -Djboss.node.name=node2 -Djboss.socket.binding.port-offset=1000 # Node 3 $ infinispan-server-7.0.2.Final/bin/clustered.sh -Djboss.node.name=node3 -Djboss.socket.binding.port-offset=2000
ポートは、2番目のNode以降1000ずつずらしています。
この結果、リッスンポートはそれぞれ11211、12211、13222となります。
クライアント側の準備
それでは、クライアント側のプログラムを作成するための準備をします。
Hot Rodを使うので、依存関係のinfinispan-client-hotrodを追加します。
build.sbt
name := "remote-clustered-starter" version := "0.0.1-SNAPSHOT" scalaVersion := "2.11.4" organization := "org.littlewings" scalacOptions ++= Seq("-Xlint", "-deprecation", "-unchecked", "-feature") incOptions := incOptions.value.withNameHashing(true) updateOptions := updateOptions.value.withCachedResolution(true) libraryDependencies ++= Seq( "org.infinispan" % "infinispan-client-hotrod" % "7.0.2.Final", "net.jcip" % "jcip-annotations" % "1.0" % "provided" )
クライアントプログラム
プログラム自体は、Embedded Modeの時と近いものになります。
src/main/scala/org/littlewings/infinispan/remote/RemoteCacheClusteringDemo.scala
package org.littlewings.infinispan.remote import scala.collection.JavaConverters._ import scala.io.StdIn import org.infinispan.client.hotrod.RemoteCacheManager import org.infinispan.client.hotrod.configuration.ConfigurationBuilder object RemoteCacheClusteringDemo { def main(args: Array[String]): Unit = { val manager = new RemoteCacheManager(new ConfigurationBuilder() .addServers("localhost:11222;localhost:12222;localhsot:13222") .build) val cache = manager.getCache[String, String]("namedCache") Iterator .continually(StdIn.readLine("> ")) .withFilter(l => l != null && !l.isEmpty) .takeWhile(_ != "exit") .map(_.split(" +").toList) .foreach { case Nil => case "put" :: key :: value :: Nil => cache.put(key, value) println(s"Putted, $key : $value") case "get" :: key :: Nil => println(s"Get, Key[$key] => ${cache.get(key)}") case "size" :: Nil => println(s"Size = ${cache.size}") case "keys" :: Nil => println(s"Keys:") cache.keySet.asScala.foreach(k => println(s" $k")) case command => println(s"Unknown command, [${command(0)}]") } cache.stop() manager.stop() } }
少々違う点として、RemoteCacheManagerを使うというところはありますが、接続先をあらかじめ与えておくところが特徴です。
val manager = new RemoteCacheManager(new ConfigurationBuilder() .addServers("localhost:11222;localhost:12222;localhsot:13222") .build)
ひとつひとつホストとポートを追加するメソッドもあるのですが、このように「;」で区切って一括で指定することも可能です。
インタラクティブにコマンドを実行する部分については、Embedded Modeと大差ありませんが「locate」については削除しています。通常のAPIの範囲では、わからない感じがしたので。
*内部APIを引きずり出せば可能っぽいですが…
では、実行してみます。
> run
起動時に、3つ接続先があることがわかっているようです。
INFO: ISPN004006: localhost/127.0.0.1:11222 sent new topology view (id=4) containing 3 addresses: [/127.0.0.1:11222, /127.0.0.1:13222, /127.0.0.1:12222]
データの登録。
> put key1 value1 Putted, key1 : value1 > put key2 value2 Putted, key2 : value2 > put key3 value3 Putted, key3 : value3 > put key4 value4 Putted, key4 : value4 > put key5 value5 Putted, key5 : value5
取得。
> get key3 Get, Key[key3] => value3
エントリ数の取得。
> size Size = 5
キーの取得。
> keys
Keys:
key1
key2
key5
key3
key4
Nodeを落としてみる
では、ここでサーバ側のNodeを落としてみましょう。
とりあえず、Ctr-cでNode 1、Node 2の順に停止してみます。この時、各Nodeを停止する間隔を詰めすぎると、リバランスが間に合わずにロストするデータが出てきます。
Node 3側では、自Nodeだけになっていることがわかります。
23:10:33,012 INFO [org.infinispan.remoting.transport.jgroups.JGroupsTransport] (OOB-72,shared=udp) ISPN000094: Received new cluster view for channel clustered: [node2/clustered|3] (2) [node2/clustered, node3/clustered] 23:10:59,397 INFO [org.infinispan.remoting.transport.jgroups.JGroupsTransport] (Incoming-5,shared=udp) ISPN000094: Received new cluster view for channel clustered: [node3/clustered|4] (1) [node3/clustered]
クライアント側で、キーを取得してみます。
> keys Keys: 12 05, 2014 11:11:47 午後 org.infinispan.client.hotrod.impl.protocol.Codec20 readNewTopologyAndHash INFO: ISPN004006: /127.0.0.1:13222 sent new topology view (id=10) containing 1 addresses: [/127.0.0.1:13222] 12 05, 2014 11:11:47 午後 org.infinispan.client.hotrod.impl.transport.tcp.TcpTransportFactory updateServers INFO: ISPN004016: Server not in cluster anymore(/127.0.0.1:11222), removing from the pool. 12 05, 2014 11:11:47 午後 org.infinispan.client.hotrod.impl.transport.tcp.TcpTransportFactory updateServers INFO: ISPN004016: Server not in cluster anymore(/127.0.0.1:12222), removing from the pool. key1 key2 key5 key3 key4
この時、クラスタの2つのNodeがいなくなったことを検知して、接続先から削除されるようです。また、エントリがなくなっていないこともわかります。
さすがに、全部落としちゃうとクライアント側もエラーになりますが。
> keys 〜省略〜 ERROR: ISPN004007: Exception encountered. Retry 10 out of 10 org.infinispan.client.hotrod.exceptions.TransportException:: Could not fetch transport
接続先は、あらかじめ列挙する必要がある?
最初のプログラムでは、このようにあらかじめ接続先をすべて列挙していました。
new RemoteCacheManager(new ConfigurationBuilder() .addServers("localhost:11222;localhost:12222;localhsot:13222") .build)
ですが、実際のところは先ほどNodeをダウンさせた時に検出されたことからもわかるように、すべてを列挙する必要はなかったりします。
new RemoteCacheManager(new ConfigurationBuilder() // .addServers("localhost:11222;localhost:12222;localhsot:13222") .addServers("localhost:11222") // これでもOK .build)
起動時、アクセス時に、クラスタに参加しているNode群を検出してくれます。
INFO: ISPN004006: localhost/127.0.0.1:11222 sent new topology view (id=4) containing 3 addresses: [/127.0.0.1:13222, /127.0.0.1:11222, /127.0.0.1:12222]
あくまで初期値ということですね。無効なNodeが書かれていた場合は、即刻削除されますが。
このため、途中でNodeが増えたりしてもちゃんとクライアント側で認識してくれます。良いですね!
今回作成したソースコードは、こちらに置いています。
https://github.com/kazuhira-r/infinispan-getting-started/tree/master/remote-clustered-starter