CLOVER🍀

That was when it all began.

InfinispanをRemote Serverとして使う

今までずっとEmbedded CacheでInfinispanを使っていましたが、そろそろInfinispanを単独で起動して、クライアントプログラムからInfinispanを使うことにトライしたいと思います。

まずは、Infinispanをダウンロード。
https://www.jboss.org/infinispan/downloads

いつの間にか、5.2.1.Finalが出ています…。

とりあえず、落としたZIPファイルを展開。

$ unzip infinispan-5.2.1.Final-all.zip
$ cd infinispan-5.2.1.Final-all
$ ll
合計 2492
drwxr-xr-x  8 xxxxx xxxxx    4096 Feb  8 16:50 ./
drwxrwxr-x  3 xxxxx xxxxx    4096 Feb 10 17:36 ../
-rw-r--r--  1 xxxxx xxxxx    1553 Feb  8 16:46 Copyright.txt
-rw-r--r--  1 xxxxx xxxxx    2213 Feb  8 16:46 README-Demo.txt
-rw-r--r--  1 xxxxx xxxxx    5409 Feb  8 16:49 README-EC2-demo.txt
-rw-r--r--  1 xxxxx xxxxx     537 Feb  8 16:46 README-Modules.txt
-rw-r--r--  1 xxxxx xxxxx    1618 Feb  8 16:49 README-NearCache-demo.txt
-rw-r--r--  1 xxxxx xxxxx    2416 Feb  8 16:49 README-distexec-demo.txt
-rw-r--r--  1 xxxxx xxxxx     966 Feb  8 16:46 README.txt
drwxr-xr-x  2 xxxxx xxxxx    4096 Feb  8 16:50 bin/
drwxr-xr-x  4 xxxxx xxxxx    4096 Feb  8 16:50 doc/
drwxr-xr-x  6 xxxxx xxxxx    4096 Feb  8 16:50 etc/
-rw-r--r--  1 xxxxx xxxxx 2471912 Feb  8 16:23 infinispan-core.jar
drwxr-xr-x  2 xxxxx xxxxx   12288 Feb  8 16:50 lib/
drwxr-xr-x  2 xxxxx xxxxx    4096 Feb  8 16:50 licenses/
drwxr-xr-x 17 xxxxx xxxxx    4096 Feb  8 16:50 modules/
-rw-r--r--  1 xxxxx xxxxx     395 Feb  8 16:23 runtime-classpath.txt

binディレクトリの中に、起動スクリプトがあります。

$ bin/startServer.sh --help
usage: startServer [options]

options:
    -h, --help                         Show this help message

    -V, --version                      Show version information

    --                                 Stop processing options

    -p, --port=<num>                   TCP port number to listen on (default: 11211 for Memcached, 11222 for Hot Rod and 8181 for WebSocket server)

    -l, --host=<host or ip>            Interface to listen on (default: 127.0.0.1, localhost)

    -t, --worker_threads=<num>         Number of threads processing incoming requests and sending responses (default: 20 * number of processors)

    -c, --cache_config=<filename>      Cache configuration file (default: creates cache with default values)

    -r, --protocol=                    Protocol to understand by the server. This is a mandatory option and you should choose one of these options
          [memcached|hotrod|websocket]

    -i, --idle_timeout=<num>           Idle read timeout, in seconds, used to detect stale connections (default: -1).
                                       If no new messages have been read within this time, the server disconnects the channel.
                                       Passing -1 disables idle timeout.

    -n, --tcp_no_delay=[true|false]    TCP no delay flag switch (default: true).

    -s, --send_buf_size=<num>          Send buffer size (default: as defined by the OS).

    -e, --recv_buf_size=<num>          Receive buffer size (default: as defined by the OS).

    -o, --proxy_host=<host or ip>      Host address to expose in topology information sent to clients.
                                       If not present, it defaults to configured host.
                                       Servers that do not transmit topology information ignore this setting.

    -x, --proxy_port=<num>             Port to expose in topology information sent to clients. If not present, it defaults to configured port.
                                       Servers that do not transmit topology information ignore this setting.

    -k, --topo_lock_timeout=<num>      Controls lock timeout (in milliseconds) for those servers that maintain the topology information in an internal cache.

    -u, --topo_repl_timeout=<num>      Sets the maximum replication time (in milliseconds) for transfer of topology information between servers.
                                       If state transfer is enabled, this setting also controls the topology cache state transfer timeout.
                                       If state transfer is disabled, it controls the amount of time to wait for this topology data
                                       to be lazily loaded from a different node when not present locally.
                                       This value should be set higher than 'topo_lock_timeout' to allow remote locks to be acquired within the time allocated to replicate the topology.

    -a, --topo_state_trasfer=          Enabling topology information state transfer means that when a server starts it retrieves this information from a different node.
          [true|false]                 Otherwise, if set to false, the topology information is lazily loaded if not available locally.

    -d, --topo_update_timeout=<num>    Sets the maximum time (in milliseconds) to wait for topology information to be updated.
                                       This value should be set higher than 'topo_repl_timeout' to allow retries to happen if a replication timeout is encountered.

    -f, --cache_manager_class=<clazz>  Cache manager class name to be used instead of the default one (it has to extend org.infinispan.manager.EmbeddedCacheManager).

    -D<name>[=<value>]                 Set a system property

