最近、HazelcastのDiscovery SPIでちょっと遊んでみました。
HazelcastのDiscovery SPIを試して解説する - CLOVER
今度はこのDiscovery SPIを、Payara Microで使ってみようかなと思いまして。
Discovery SPIは、Hazelcastのクラスタに参加するNode探す機能(Node Discovery)を実装するためのAPIセットでした。こちらを使うことで、マルチキャストが
使えない環境であっても、TCPでのホスト列挙設定以外の方法でHazelcastクラスタを構成することができるようになります。
ポイント
Payara MicroでHazelcastのDiscovery SPIを使うにあたって、ちょっと気をつけなくてはいけないことがあります。
それは、HazelcastのDiscovery SPIの実装を、デプロイするアプリケーションには含めないということです。
- Hazelcastは、Payara Microにより使われる
- Discovery SPIは、Service Providerの仕組みによってロードされる
このため、デプロイするアプリケーションにDiscovery SPIの実装を含めるのではなく、Payara Micro側に含めてあげる必要があります。ポイントは、ここになります。
で、どうすればいいのかというと、Payara Microには「--addjars」というオプションがあり、こちらを使うことでPayara Micro側のクラスパスにライブラリを追加することが
できるようになります。
Adding Third-Party JARs to a Micro Instance
こちらを活用してみましょう。
お題
こんなお題で、確認してみます。
- Discovery SPIの実装としては、Hazelcast Discovery Plugin for Apache ZooKeeperを使う
- Apache ZooKeeperを使った、Hazelcastのクラスタが構成できることを確認する
- Hazelcastクラスタによるデータ共有ができていることを確認する
環境
動作環境は、こんな感じ。
$ java -version openjdk version "1.8.0_151" OpenJDK Runtime Environment (build 1.8.0_151-8u151-b12-0ubuntu0.16.04.2-b12) OpenJDK 64-Bit Server VM (build 25.151-b12, mixed mode) $ mvn -v Apache Maven 3.5.3 (3383c37e1f9e9b3bc3df5050c29c8aff9f295297; 2018-02-25T04:49:05+09:00) Maven home: /usr/local/maven3/current Java version: 1.8.0_151, vendor: Oracle Corporation Java home: /usr/lib/jvm/java-8-openjdk-amd64/jre Default locale: ja_JP, platform encoding: UTF-8 OS name: "linux", version: "4.4.0-104-generic", arch: "amd64", family: "unix"
使用するPayara Microは4.1.2.181、あとApache ZooKeeperは起動済みで3.4.11を使うものとします。
準備
作成するアプリケーションのMaven設定。
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <failOnMissingWebXml>false</failOnMissingWebXml> </properties> <dependencies> <dependency> <groupId>javax</groupId> <artifactId>javaee-api</artifactId> <version>7.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>com.hazelcast</groupId> <artifactId>hazelcast</artifactId> <version>3.8.5</version> <scope>provided</scope> </dependency> </dependencies> <build> <finalName>app</finalName> </build>
packagingは、warとしています。
アプリケーションの作成
簡単な、カウンタを作ってみます。
JAX-RSの有効化。
src/main/java/org/littlewings/payara/rest/JaxrsActivator.java
package org.littlewings.payara.rest; import javax.ws.rs.ApplicationPath; import javax.ws.rs.core.Application; @ApplicationPath("rest") public class JaxrsActivator extends Application { }
HazelcastのAtomicLongを使った、カウンタを扱うJAX-RSリソースクラス。
src/main/java/org/littlewings/payara/rest/CalcResource.java
package org.littlewings.payara.rest; import javax.enterprise.context.ApplicationScoped; import javax.inject.Inject; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import com.hazelcast.core.HazelcastInstance; import com.hazelcast.core.IAtomicLong; @ApplicationScoped @Path("calc") public class CalcResource { @Inject HazelcastInstance hazelcast; @GET @Path("inc") @Produces(MediaType.TEXT_PLAIN) public String increment() { IAtomicLong counter = hazelcast.getAtomicLong("counter"); return "count = " + counter.incrementAndGet(); } }
とても単純です。
パッケージングして
$ mvn package
とりあえず、動かしてみましょう。
$ java -jar payara-micro-4.1.2.181.jar --deploy target/app.war
確認。
$ curl localhost:8080/app/rest/calc/inc count = 1 count = 2 count = 3
OKそうです。クラスタ構成の確認は、はしょります。
Payara MicroでHazelcast Discovery Plugin for Apache ZooKeeperを使えるようにする
では、HazelcastのNode DiscoveryをApache ZooKeeperで行うようにしてみましょう。
まずは、Hazelcast Discovery Plugin for Apache ZooKeeper(以降、hazelcast-zookeeper)が依存するライブラリを、Payara Microに突っ込む必要があります。
ここは、Maven Dependency Pluginを使ってライブラリを集めましょう。まずは、hazelcast-zookeeperのpom.xmlを取得します。
$ wget 'https://search.maven.org/remotecontent?filepath=com/hazelcast/hazelcast-zookeeper/3.6.3/hazelcast-zookeeper-3.6.3.pom' -O hazelcast-zookeeper-3.6.3.pom
今回使用するhazelcast-zookeeperのバージョンは、3.6.3です。
hazelcast-zookeeperの依存ライブラリのうち、Hazelcastを除いた「compile」スコープのライブラリを「dependency:copy-dependencies」で集め、それから
hazelcast-zookeeperも忘れずに取得します。
*HazelcastはPayara Micro側に含まれているので、外しておきます
収集するディレクトリは、「zookeeper-discovery-spi-lib」とします。
$ mvn -f hazelcast-zookeeper-3.6.3.pom dependency:copy-dependencies -DoutputDirectory=zookeeper-discovery-spi-lib -DincludeScope=compile -DexcludeArtifactIds=hazelcast $ wget 'https://search.maven.org/remotecontent?filepath=com/hazelcast/hazelcast-zookeeper/3.6.3/hazelcast-zookeeper-3.6.3.jar' -O zookeeper-discovery-spi-lib/hazelcast-zookeeper-3.6.3.jar
集めたライブラリ。
$ ls -l zookeeper-discovery-spi-lib 合計 6320 -rw-rw-r-- 1 xxxxx xxxxx 71909 3月 18 23:30 curator-client-2.9.0.jar -rw-rw-r-- 1 xxxxx xxxxx 190334 3月 18 23:30 curator-framework-2.9.0.jar -rw-rw-r-- 1 xxxxx xxxxx 273666 3月 18 23:30 curator-recipes-2.9.0.jar -rw-rw-r-- 1 xxxxx xxxxx 58325 3月 18 23:30 curator-x-discovery-2.9.0.jar -rw-rw-r-- 1 xxxxx xxxxx 2228009 3月 18 23:30 guava-16.0.1.jar -rw-rw-r-- 1 xxxxx xxxxx 11862 3月 18 23:30 hazelcast-zookeeper-3.6.3.jar -rw-rw-r-- 1 xxxxx xxxxx 232248 3月 18 23:30 jackson-core-asl-1.9.13.jar -rw-rw-r-- 1 xxxxx xxxxx 780664 3月 18 23:30 jackson-mapper-asl-1.9.13.jar -rw-rw-r-- 1 xxxxx xxxxx 87325 3月 18 23:30 jline-0.9.94.jar -rw-rw-r-- 1 xxxxx xxxxx 481535 3月 18 23:30 log4j-1.2.16.jar -rw-rw-r-- 1 xxxxx xxxxx 1208356 3月 18 23:30 netty-3.7.0.Final.jar -rw-rw-r-- 1 xxxxx xxxxx 32127 3月 18 23:30 slf4j-api-1.7.12.jar -rw-rw-r-- 1 xxxxx xxxxx 792964 3月 18 23:30 zookeeper-3.4.6.jar
続いて、Apache ZooKeeperを使ってNode Discoveryを行うように、Hazelcastの設定を行います。こういう設定ファイルを用意。
hazelcast.xml
<?xml version="1.0" encoding="UTF-8"?> <hazelcast xsi:schemaLocation="http://www.hazelcast.com/schema/config hazelcast-config-3.8.xsd" xmlns="http://www.hazelcast.com/schema/config" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <properties> <property name="hazelcast.discovery.enabled">true</property> </properties> <group> <name>discovery-development</name> <password>D3v3l0pm3nt</password> </group> <network> <port>5900</port> <join> <multicast enabled="false"/> <discovery-strategies> <discovery-strategy enabled="true" class="com.hazelcast.zookeeper.ZookeeperDiscoveryStrategy"> <properties> <property name="zookeeper_url">172.17.0.2:2181</property> <!-- <property name="zookeeper_path">/discovery/hazelcast</property> <property name="group">hazelcast</property> --> </properties> </discovery-strategy> </discovery-strategies> </join> </network> </hazelcast>
Payara MicroのデフォルトのHazelcastの設定から、少し変更しました(groupの名前あたり)。
Payara Microで使用されるデフォルトのHazelcastの設定については、こちらを見るとよいでしょう。
https://github.com/payara/Payara/blob/payara-server-4.1.2.181/nucleus/payara-modules/hazelcast-bootstrap/src/main/java/fish/payara/nucleus/hazelcast/HazelcastRuntimeConfiguration.java
hazelcast-zookeeperの設定ですが、接続先以外はデフォルトのままです。
<discovery-strategy enabled="true" class="com.hazelcast.zookeeper.ZookeeperDiscoveryStrategy"> <properties> <property name="zookeeper_url">172.17.0.2:2181</property> <!-- <property name="zookeeper_path">/discovery/hazelcast</property> <property name="group">hazelcast</property> --> </properties> </discovery-strategy>
コメントアウトしている箇所は、デフォルト値を指していますが、Apache ZooKeeper上のパスを指します。
Apache ZooKeeper上には、「${zookeeper_path}/${group}」でノードが作られるようです。
なお、接続先URLのデフォルト値は「127.0.0.1:2181」です。
では、起動してみましょう。
ひとつ目のNodeを起動してみます。「--addjars」でhazelcast-zookeeperと関連ライブラリを含めたディレクトリを、「--hzconfigfile」で作成したHazelcastの
設定ファイルを指定しているところがポイントです。
$ java -jar payara-micro-4.1.2.181.jar --deploy target/app.war --addjars zookeeper-discovery-spi-lib --hzconfigfile hazelcast.xml
Node起動時に、Apache ZooKeeper側にはこういうログが出力されます。
2018-03-18 14:16:50,396 [myid:] - INFO [SyncThread:0:ZooKeeperServer@683] - Established session 0x10001d290a00000 with negotiated timeout 40000 for client /172.17.0.1:54112 2018-03-18 14:16:51,280 [myid:] - INFO [ProcessThread(sid:0 cport:2181)::PrepRequestProcessor@653] - Got user-level KeeperException when processing sessionid:0x10001d290a00000 type:create cxid:0x1 zxid:0x2 txntype:-1 reqpath:n/a Error Path:/discovery/hazelcast/hazelcast Error:KeeperErrorCode = NoNode for /discovery/hazelcast/hazelcast
「/discovery/hazelcast」が「zookeeper_path」のデフォルト値、「hazelcast」が「group」のデフォルト値でした。
Path:/discovery/hazelcast/hazelcast Error:KeeperErrorCode = NoNode for /discovery/hazelcast/hazelcast
続いて、2つ目のNodeを起動します。HTTPリッスンポートは、8081を使うことにしました。
$ java -jar payara-micro-4.1.2.181.jar --deploy target/app.war --port 8081 --addjars zookeeper-discovery-spi-lib --hzconfigfile hazelcast.xml
Apache ZooKeeper側にも接続されたというログが現れ
2018-03-18 14:20:25,820 [myid:] - INFO [SyncThread:0:ZooKeeperServer@683] - Established session 0x10001d290a00001 with negotiated timeout 40000 for client /172.17.0.1:54144
Hazelcastとしてもクラスタが構成されます。
[2018-03-18T23:20:33.087+0900] [] [情報] [] [com.hazelcast.internal.cluster.ClusterService] [tid: _ThreadID=56 _ThreadName=hz._hzInstance_1_discovery-development.generic-operation.thread-0] [timeMillis: 1521382833087] [levelValue: 800] [[ [172.17.0.1]:5900 [discovery-development] [3.8.5] Members [2] { Member [172.17.0.1]:5900 - dfc320fd-1417-4834-bc3d-dfba949caf06 this Member [172.17.0.1]:5901 - 38118a41-08e7-4094-bd0f-33d70021a3f0 } ]]
確認してみましょう。
$ curl localhost:8080/app/rest/calc/inc count = 1 $ curl localhost:8081/app/rest/calc/inc count = 2 $ curl localhost:8080/app/rest/calc/inc count = 3 $ curl localhost:8081/app/rest/calc/inc count = 4
OKそうですね。
オマケ
Uber JARにする場合は、こんな感じで。
$ java -jar payara-micro-4.1.2.181.jar --deploy target/app.war --addjars zookeeper-discovery-spi-lib --outputuberjar target/app.jar
起動。
$ java -jar target/app.jar --hzconfigfile hazelcast.xml
Payara Micro Maven Pluginを使ってUber JARを使おうかとも思ったのですが、customJars/artifactItemでは依存関係を含めた形でJARに含めてくれない
みたいなので、今回はパスで…。