これは、なにをしたくて書いたもの?
WildFlyでのHTTPセッションの保存先として、以下のパターンがあるようです。
- Infinispan(Embedded)
- Infinispan(Embedded)+Infinispan Server(Hot Rod)
- Infinispan Server(Hot Rod)
このブログでは、どれも扱ったことがないのですが。
最初のInfinispan(Embedded)を扱う場合はstandalone-ha.xml
等のHigh Availability向けの設定ファイルを使うとすぐにできるので、
今回は3つ目のInfinispan Server(Hot Rod)をHTTPセッションの保存先にしてみたいと思います。
HotRod session management
WildFlyのHTTPセッションの保存先をInfinispan Server(Hot Rod)にする方法については、以下に記載があります。
ざっくり言うと、WildFlyに対して以下の設定を行うことで利用できます。
- Remote Cache Containerの定義
- Infinispan Serverへの接続先の定義(
socket-binding-group
への追加) - InfinispanサブシステムへRemote Cache Containerを追加(
remote-cache-container
を追加)
- Infinispan Serverへの接続先の定義(
- Distributable Webの設定
- Distributable Webサブシステムへ、Hot Rod用のHTTPセッション管理設定を追加(
hotrod-session-management
を追加)
- Distributable Webサブシステムへ、Hot Rod用のHTTPセッション管理設定を追加(
- Webアプリケーションの設定
web.xml
で<distributable/>
を設定する- (Distributable WebサブシステムでデフォルトのHTTPセッション保存先をHot Rodにしていない場合は)
WEB-INF/distributable-web.xml
でHTTPセッション保存先をHot Rodに指定
では、確認していきましょう。
環境
今回の環境は、こちらです。
$ java --version openjdk 17.0.3 2022-04-19 OpenJDK Runtime Environment (build 17.0.3+7-Ubuntu-0ubuntu0.20.04.1) OpenJDK 64-Bit Server VM (build 17.0.3+7-Ubuntu-0ubuntu0.20.04.1, mixed mode, sharing) $ mvn --version Apache Maven 3.8.5 (3599d3414f046de2324203b78ddcf9b5e4388aa0) Maven home: $HOME/.sdkman/candidates/maven/current Java version: 17.0.3, vendor: Private Build, runtime: /usr/lib/jvm/java-17-openjdk-amd64 Default locale: ja_JP, platform encoding: UTF-8 OS name: "linux", version: "5.4.0-117-generic", arch: "amd64", family: "unix"
WildFlyは26.1.1.Finalを使用します。
$ curl -OL https://github.com/wildfly/wildfly/releases/download/26.1.1.Final/wildfly-26.1.1.Final.zip
zipファイルを2回展開して、ローカルにWildFlyを2つのNodeを起動させることにします。
## WildFly-1 $ unzip wildfly-26.1.1.Final.zip $ mv wildfly-26.1.1.Final wildfly-26.1.1.Final-1 $ cd wildfly-26.1.1.Final-1 ## WildFly-2 $ unzip wildfly-26.1.1.Final.zip $ mv wildfly-26.1.1.Final wildfly-26.1.1.Final-2 $ cd wildfly-26.1.1.Final-2
WildFly-1はそのまま起動し、
$ bin/standalone.sh
WildFly-2はポートを100ずらして起動しておきます。
$ bin/standalone.sh -Djboss.socket.binding.port-offset=100
Infinispan Serverは、WildFly 26.1.1.Finalに含まれているものがInfinispan 13.0.10.Finalだったので、こちらの合わせたものを使用。
Infinispan Serverは3つのNode(172.18.0.2〜172.18.0.4)を用意して、それぞれ以下のコマンドで起動しておきます。
$ bin/server.sh \ -b 0.0.0.0 \ -Djgroups.tcp.address=`hostname -i`
また、各Infinispan Serverには管理者権限を持ったユーザーを作成しておきます。以下のコマンドは、各Infinispan Serverで実行します。
$ bin/cli.sh user create -g admin -p password web-session-user
Cacheは作成しません。
WildFlyの設定を行う
ところで、WildFlyの起動コマンドは以下にしていました。
## WildFly-1 $ bin/standalone.sh ## WildFly-2 $ bin/standalone.sh -Djboss.socket.binding.port-offset=100
Standaloneモードであり、WildFly自体はクラスターを構成しない方針でいきます。
※WildFly自体もクラスター構成にしてもいいのですが、今回はInfinispan Serverを介してHTTPセッションを共有していることを確認する主旨とします
$ bin/jboss-cli.sh -c [standalone@localhost:9990 /]
手順に従って、WildFlyを設定していきます。
まずはSocket Binding Groupの追加と、Remote Cache Containerの追加です。
High Availability Guide / Infinispan Subsystem / Remote Cache Container / Configuration
/socket-binding-group=standard-sockets/remote-destination-outbound-socket-binding=infinispan-server-1:add(host=172.18.0.2, port=11222) /socket-binding-group=standard-sockets/remote-destination-outbound-socket-binding=infinispan-server-2:add(host=172.18.0.3, port=11222)
2つのNodeしか登録していませんが、あとひとつはHot Rod Client自身に見つけてもらうようにしましょう(Hot Rod Client自身がクラスターを
構成しているInfinispan Serverの各Nodeを検出することができます)。
次に、Remote Cache Containerを追加します。
batch /subsystem=infinispan/remote-cache-container=remote-infinispan:add(default-remote-cluster=remote-infinispan-cluster) /subsystem=infinispan/remote-cache-container=remote-infinispan/remote-cluster=remote-infinispan-cluster:add(socket-bindings=[infinispan-server-1, infinispan-server-2]) run-batch
少なくとも初回は、上記2つの操作はバッチ処理で実行する必要があります。Remote Cache ContainerとRemote Clusterの設定が相互に
依存したものになっているからです。かつ、Remote Cache Containerの作成時にはdefault-remote-cluster
(デフォルトのRemote Clusterの設定)は
必須になっています。
個々に登録しようとすると、以下のようにエラーになります。
/subsystem=infinispan/remote-cache-container=remote-infinispan:add(default-remote-cluster=remote-infinispan-cluster) { "outcome" => "failed", "failure-description" => "WFLYCTL0369: Required capabilities are not available: org.wildfly.clustering.infinispan.remote-cache-container.remote-cluster.remote-infinispan.remote-infinispan-cluster; Possible registration points for this capability: /subsystem=infinispan/remote-cache-container=* /subsystem=infinispan/remote-cache-container=*/remote-cluster=*", "rolled-back" => true } /subsystem=infinispan/remote-cache-container=remote-infinispan/remote-cluster=remote-infinispan-cluster:add(socket-bindings=[infinispan-server-1, infinispan-server-2]) { "outcome" => "failed", "failure-description" => "WFLYCTL0175: Resource [ (\"subsystem\" => \"infinispan\"), (\"remote-cache-container\" => \"remote-infinispan\") ] does not exist; a resource at address [ (\"subsystem\" => \"infinispan\"), (\"remote-cache-container\" => \"remote-infinispan\"), (\"remote-cluster\" => \"remote-infinispan-cluster\") ] cannot be created until all ancestor resources have been added", "rolled-back" => true }
次に、Remote Cache Containerにorg.wildfly.clustering.web.hotrod
をモジュールとして追加し、properties
で認証情報を追加します。
認証情報は、Infinispan Serverで最初に作成した管理者権限を持ったユーザーを指定します。
/subsystem=infinispan/remote-cache-container=remote-infinispan:write-attribute(name=modules,value=[org.wildfly.clustering.web.hotrod]) /subsystem=infinispan/remote-cache-container=remote-infinispan:write-attribute(name=properties,value={infinispan.client.hotrod.auth_username=web-session-user,infinispan.client.hotrod.auth_password=password})
org.wildfly.clustering.web.hotrod
が必要な点はドキュメントに記載がなかったので、まあまあハマりました…。
ドキュメントに習って、統計情報も有効にしておきましょう。
High Availability Guide / Infinispan Subsystem / Remote Cache Container / Configuration / Statistics
/subsystem=infinispan/remote-cache-container=remote-infinispan:write-attribute(name=statistics-enabled, value=true)
Remote Cache Containerの定義が終わったので、今度はHTTPセッションの保存先としてInfinispan Server(Hot Rod)が利用できるように
設定します。
Distributable Webサブシステムのhotrod-session-management
として、先ほど作成したRemote Cache Containerを指定。
/subsystem=distributable-web/hotrod-session-management=remote-session:add(remote-cache-container=remote-infinispan, cache-configuration=org.infinispan.DIST_SYNC, granularity=SESSION)
指定している各要素の意味は、それぞれ以下です。
remote-cache-container
… HTTPセッションの保存先となるRemote Cache Containercache-configuration
… Infinispan Server側でCacheを作成する時のテンプレートとなるCacheの設定- Deploymentの名前を同じCacheがInfinispan Server側に存在しない場合、この設定を元にしてCacheを作成する
granularity
… Session Managerが個々のセッションをどのように扱うかを指定する(SESSION
、ATTRIBUTE
の2つから選択)SESSION
… すべてのセッションの属性を単一のCacheエントリー内に格納する。ATTRIBUTE
よりもコストがかかるが、オブジェクト間の参照は保持されるATTRIBUTE
… 各セッションの属性を個々のCacheエントリーとして格納する。SESSION
よりも効率的だが、オブジェクト間の参照は保持されない
granularity
は、standalone-ha.xml
に定義されているデフォルトのInfinispan(Embedded)のHTTPセッション管理だとSESSION
だったので、今回はそれに習いました。
granularity
については、こちらにも記載があります。
affinity
の設定も必要になります。affinity
はHot Rodだとnone
とlocal
のいずれかから選択します。今回はnone
としました。
/subsystem=distributable-web/hotrod-session-management=remote-session/affinity=none:add()
none
はWebのセッションがアプリケーションごとに維持されないユースケースを想定しており、特定のNodeには紐付かない指定になります。
local
は特定のリクエストを最後に処理したNodeとの親和性を持たせます。いわゆるスティッキーセッションに対応するオプションです。
デフォルトのHTTPセッション管理(default-session-management
)は、今回作成したhotrod-session-management
としておきましょう。
High Availability Guide / Distributable Web Applications / Distributable Web Subsystem
/subsystem=distributable-web:write-attribute(name=default-session-management,value=remote-session)
これで、web.xml
に<distributable/>
として指定されたWebアプリケーションは、HTTPセッションの管理がInfinispan Server(Hot Rod)と
なります。
ここまでやったら、reload
でWildFlyを再起動。
reload
WildFly-2にも、同様に反映しておきます。
$ bin/jboss-cli.sh -c --controller=localhost:10090
設定。
/socket-binding-group=standard-sockets/remote-destination-outbound-socket-binding=infinispan-server-1:add(host=172.18.0.2, port=11222) /socket-binding-group=standard-sockets/remote-destination-outbound-socket-binding=infinispan-server-2:add(host=172.18.0.3, port=11222) batch /subsystem=infinispan/remote-cache-container=remote-infinispan:add(default-remote-cluster=remote-infinispan-cluster,modules=[org.wildfly.clustering.web.hotrod],properties={infinispan.client.hotrod.auth_username=web-session-user,infinispan.client.hotrod.auth_password=password},statistics-enabled=true) /subsystem=infinispan/remote-cache-container=remote-infinispan/remote-cluster=remote-infinispan-cluster:add(socket-bindings=[infinispan-server-1, infinispan-server-2]) run-batch /subsystem=distributable-web/hotrod-session-management=remote-session:add(remote-cache-container=remote-infinispan, cache-configuration=org.infinispan.DIST_SYNC, granularity=SESSION) /subsystem=distributable-web/hotrod-session-management=remote-session/affinity=none:add() /subsystem=distributable-web:write-attribute(name=default-session-management,value=remote-session) reload
Remote Cache Containerの設定は、こちらでは1行にまとめました。
/subsystem=infinispan/remote-cache-container=remote-infinispan:add(default-remote-cluster=remote-infinispan-cluster,modules=[org.wildfly.clustering.web.hotrod],properties={infinispan.client.hotrod.auth_username=web-session-user,infinispan.client.hotrod.auth_password=password},statistics-enabled=true)
サンプルアプリケーションを作成する
では、動作確認用のサンプルアプリケーションを作成します。
Mavenの依存関係等。
<groupId>org.littlewings</groupId> <artifactId>remote-wildfly-hotrod-session</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <maven.compiler.source>17</maven.compiler.source> <maven.compiler.target>17</maven.compiler.target> <failOnMissingWebXml>false</failOnMissingWebXml> </properties> <dependencies> <dependency> <groupId>jakarta.platform</groupId> <artifactId>jakarta.jakartaee-web-api</artifactId> <version>8.0.0</version> <scope>provided</scope> </dependency> </dependencies> <build> <finalName>ROOT</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>3.3.2</version> </plugin> </plugins> </build>
HTTPセッションに保存するクラス。
src/main/java/org/littlewings/infinispan/session/Counter.java
package org.littlewings.infinispan.session; import java.io.Serializable; import java.util.concurrent.atomic.AtomicInteger; public class Counter implements Serializable { private static final long serialVersionUID = 1L; AtomicInteger value = new AtomicInteger(); public int increment() { return value.incrementAndGet(); } public int getValue() { return value.get(); } }
HTTPセッションを操作するクラス。お題は、カウンターということで。
src/main/java/org/littlewings/infinispan/session/CounterServlet.java
package org.littlewings.infinispan.session; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; @WebServlet("/counter") public class CounterServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { HttpSession session = req.getSession(); Counter counter = (Counter) session.getAttribute("counter"); if (counter == null) { counter = new Counter(); session.setAttribute("counter", counter); } int current = counter.increment(); resp.getWriter().write(String.format("current value = %d%n", current)); } }
web.xml
。ポイントは、<distributable/>
の指定です。
src/main/webapp/WEB-INF/web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee webapp_4_0.xsd" version="4.0"> <distributable/> </web-app>
パッケージングして準備完了です。
$ mvn package
動作確認してみる
それでは、動作確認をしてみましょう。
まずはWildFly-1にデプロイ。
$ cp target/ROOT.war /path/to/wildfly-26.1.1.Final-1/standalone/deployments
すると、WildFly側ではInfinispan ServerにROOT.war
というCacheが存在しないというWARNログが出力され
19:45:20,390 WARN [org.infinispan.HOTROD] (HotRod-client-async-pool-0) ISPN004005: Error received from the server: org.infinispan.server.hotrod.CacheNotFoundException: Cache with name 'ROOT.war' not found amongst the configured caches
Infinispan Server側ではCacheが作成されます。
$ bin/cli.sh -c http://web-session-user:password@localhost:11222 [infinispan-server-18273@cluster//containers/default]> describe caches/ROOT.war { "distributed-cache" : { "mode" : "SYNC", "remote-timeout" : "17500", "statistics" : true, "locking" : { "concurrency-level" : "1000", "acquire-timeout" : "15000", "striping" : false }, "state-transfer" : { "timeout" : "60000" } } }
また、WildFly側では、Infinispan Serverが3つのNodeで構成されていることを検出しています(登録していたのは、もともと2つのNodeでした)。
19:45:20,625 INFO [org.infinispan.HOTROD] (HotRod-client-async-pool-1) ISPN004006: Server sent new topology view (id=9, age=0) containing 3 addresses: [172.18.0.4/<unresolved>:11222, 172.18.0.3/<unresolved>:11222, 172.18.0.2/<unresolved>:11222]
何回かアクセスしてみます。
$ curl -c cookie.txt -b cookie.txt localhost:8080/counter current value = 1 $ curl -c cookie.txt -b cookie.txt localhost:8080/counter current value = 2 $ curl -c cookie.txt -b cookie.txt localhost:8080/counter current value = 3
ここで、WildFly-2にもデプロイ。
$ cp target/ROOT.war /path/to/wildfly-26.1.1.Final-2/standalone/deployments
WildFly-2にアクセスしてみます。
$ curl -c cookie.txt -b cookie.txt localhost:8180/counter current value = 4 $ curl -c cookie.txt -b cookie.txt localhost:8180/counter current value = 5
WildFly-1で進めたカウンターの値を引き継いでいます。
もう1度、WildFly-1にアクセス。
$ curl -c cookie.txt -b cookie.txt localhost:8080/counter current value = 6 $ curl -c cookie.txt -b cookie.txt localhost:8080/counter current value = 7
OKそうですね。
これで、クラスター構成にしなくてもWildFly Node間でHTTPセッションの共有かつリモートのInfinispan Serverへ保存するということが
実現できました。
この時の、WildFlyのInfinispan関連のメトリクスはこちら。
$ curl -s localhost:9990/metrics | grep -v '^#' | grep infinispan wildfly_infinispan_activations_total{cache_container="ejb",cache="http-remoting-connector"} 0.0 wildfly_infinispan_active_connections{remote_cache_container="remote-infinispan"} 0.0 wildfly_infinispan_average_read_time_seconds{remote_cache_container="remote-infinispan",remote_cache="ROOT.war"} 0.004 wildfly_infinispan_average_remove_time_seconds{remote_cache_container="remote-infinispan",remote_cache="ROOT.war"} 0.0 wildfly_infinispan_average_write_time_seconds{remote_cache_container="remote-infinispan",remote_cache="ROOT.war"} 0.004 wildfly_infinispan_connections{remote_cache_container="remote-infinispan"} 3.0 wildfly_infinispan_hits_total{remote_cache_container="remote-infinispan",remote_cache="ROOT.war"} 3.0 wildfly_infinispan_idle_connections{remote_cache_container="remote-infinispan"} 3.0 wildfly_infinispan_misses_total{remote_cache_container="remote-infinispan",remote_cache="ROOT.war"} 0.0 wildfly_infinispan_near_cache_hits_total{remote_cache_container="remote-infinispan",remote_cache="ROOT.war"} 0.0 wildfly_infinispan_near_cache_invalidations_total{remote_cache_container="remote-infinispan",remote_cache="ROOT.war"} 0.0 wildfly_infinispan_near_cache_misses_total{remote_cache_container="remote-infinispan",remote_cache="ROOT.war"} 0.0 wildfly_infinispan_near_cache_size{remote_cache_container="remote-infinispan",remote_cache="ROOT.war"} 0.0 wildfly_infinispan_passivations_total{cache_container="ejb",cache="http-remoting-connector"} 0.0 wildfly_infinispan_removes_total{remote_cache_container="remote-infinispan",remote_cache="ROOT.war"} 0.0 wildfly_infinispan_time_since_reset_seconds{remote_cache_container="remote-infinispan",remote_cache="ROOT.war"} 16119.0 wildfly_infinispan_writes_total{remote_cache_container="remote-infinispan",remote_cache="ROOT.war"} 2.0 wildfly_undertow_max_request_time_seconds{deployment="ROOT.war",servlet="org.littlewings.infinispan.session.CounterServlet",subdeployment="ROOT.war"} 0.0 wildfly_undertow_min_request_time_seconds{deployment="ROOT.war",servlet="org.littlewings.infinispan.session.CounterServlet",subdeployment="ROOT.war"} 0.0 wildfly_undertow_request_count_total{deployment="ROOT.war",servlet="org.littlewings.infinispan.session.CounterServlet",subdeployment="ROOT.war"} 0.0 wildfly_undertow_total_request_time_total_seconds{deployment="ROOT.war",servlet="org.littlewings.infinispan.session.CounterServlet",subdeployment="ROOT.war"} 0.0
Infinispan Serverのメトリクスはこちら。
$ curl -s --digest -u web-session-user:password 172.18.0.2:11222/metrics | grep -v '^#' | grep ROOT_war vendor_cache_manager_default_cache_ROOT_war_cluster_cache_stats_activations{node="infinispan-server-47530"} 0.0 vendor_cache_manager_default_cache_ROOT_war_cluster_cache_stats_approximate_entries{node="infinispan-server-47530"} 6.0 vendor_cache_manager_default_cache_ROOT_war_cluster_cache_stats_approximate_entries_in_memory{node="infinispan-server-47530"} 6.0 vendor_cache_manager_default_cache_ROOT_war_cluster_cache_stats_approximate_entries_unique{node="infinispan-server-47530"} 3.0 vendor_cache_manager_default_cache_ROOT_war_cluster_cache_stats_average_read_time{node="infinispan-server-47530"} 0.0 vendor_cache_manager_default_cache_ROOT_war_cluster_cache_stats_average_read_time_nanos{node="infinispan-server-47530"} 403717.0 vendor_cache_manager_default_cache_ROOT_war_cluster_cache_stats_average_remove_time{node="infinispan-server-47530"} 0.0 vendor_cache_manager_default_cache_ROOT_war_cluster_cache_stats_average_remove_time_nanos{node="infinispan-server-47530"} 0.0 vendor_cache_manager_default_cache_ROOT_war_cluster_cache_stats_average_write_time{node="infinispan-server-47530"} 1.0 vendor_cache_manager_default_cache_ROOT_war_cluster_cache_stats_average_write_time_nanos{node="infinispan-server-47530"} 1979985.0 vendor_cache_manager_default_cache_ROOT_war_cluster_cache_stats_cache_loader_loads{node="infinispan-server-47530"} 0.0 vendor_cache_manager_default_cache_ROOT_war_cluster_cache_stats_cache_loader_misses{node="infinispan-server-47530"} 0.0 vendor_cache_manager_default_cache_ROOT_war_cluster_cache_stats_current_number_of_entries_in_memory{node="infinispan-server-47530"} -1.0 vendor_cache_manager_default_cache_ROOT_war_cluster_cache_stats_data_memory_used{node="infinispan-server-47530"} -1.0 vendor_cache_manager_default_cache_ROOT_war_cluster_cache_stats_evictions{node="infinispan-server-47530"} 0.0 vendor_cache_manager_default_cache_ROOT_war_cluster_cache_stats_hit_ratio{node="infinispan-server-47530"} 0.8 vendor_cache_manager_default_cache_ROOT_war_cluster_cache_stats_hits{node="infinispan-server-47530"} 24.0 vendor_cache_manager_default_cache_ROOT_war_cluster_cache_stats_invalidations{node="infinispan-server-47530"} 0.0 vendor_cache_manager_default_cache_ROOT_war_cluster_cache_stats_misses{node="infinispan-server-47530"} 6.0 vendor_cache_manager_default_cache_ROOT_war_cluster_cache_stats_number_of_entries{node="infinispan-server-47530"} -1.0 vendor_cache_manager_default_cache_ROOT_war_cluster_cache_stats_number_of_locks_available{node="infinispan-server-47530"} 0.0 vendor_cache_manager_default_cache_ROOT_war_cluster_cache_stats_number_of_locks_held{node="infinispan-server-47530"} 0.0 vendor_cache_manager_default_cache_ROOT_war_cluster_cache_stats_off_heap_memory_used{node="infinispan-server-47530"} 0.0 vendor_cache_manager_default_cache_ROOT_war_cluster_cache_stats_passivations{node="infinispan-server-47530"} 0.0 vendor_cache_manager_default_cache_ROOT_war_cluster_cache_stats_read_write_ratio{node="infinispan-server-47530"} 2.090909090909091 vendor_cache_manager_default_cache_ROOT_war_cluster_cache_stats_remove_hits{node="infinispan-server-47530"} 0.0 vendor_cache_manager_default_cache_ROOT_war_cluster_cache_stats_remove_misses{node="infinispan-server-47530"} 0.0 vendor_cache_manager_default_cache_ROOT_war_cluster_cache_stats_required_minimum_number_of_nodes{node="infinispan-server-47530"} 2.0 vendor_cache_manager_default_cache_ROOT_war_cluster_cache_stats_store_writes{node="infinispan-server-47530"} 0.0 vendor_cache_manager_default_cache_ROOT_war_cluster_cache_stats_stores{node="infinispan-server-47530"} 22.0 vendor_cache_manager_default_cache_ROOT_war_cluster_cache_stats_time_since_reset{node="infinispan-server-47530"} 16067.0 vendor_cache_manager_default_cache_ROOT_war_cluster_cache_stats_time_since_start{node="infinispan-server-47530"} 600.0 vendor_cache_manager_default_cache_ROOT_war_configuration_eviction_size{node="infinispan-server-47530"} -1.0 vendor_cache_manager_default_cache_ROOT_war_lock_manager_number_of_locks_available{node="infinispan-server-47530"} 0.0 vendor_cache_manager_default_cache_ROOT_war_lock_manager_number_of_locks_held{node="infinispan-server-47530"} 0.0 vendor_cache_manager_default_cache_ROOT_war_passivation_passivations{node="infinispan-server-47530"} 0.0 vendor_cache_manager_default_cache_ROOT_war_rpc_manager_average_replication_time{node="infinispan-server-47530"} 1.0 vendor_cache_manager_default_cache_ROOT_war_rpc_manager_average_xsite_replication_time{node="infinispan-server-47530"} -1.0 vendor_cache_manager_default_cache_ROOT_war_rpc_manager_maximum_xsite_replication_time{node="infinispan-server-47530"} -1.0 vendor_cache_manager_default_cache_ROOT_war_rpc_manager_minimum_xsite_replication_time{node="infinispan-server-47530"} -1.0 vendor_cache_manager_default_cache_ROOT_war_rpc_manager_number_xsite_requests{node="infinispan-server-47530"} 0.0 vendor_cache_manager_default_cache_ROOT_war_rpc_manager_number_xsite_requests_received{node="infinispan-server-47530"} 0.0 vendor_cache_manager_default_cache_ROOT_war_rpc_manager_replication_count{node="infinispan-server-47530"} 23.0 vendor_cache_manager_default_cache_ROOT_war_rpc_manager_replication_failures{node="infinispan-server-47530"} 0.0 vendor_cache_manager_default_cache_ROOT_war_rpc_manager_success_ratio_floating_point{node="infinispan-server-47530"} 1.0 vendor_cache_manager_default_cache_ROOT_war_statistics_approximate_entries{node="infinispan-server-47530"} 2.0 vendor_cache_manager_default_cache_ROOT_war_statistics_approximate_entries_in_memory{node="infinispan-server-47530"} 2.0 vendor_cache_manager_default_cache_ROOT_war_statistics_approximate_entries_unique{node="infinispan-server-47530"} 1.0 vendor_cache_manager_default_cache_ROOT_war_statistics_average_read_time{node="infinispan-server-47530"} 0.0 vendor_cache_manager_default_cache_ROOT_war_statistics_average_read_time_nanos{node="infinispan-server-47530"} 172998.0 vendor_cache_manager_default_cache_ROOT_war_statistics_average_remove_time{node="infinispan-server-47530"} 0.0 vendor_cache_manager_default_cache_ROOT_war_statistics_average_remove_time_nanos{node="infinispan-server-47530"} 0.0 vendor_cache_manager_default_cache_ROOT_war_statistics_average_write_time{node="infinispan-server-47530"} 2.0 vendor_cache_manager_default_cache_ROOT_war_statistics_average_write_time_nanos{node="infinispan-server-47530"} 2944007.0 vendor_cache_manager_default_cache_ROOT_war_statistics_data_memory_used{node="infinispan-server-47530"} -1.0 vendor_cache_manager_default_cache_ROOT_war_statistics_elapsed_time{node="infinispan-server-47530"} 600.0 vendor_cache_manager_default_cache_ROOT_war_statistics_evictions{node="infinispan-server-47530"} 0.0 vendor_cache_manager_default_cache_ROOT_war_statistics_hit_ratio{node="infinispan-server-47530"} 1.0 vendor_cache_manager_default_cache_ROOT_war_statistics_hits{node="infinispan-server-47530"} 8.0 vendor_cache_manager_default_cache_ROOT_war_statistics_misses{node="infinispan-server-47530"} 0.0 vendor_cache_manager_default_cache_ROOT_war_statistics_number_of_entries{node="infinispan-server-47530"} -1.0 vendor_cache_manager_default_cache_ROOT_war_statistics_number_of_entries_in_memory{node="infinispan-server-47530"} -1.0 vendor_cache_manager_default_cache_ROOT_war_statistics_off_heap_memory_used{node="infinispan-server-47530"} 0.0 vendor_cache_manager_default_cache_ROOT_war_statistics_read_write_ratio{node="infinispan-server-47530"} 0.8 vendor_cache_manager_default_cache_ROOT_war_statistics_remove_hits{node="infinispan-server-47530"} 0.0 vendor_cache_manager_default_cache_ROOT_war_statistics_remove_misses{node="infinispan-server-47530"} 0.0 vendor_cache_manager_default_cache_ROOT_war_statistics_required_minimum_number_of_nodes{node="infinispan-server-47530"} 2.0 vendor_cache_manager_default_cache_ROOT_war_statistics_stores{node="infinispan-server-47530"} 10.0 vendor_cache_manager_default_cache_ROOT_war_statistics_time_since_reset{node="infinispan-server-47530"} 600.0 vendor_cache_manager_default_cache_ROOT_war_statistics_time_since_start{node="infinispan-server-47530"} 600.0
オマケ
Cacheの名前はどこで決まっている?
Infinispan Server側に作成されるCacheの名前は、Deploymentの名前ということでした。実際、ROOT.war
をデプロイするとROOT.war
という
名前のCacheが作成されました。
これはどこで決まっているかというと、ここみたいですね。
そして、Cacheを追加している箇所はこちら。
Marshallerで警告されている
今回の設定だと、起動時にMarshallerに関するこんなWARNログが出力されます。
19:45:03,247 WARN [org.jboss.as.clustering.infinispan] (ServerService Thread Pool -- 54) WFLYCLINF0033: Attribute 'marshaller' is configured to use a deprecated value: LEGACY; use one of the following values instead: [JBOSS, PROTOSTREAM]
これは、Remote Cache Containerの設定でMarshallerにLEGACY
が設定されているからですが。
/subsystem=infinispan/remote-cache-container=remote-infinispan:read-attribute(name=marshaller) { "outcome" => "success", "result" => "LEGACY" }
PROTOSTREAM
を指定するのがInfinispan的には良いと思いますが、今回はこのままで。
※あとで調べた結果、HTTPセッションのケースではPROTOSTREAM
を指定したことと同じになるようです
追記) Marshallerについての追加
WildFlyのInfinispanサブシステムでProtoStreamが使われているようになっていたという話 - CLOVER🍀
アプリケーション側で使用するHTTPセッション保存先を指定する
これは、以下の記載を見ます。
High Availability Guide / Distributable Web Applications / Overriding default behavior
WEB-INF/distributable-web.xml
またはMETA-INF/jboss-all.xml
で指定できるようです。
たとえば、今回は<distributable/>
なアプリケーションのHTTPセッションのデフォルトの保存先をRemote Cache Containerとしましたが、
これを他の保存先を指定する場合は以下のように記載します。
src/main/webapp/WEB-INF/distributable-web.xml
<?xml version="1.0" encoding="UTF-8"?> <distributable-web xmlns="urn:jboss:distributable-web:2.0"> <session-management name="default"/> </distributable-web>
これは、今回の設定変更を行った状態でのstandalone/configuration/standalone.xml
で、infinispan-session-management
のdefault
を
指しています(つまり、WildFlyのデフォルトの状態)。
<subsystem xmlns="urn:jboss:domain:distributable-web:2.0" default-session-management="remote-session" default-single-sign-on-management="default"> <infinispan-session-management name="default" cache-container="web" granularity="SESSION"> <local-affinity/> </infinispan-session-management> <hotrod-session-management name="remote-session" remote-cache-container="remote-infinispan" cache-configuration="org.infinispan.DIST_SYNC" granularity="SESSION"> <no-affinity/> </hotrod-session-management> <infinispan-single-sign-on-management name="default" cache-container="web" cache="sso"/> <local-routing/> </subsystem>
単純に定義済みのものを指定するだけではなく、hotrod-session-management
やinfinispan-session-management
の指定をもっと細かく
行えるようです。
ハマったこと
今回の内容で、いくつかハマりそうなこと(ハマったこと)を書いておきます。
認証・認可
現在のInfinispan Serverはデフォルトで認証が有効になっているので、WildFlyからの接続時に認証情報を指定しておかないとアクセスできません。
認証情報を設定していない場合は、こんなエラーが出力されます。
20:21:38,487 ERROR [org.jboss.msc.service.fail] (ServerService Thread Pool -- 81) MSC000001: Failed to start service jboss.clustering.web."ROOT.war".cache: org.jboss.msc.service.StartException in service jboss.clustering.web."ROOT.war".cache: org.infinispan.client.hotrod.exceptions.HotRodClientException:Request for messageId=6 returned server error (status=0x85): java.lang.SecurityException: ISPN006017: Operation 'EXEC' requires authentication
Hot Rodのプロパティの指定方法がドキュメントに書かれていないのでちょっとわかりづらいですが、こんな感じの指定方法になります。
/subsystem=infinispan/remote-cache-container=remote-infinispan:write-attribute(name=properties,value={infinispan.client.hotrod.auth_username=web-session-user,infinispan.client.hotrod.auth_password=password})
また今回、Infinispan Serverでユーザーを作成する際にadmin
グループに属するようにしましたが。
$ bin/cli.sh user create -g admin -p password web-session-user
これをapplication
グループに属するユーザーとすると、
$ bin/cli.sh user create -g application -p password web-session-user
以下のようにCacheを作成する権限がなくてエラーになります。
java.lang.SecurityException: ISPN000287: Unauthorized access: subject 'Subject with principal(s): [web-session-app-user, RolePrincipal{name='application'}, InetAddressPrincipal [address=172.18.0.1/172.18.0.1]]' lacks 'CREATE' permission 20:23:53,318 ERROR [org.jboss.msc.service.fail] (ServerService Thread Pool -- 79) MSC000001: Failed to start service jboss.clustering.web."ROOT.war".cache: org.jboss.msc.service.StartException in service jboss.clustering.web."ROOT.war".cache: org.infinispan.client.hotrod.exceptions.HotRodClientException:Request for messageId=18 returned server error (status=0x85): org.infinispan.commons.CacheException: java.lang.SecurityException: ISPN000287: Unauthorized access: subject 'Subject with principal(s): [web-session-app-user, RolePrincipal{name='application'}, InetAddressPrincipal [address=172.18.0.1/172.18.0.1]]' lacks 'CREATE' permission java.lang.SecurityException: ISPN000287: Unauthorized access: subject 'Subject with principal(s): [web-session-app-user, RolePrincipal{name='application'}, InetAddressPrincipal [address=172.18.0.1/172.18.0.1]]' lacks 'CREATE' permission
org.infinispan.client.hotrod.exceptions.HotRodClientException:Request for messageId=18 returned server error (status=0x85): org.infinispan.commons.CacheException: java.lang.SecurityException: ISPN000287: Unauthorized access: subject 'Subject with principal(s): [web-session-app-user, RolePrincipal{name='application'}, InetAddressPrincipal [address=172.18.0.1/172.18.0.1]]' lacks 'CREATE' permission
今回はadmin
グループに属する強い権限を与えましたが、Cacheさえ作れればよいのでdeployer
グループあたりでよいかもですね。
このグループは、Infinispan Serverでデフォルトで使えるClusterRoleMapper
のものを使用しています。
もっと細かく権限管理したい場合は、Infinispan Serverのドキュメントに従って認証・認可設定を行ってください。
org.wildfly.clustering.web.hotrodモジュールを指定する
org.wildfly.clustering.web.hotrod
モジュールをRemote Cache Containerに指定していましたが、これを忘れるとSessionCreationMetaDataKey
が
シリアライズできずに失敗します。
20:31:38,437 ERROR [io.undertow.request] (default task-1) UT005023: Exception handling request to /counter: org.infinispan.client.hotrod.exceptions.HotRodClientException:: Unable to marshall object of type [org.wildfly.clustering.web.hotrod.session.SessionCreationMetaDataKey]
以下のコマンドは、org.wildfly.clustering.web.hotrod
モジュールをRemote Cache Containerに設定しているものです。
/subsystem=infinispan/remote-cache-container=remote-infinispan:write-attribute(name=modules,value=[org.wildfly.clustering.web.hotrod])
この説明は、ドキュメントには一切出てきませんが…。
追記) org.wildfly.clustering.web.hotrod
モジュールを足さないとシリアライズに失敗するのは、MarshallerをLEGACY
にしているからだと
いうことに後で気づきました
WildFlyのInfinispanサブシステムでProtoStreamが使われているようになっていたという話 - CLOVER🍀
実はaffinityの指定が必須
途中で以下のように突然affinity
の指定を行いましたが。
/subsystem=distributable-web/hotrod-session-management=remote-session/affinity=none:add()
実は、これを入れないとデプロイ時に失敗します。
20:45:46,511 INFO [org.jboss.as.controller] (DeploymentScanner-threads - 1) WFLYCTL0183: Service status report WFLYCTL0184: New missing/unsatisfied dependencies: service org.wildfly.clustering.web.session-management-provider.remote-session.affinity (missing) dependents: [service org.wildfly.clustering.web.session-management-provider.remote-session]
hotrod-session-management
の必須項目ではないのですが、まあ要りますということで…。
参考
How to externalize HTTP sessions on Infinispan - Mastertheboss
まとめ
WildFlyで動作するアプリケーションのHTTPセッションの保存先を、Infinispan Serverに設定してみました。
設定内容のイメージはある程度ありましたが、WildFly上でどう表現するのかがよくわからなかったり、モジュール指定が必要だというところで
まあまあハマりました。
とりあえず、実現できたので良しとしましょう。
今回作成したソースコードは、こちらに置いています。
https://github.com/kazuhira-r/infinispan-getting-started/tree/master/remote-wildfly-hotrod-session