binディレクトリにはその他サンプルアプリケーションの起動スクリプトがあったり、etcディレクトリには設定ファイルのサンプルがあったりすので、必要に応じて見てみるとよいと思います。

では、起動してみます。

$ bin/startServer.sh 
ERROR: Please indicate protocol to run with -r parameter
usage: startServer [options]

options:
    -h, --help  

〜省略〜

「-rパラメータは必須だよ」と怒られました。「-r」は、通信に使うプロトコルを指定するパラメータです。

    -r, --protocol=                    Protocol to understand by the server. This is a mandatory option and you should choose one of these options
          [memcached|hotrod|websocket]

ヘルプによると、

プロトコル パラメータ値 デフォルトポート
Memcached memcached 11211
Hot Rod hotrod 11222
WebSocket websocket 8181

ということになるようです。その他、modulesにあるWARファイルを使用することで、RESTサーバとしても使える模様。

まずはMemcachedで試してみようと思ったのですが、Mavenリポジトリ上で使えるクライアントが…な感じだったので、ここはいきなりHot Rodにすることにしました。

Hot Rodは、Javaから使えるバイナリプロトコルらしいです。
https://docs.jboss.org/author/display/ISPN/Java+Hot+Rod+client

Hot Rod Clientを使ってみる

それでは、試してみましょう。

build.sbt

name := "infinispan-remote"

version := "0.0.1"

scalaVersion := "2.10.0"

organization := "littlewings"

resolvers += "JBoss Public Maven Repository Group" at "http://repository.jboss.org/nexus/content/groups/public-jboss/"

libraryDependencies += "org.infinispan" % "infinispan-client-hotrod" % "5.2.1.Final"

src/main/scala/HotRodClient.scala

import org.infinispan.client.hotrod.{RemoteCache, RemoteCacheManager}

object HotRodClient {
  def main(args: Array[String]): Unit = {
    val manager: RemoteCacheManager = new RemoteCacheManager("localhost:11222")
    // デフォルトポートを使うなら、以下でOK
    // val manager: RemoteCacheManager = new RemoteCacheManager("localhost")
    val cache: RemoteCache[String, Integer] = manager.getCache()

    val keys = (1 to 3) map (i => s"key$i")

    keys foreach (k => println(s"key[$k] => value[${cache.get(k)}]"))

    keys foreach (k => cache.get(k) match {
      case null => cache.put(k, 1)
      case v => cache.put(k, v.toInt + 1)
    })

    keys foreach (k => println(s"key[$k] => value[${cache.get(k)}]"))
  }
}

キャッシュの値をIntegerにして、単純にインクリメントしていくサンプルです。

では、InfinispanをHot Rodで起動。

$ bin/startServer.sh -r hotrod

プログラムを動かしてみます。

