1. はじめに
今回は1台のホスト上でTomcatのセッション共有を試してみたいと思います。セッションの保存先をTomcatのメモリから外部永続化(DB、ファイル、KVS等)するだけで良いと思っているメンバがいたため試せる環境を構築してみました。
Javaアプリでセッションを利用するにはjsessionidが重要になりますが、jsessionidはオリジン(Origin)とコンテキストパスが異なれば連携されません。example1.com
のjsessionidが別のサイトであるexample2.com
に連携されたら困ってしまいます。同じ理由でlocalhost:8080
とlocalhost:8081
は別のサイトと認識され、jsessionidが連携されることはありません。つまりWebブラウザが同じサイトと認識してjsessionidを連携するにはオリジンとコンテキストパスを同じにする必要があります。
Apache、mod_jk、Tomcat、redisson、Redisを利用して、セッション共有の検証環境を構築する手順について説明します。
2. Redisのダウンロードと実行
WindowsでRedisを動かすため古いバージョンになりますが以下のサイトからZip版をダウンロードし、任意のディレクトリに展開後、redis-server.exe
を実行します。
https://github.com/MicrosoftArchive/redis/releases
Redis-x64-3.0.504.zip
3. Tomcatのダウンロード
以下のサイトからZip版をダウンロードし、任意のディレクトリに展開します。展開したディレクトリをCATALINA_HOME
環境変数として定義します。
https://tomcat.apache.org/download-10.cgi
apache-tomcat-10.1.26-windows-x64.zip
4. redissonのダウンロードと設定
以下のサイトからredisson-all-3.37.0.jar
とredisson-tomcat-10-3.37.0.jar
をダウンロードし、%CATALINA_HOME%/lib
に配置します。
redisサーバにアクセスするための設定ファイル(redisson.conf)を作成し、%CATALINA_HOME%/conf
に配置します。
singleServerConfig:
address: "redis://127.0.0.1:6379"
threads: 0
nettyThreads: 0
transportMode: NIO
Tomcatのセッションの保存先をRedisにするため、%CATALINA_BASE%/conf/context.xml
に設定を追加します。
<Context>
<!-- Default set of monitored resources. If one of these changes, the -->
<!-- web application will be reloaded. -->
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<WatchedResource>WEB-INF/tomcat-web.xml</WatchedResource>
<WatchedResource>${catalina.base}/conf/web.xml</WatchedResource>
<!-- Uncomment this to enable session persistence across Tomcat restarts -->
<!--
<Manager pathname="SESSIONS.ser" />
-->
<!-- ⭐️以下の内容を追加 -->
<Manager className="org.redisson.tomcat.RedissonSessionManager"
configPath="${catalina.base}/conf/redisson.conf"
readMode="REDIS" updateMode="DEFAULT" broadcastSessionEvents="false"
keyPrefix=""/>
</Context>
5. Tomcatの起動
セッション共有を確認するため、2つのTomcatインスタンスを起動させます。詳細についてはCATALINA_BASE環境変数を利用してTomcatを複数起動する方法を参照ください。
@echo off
set JAVA_HOME=C:¥tools¥corretto¥jdk17.0.12_7
set CATALINA_HOME=C:¥tools¥apache-tomcat-10.1.26
set SHUTDOWN_PORT=8005
set SERVER_PORT=8081
set AJP_PORT=8009
call %CATALINA_HOME%\bin\startup.bat
@echo off
set JAVA_HOME=C:¥tools¥corretto¥jdk17.0.12_7
set CATALINA_HOME=C:¥tools¥apache-tomcat-10.1.26
set CATALINA_BASE=C:¥tools¥apserver_2
set SHUTDOWN_PORT=8006
set SERVER_PORT=8084
set AJP_PORT=8019
call %CATALINA_HOME%¥bin¥startup.bat
6. Apache(httpd)のダウンロードと設定
以下のサイトからWindows向けのZip版をダウンロードに、任意のディレクトリに展開します。展開したディレクトリをSRVROOT
として定義します。
https://www.apachelounge.com/download/
httpd-2.4.62-240904-win64-VS17.zip
Define SRVROOT "C:/tools/httpd-2.4.62/Apache24"
ServerRoot "${SRVROOT}"
7. mod_jkのダウンロードと設定
以下のサイトからmod_jkモジュールをダウンロードし、mod_jk.so
をSRVROOT/modules
に配置します。
https://www.apachelounge.com/download/
mod_jk-1.2.50-win64-VS17.zip
Apacheがmod_jkモジュールを読み込むように設定ファイル(httpd.conf)を変更します。
JkMount /examples/* lb
は/examples/*
のリクエストはmod_jkのlbワーカーで処理(リクエストをTomcatに転送)させるという記述です。
# Load mod_jk module
LoadModule jk_module modules/mod_jk.so
<IfModule jk_module>
# Where to find workers.properties
# Update this path to match your conf directory location (put workers.properties next to httpd.conf)
JkWorkersFile conf/workers.properties
# Where to put jk shared memory
# Update this path to match your local state directory or logs directory
JkShmFile logs/mod_jk.shm
# Where to put jk logs
# Update this path to match your logs directory location (put mod_jk.log next to access_log)
JkLogFile logs/mod_jk.log
# Set the jk log level [debug/error/info]
JkLogLevel info
# Select the timestamp log format
JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "
JkRequestLogFormat "%w %p %s %v %V %T"
# Send everything for context /examples to worker named lb (ajp13)
JkMount /examples/* lb
</IfModule>
ApacheからTomcatへリクエストを転送させるための設定ファイル(SRVROOT/conf/workers.properties
)を作成します。
portはTomcatのAJP13プロトコルの待ち受けポート番号と合わせる必要があります。
lbfactorはワーカーの振り分け割合を示すもので、同じ値の場合は均等(2台の場合はそれぞれ50%)となります。また、セッション共有のためsticky_session
は不要なので無効(false)に設定します。
worker.list=lb
worker.lb.type=lb
worker.lb.balance_workers=worker1,worker2
worker.worker1.port=8009
worker.worker1.host=127.0.0.2
worker.worker1.type=ajp13
worker.worker1.lbfactor=1
worker.worker1.sticky_session=false
worker.worker2.port=8019
worker.worker2.host=127.0.0.3
worker.worker2.type=ajp13
worker.worker2.lbfactor=1
worker.worker2.sticky_session=false
8. Apache(httpd)の起動
準備が終わったので最後にApache(httpd)を起動します。SRVROOT/bin
にあるhttpd.exe
を実行します。
9. 動作確認
Webブラウザを起動しhttp://localhost/examples/
にアクセスすると、Apache Tomcat Examplesの画面が表示されると思います。
「Servlet examples」の「Sessions」ー「Execute」リンクからセッションのサンプル機能でセッション共有の機能を確認できます。
セッションに値を設定しつつ、Tomcatインスタンスの一方を停止(Ctrl+C)させてもセッションサンプルは正常に動作するはずです。また、停止させたTomcatを起動し、一定時間が経過すると再度リクストが転送されることも確認できると思います。
git bash
をインストールしている場合、tail
コマンドが使えるのでtail -f
でTomcatのアクセスログを表示すると2つのTomcatのどちらでリクエストを処理をしているのか判断しやすくなります。
10. さいごに
今回はWindowsのローカル上でRedis&Redissonによるセッション共有を確認する方法について説明しました。redissonのaddressやmod_jk(workers.porperties)のhostを別ホストに設定すれば、複数ホスト(ノード)でのセッション共有のサーバ構築ができるかと思います。
なお、クラウド環境で実行する場合、Apacheやmod_jkを利用せずに実現することができます。例えばAWSであればALBでHTTP(S)を受け付け、バックエンドのTomcatの8080ポートにリクエストを転送できます。Cookies(jsessionid)のドメイン・パスを確認するとWebブラウザから見えるホスト(ApacheやALB等)とセッションの関係が分かるかと思います。