Redis と Apache TomcatのHttpSession連携

# RedisとApache TomcatのHttpSession連携

## はじめに
- Tomcatが扱うHttpSessionをTomcat上のメモリー（Javaのヒープ）ではなく、Redisを利用する
- Tomcatから使う時のデータ等のインメモリーキャッシュの用途ではない
- [Spring](https://spring.io/)は使わない。Springに頼らないで対応するのは、知見獲得に良い。

## サンプル
- GitHub リポジトリ https://github.com/ssugimoto/tomcat-session-redis
- docker-compose.yml, Dockerfile, reddsion*.jar, example.war をリポジトリに置いています
- https://github.com/ssugimoto/tomcat-session-redis#install-using に利用方法を記載しています


## RedisのDockerコンテナ
- tomcatと連携することになるので、docker-composeを使うようにします
- Redisの最新は7.0系でした（ https://hub.docker.com/_/redis より）

※途中過程なので、最終版は異なります

```docker-compose.yml
services:

  redis:
    container_name: redis
    image: redis:7.0-bullseye
    ports:
      - 6379:6379
    volumes:
      - "./data/redis:/data"

```


- docker compose で コンテナを起動
```
docker-compose up

Pulling redis (redis:7.0-bullseye)...
7.0-bullseye: Pulling from library/redis
461246efe0a7: Pull complete
edee06fdf403: Pull complete
04b7adc9ef61: Pull complete
6f4a4580ec0b: Pull complete
b70fc086369d: Pull complete
242936d47e59: Pull complete
Digest: sha256:ed8cba11c09451dbb3495f15951e4afb4f1ba72a4a13e135c6da06c6346e0333
Status: Downloaded newer image for redis:7.0-bullseye
Creating redis ... done
Attaching to redis
redis    | 1:C 31 Jul 2022 14:32:39.727 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
redis    | 1:C 31 Jul 2022 14:32:39.727 # Redis version=7.0.4, bits=64, commit=00000000, modified=0, pid=1, just started
redis    | 1:C 31 Jul 2022 14:32:39.727 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
redis    | 1:M 31 Jul 2022 14:32:39.727 * monotonic clock: POSIX clock_gettime
redis    | 1:M 31 Jul 2022 14:32:39.727 * Running mode=standalone, port=6379.
redis    | 1:M 31 Jul 2022 14:32:39.727 # Server initialized
redis    | 1:M 31 Jul 2022 14:32:39.727 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
redis    | 1:M 31 Jul 2022 14:32:39.728 * Ready to accept connections
```

これで、Redisのコンテナは起動しました。

### コンテナの中に入ってみます。コマンド使うのは手間なので、VSCodeの拡張機能を使います。
1. 使うVSCodeの拡張機能
     - <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1482752/5402dab2-19a7-ed85-72ff-80fdbed80ae8.png" width="500" />

2. 左側メニューのdockerのアイコンを押すと

3. 緑色の矢印アイコン `redis:7.0-bullseye `が 見えるので、右クリックして、`Attach Shell ` を押す

4. コンテナの中に入れます

5. redis-cli で接続して keys で確認します
```
root@dab3c7d74133:/data# redis-cli
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379>
```

## Redisのredissionについて
- TomcatとRedisを連携するためには、jarやxml設定ファイルが必要になる

### 必要なjarファイルは2ファイル
- https://redisson.org/articles/redis-based-tomcat-session-management.html より、tomcatの設定、jarファイルについて記載がある
- [mavenリポジトリ](https://mvnrepository.com/artifact/org.redisson)からダウンロードする 
    - `redisson-all-3.17.5.jar` https://mvnrepository.com/artifact/org.redisson/redisson-all
    - `redisson-tomcat-10-3.16.1.jar` https://mvnrepository.com/artifact/org.redisson/redisson-tomcat-10
        - Tomcat6,7,8,9,10それぞれjarが異なります 
    - （redisson-3.17.5.jarは使わない） https://mvnrepository.com/artifact/org.redisson/redisson 

### 必要な設定

#### Redisコンテナへの接続情報
- redisson.conf `{CATALINA_BASE}/conf` に配置する、 パス例  /usr/local/tomcat/conf/redisson.conf

後から変更します
```redisson.conf
singleServerConfig:
  address: "redis://127.0.0.1:6379"
 
threads: 0
nettyThreads: 0
transportMode: NIO
```

-  redisson.conf では コンテナ間通信できるように container_name を指定する（最終形）

```redisson.conf
singleServerConfig:
  address: "redis://redis:6379"
  #address: "redis://127.0.0.1:6379"
 
threads: 0
nettyThreads: 0
transportMode: NIO
```

#### TomcatのHttpSessionをRedis使うためのクラス設定
- context.xml `{CATALINA_BASE}/conf` に配置する、パス例 /usr/local/tomcat/conf/context.xml

```context.xml
<?xml version="1.0" encoding="UTF-8"?>
<Context>
  <Manager className="org.redisson.tomcat.RedissonSessionManager" 
            configPath="${catalina.base}/conf/redisson.conf" 
            readMode="MEMORY" 
            updateMode="DEFAULT"/>
</Context>
```

## Tomcatのコンテナと sample.war と examples


- sample.war では、HttpSession使うような機能が見つからなかったので、examplesを試す方が良さそう
- docker-compose.yml  ※途中過程なので、最終版は異なります

```docker-compose.yml
services:
  tomcat:
    build:
      context: .
      dockerfile: ./tomcat/Dockerfile
    # volumes:
    #   -./tomcat/data:/

    ports:
      - 8080:8080
```

- Dockerfile
    - [docker-hub](https://hub.docker.com/_/tomcat) を見てみたが、exampls,manager等が入ったコンテナがどれかわからなかった

```Dockerfile

FROM tomcat:10.0-jre11-openjdk-slim
RUN apt-get update && apt-get install -y wget

COPY ./tomcat/files/redisson-tomcat-10-3.17.5.jar /usr/local/tomcat/lib
COPY ./tomcat/files/redisson-all-3.17.5.jar /usr/local/tomcat/lib
COPY ./tomcat/files/redisson.conf /usr/local/tomcat/conf/
COPY ./tomcat/files/context.xml /usr/local/tomcat/conf/
COPY ./tomcat/files/examples.war $CATALINA_HOME/webapps/

WORKDIR /usr/local/tomcat/webapps/
RUN wget https://tomcat.apache.org/tomcat-10.0-doc/appdev/sample/sample.war

```

- Tomcatコンテナのログ
```txt
docker-compose up


Building tomcat
[+] Building 6.1s (8/8) FINISHED
 => [internal] load build definition from Dockerfile                                                                             0.0s
 => => transferring dockerfile: 473B                                                                                             0.0s
 => [internal] load .dockerignore                                                                                                0.0s
 => => transferring context: 2B                                                                                                  0.0s
 => [internal] load metadata for docker.io/library/tomcat:10.0-jre11-openjdk-slim                                                1.9s
 => CACHED [1/4] FROM docker.io/library/tomcat:10.0-jre11-openjdk-slim@sha256:758470f6f9e007ef84cf5dd4c73c4dedeeaf5688d18a2ad39  0.0s
 => [2/4] RUN apt-get update && apt-get install -y wget                                                                          3.4s
 => [3/4] WORKDIR /usr/local/tomcat/webapps/                                                                                     0.0s
 => [4/4] RUN wget https://tomcat.apache.org/tomcat-10.0-doc/appdev/sample/sample.war                                            0.5s
 => exporting to image                                                                                                           0.1s
 => => exporting layers                                                                                                          0.1s
 => => writing image sha256:544afa923ad918471de4119dc06c912966cc66778b691e9ebeefd41c8e25d62e                                     0.0s
 => => naming to docker.io/library/session-redis_tomcat                                                                          0.0s

Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them
WARNING: Image for service tomcat was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`.
Recreating redis ... done
Creating session-redis_tomcat_1 ... done
Attaching to redis, session-redis_tomcat_1

... 略

tomcat_1  | 31-Jul-2022 15:20:43.779 INFO [main] org.apache.catalina.startup.HostConfig.deployWAR Deploying web application archive [/usr/local/tomcat/webapps/sample.war]
tomcat_1  | 31-Jul-2022 15:20:43.932 INFO [main] org.apache.catalina.startup.HostConfig.deployWAR Deployment of web application archive [/usr/local/tomcat/webapps/sample.war] has finished in [154] ms
tomcat_1  | 31-Jul-2022 15:20:43.937 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["http-nio-8080"]
tomcat_1  | 31-Jul-2022 15:20:43.953 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in [217] milliseconds


```

### examplesを動かしてみる

1. URL を開く
http://localhost:8080/examples/
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1482752/44e61ecf-5194-f148-9ee4-e3e58b82ec9f.png)

2. servlets examples  http://localhost:8080/examples/servlets/

- 2.1 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1482752/ecaccbe7-009d-3581-8ae8-1cf482817950.png)
「Sessions」の「Execute」を押すと、セッションを使えるようになる

- 2.3 
セッションID（jsessionid）
![exmaple-session1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1482752/1bdb6327-d650-b40b-9fae-af825c912f3d.png)


現時点の セッションID（jsessionid）がわかる、そのjsessionidは、redis側にも存在している

```
root@8dabeb9e01cf:/data# redis-cli
127.0.0.1:6379> keys *
1) "redisson:tomcat_session:686A47657B59BA6C3B6BB3CBB5783003"
2) "redisson:tomcat_session:F2BC7EAFC07D565F931CEF8E554606E3"
127.0.0.1:6379> 
```

- 2.4 セッションに情報を登録してみる

|セッション属性名|セッション属性の値|
| :--- | :---|
|key1|abcd|

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1482752/91b3b8fe-f087-3508-00bf-1b09eba33f67.png)

を入力し、「送信」ボタンを押す

- 2.4.2 examples画面の表示内容が変わる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1482752/9060ec9f-1565-b4c8-ddd6-8b7ba9cda6e6.png)


- 2.4.3 redisコンテナ側のデータを確認、redis のコマンドは、https://blog.eiel.info/blog/2014/08/26/remember-redis/ が参考になります。

```
127.0.0.1:6379> keys *
1) "redisson:tomcat_session:27864A9462136192E7ABA0CE42B6555F"
127.0.0.1:6379> type redisson:tomcat_session:27864A9462136192E7ABA0CE42B6555F
hash
127.0.0.1:6379> hgetall redisson:tomcat_session:27864A9462136192E7ABA0CE42B6555F
 1) "session:thisAccessedTime"
 2) "\x04L\x00\x00\x01\x82W&n\x8b"
 3) "session:isNew"
 4) "\x04Q"
 5) "session:lastAccessedTime"
 6) "\x04L\x00\x00\x01\x82W&n\x8b"
 7) "session:maxInactiveInterval"
 8) "\x04K\x00\x00\a\b"
 9) "session:isValid"
10) "\x04P"
11) "session:creationTime"
12) "\x04L\x00\x00\x01\x82W&n\x84"
13) "key1"
14) "\x04>\x04abcd"
127.0.0.1:6379>
```

13,14行目の結果に、画面で入れた内容が反映されている


### sample の方を動かしてみる
- HttpSessionを使うような処理が無さそう、一部エラー
- ブラウザで http://localhost:8080/sample/ を開く
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1482752/254be182-d03a-6b0e-fa8f-394220d3c75e.png)
- `http://localhost:8080/sample/hello.jsp` は動くけど、`http://localhost:8080/sample/hello` はエラーになる