> run
[info] Running HotRodClient 
2 10, 2013 6:09:33 午後 org.infinispan.client.hotrod.RemoteCacheManager start
INFO: ISPN004021: Infinispan version: Infinispan 'Delirium' 5.2.1.Final
key[key1] => value[null]
key[key2] => value[null]
key[key3] => value[null]
key[key1] => value[1]
key[key2] => value[1]
key[key3] => value[1]
[success] Total time: 2 s, completed 2013/02/10 18:09:33
> run
[info] Running HotRodClient 
2 10, 2013 6:09:37 午後 org.infinispan.client.hotrod.RemoteCacheManager start
INFO: ISPN004021: Infinispan version: Infinispan 'Delirium' 5.2.1.Final
key[key1] => value[1]
key[key2] => value[1]
key[key3] => value[1]
key[key1] => value[2]
key[key2] => value[2]
key[key3] => value[2]
[success] Total time: 1 s, completed 2013/02/10 18:09:37
> run
[info] Running HotRodClient 
2 10, 2013 6:09:39 午後 org.infinispan.client.hotrod.RemoteCacheManager start
INFO: ISPN004021: Infinispan version: Infinispan 'Delirium' 5.2.1.Final
key[key1] => value[2]
key[key2] => value[2]
key[key3] => value[2]
key[key1] => value[3]
key[key2] => value[3]
key[key3] => value[3]
[success] Total time: 1 s, completed 2013/02/10 18:09:39

1回目は値がnullですが、実行を繰り返すにしたがって値がインクリメントされていきます。
プログラムが終了しても値がInfinispanに保持されたままですが、今回は別プロセスで起動しているので、そりゃそうですよね、と。

Infinispanを止める時は、とりあえずCtrl-Cで。

名前付きキャッシュを使う

今度は、名前付きキャッシュを使ってみます。キャッシュ取得の部分をこう変更して

    val cache: RemoteCache[String, Integer] = manager.getCache("namedCache")

実行すると

> run
[info] Running HotRodClient 
2 10, 2013 6:18:55 午後 org.infinispan.client.hotrod.RemoteCacheManager start
INFO: ISPN004021: Infinispan version: Infinispan 'Delirium' 5.2.1.Final
2 10, 2013 6:18:55 午後 org.infinispan.client.hotrod.impl.protocol.Codec10 checkForErrorsInResponseStatus
WARN: ISPN004005: Error received from the server: org.infinispan.server.hotrod.CacheNotFoundException: Cache with name 'namedCache' not found amongst the configured caches

「そんな名前のキャッシュ、知らないよ」と怒られました…。RemoteCacheの場合は、あらかじめ定義しておく必要があるみたいですね。

というわけで、サーバ側に設定ファイルを作ります。1度Infinispanを終了して

$ bin/startServer.sh -r hotrod -c etc/infinispan-remote.xml

「-c」オプションを付けて作った設定ファイルのパスを指定して起動します。

設定ファイルの内容は最小設定で、これだけです。

<?xml version="1.0" encoding="UTF-8"?>
<infinispan
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="urn:infinispan:config:5.2 http://www.infinispan.org/schemas/infinispan-config-5.2.xsd"
    xmlns="urn:infinispan:config:5.2">
  <namedCache name="namedCache" />
</infinispan>

では、再度実行。

> run
[info] Running HotRodClient 
2 10, 2013 6:24:40 午後 org.infinispan.client.hotrod.RemoteCacheManager start
INFO: ISPN004021: Infinispan version: Infinispan 'Delirium' 5.2.1.Final
key[key1] => value[null]
key[key2] => value[null]
key[key3] => value[null]
key[key1] => value[1]
key[key2] => value[1]
key[key3] => value[1]
[success] Total time: 1 s, completed 2013/02/10 18:24:41
> run
[info] Running HotRodClient 
2 10, 2013 6:24:42 午後 org.infinispan.client.hotrod.RemoteCacheManager start
INFO: ISPN004021: Infinispan version: Infinispan 'Delirium' 5.2.1.Final
key[key1] => value[1]
key[key2] => value[1]
key[key3] => value[1]
key[key1] => value[2]
key[key2] => value[2]
key[key3] => value[2]
[success] Total time: 0 s, completed 2013/02/10 18:24:42

今度は、うまくいきました。