Spring Session Redisの接続先をAmazon ElastiCacheにする

はじめに

Spring Bootアプリの開発でセッション管理をする際にSpring Sessionを使うことが多いかなと思います。今回、Spring Session Data Redisの接続先としてAmazon ElastiCacheを使ってみましたので、その内容を記します。

前提条件

今回、Spring Bootは3.1.5を使用しました。このバージョンが重要で、Spring Boot 2.7までとは設定が異なりましたので、その点も踏まえて記します。

また、EC2上で動かしているSpring BootアプリからAmazon ElastiCacheに対して接続する構成としました。

実装

build.gradleのdependenciesに以下の二つを追記します。

    implementation 'org.springframework.boot:spring-boot-starter-data-redis'
    implementation 'org.springframework.session:spring-session-data-redis'

接続先の設定はapplication.propertiesにて以下のようにします。Spring Boot 3.xから設定項目が微妙に変わっているのが要注意です。

spring.data.redis.host=${REDIS_HOST:localhost}
spring.data.redis.port=${REDIS_PORT:6379}

Spring Boot 2.7までですと、以下の記述がapplication.propertiesに必要でした。

spring.session.redis.configure-action=none

これは、下記ページにあるようにElastiCache RedisにてRedisのconfigコマンドは使用が制限されており、その対応のためです。

docs.aws.amazon.com

Spring Boot 2.7では上記の記述をしていない場合、アプリ起動時(bootRunなど実行時)に以下のメッセージが出て、起動に失敗します。メッセージ内にERR unknown command 'CONFIG'というのがconfigコマンドの使用が制限されていることを示しています。

2023-11-19 06:35:19.826  WARN 27001 --- [           main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'enableRedisKeyspaceNotificationsInitializer' defined in class path resource [org/springframework/boot/autoconfigure/session/RedisSessionConfiguration$SpringBootRedisHttpSessionConfiguration.class]: Invocation of init method failed; nested exception is org.springframework.data.redis.RedisSystemException: Error in execution; nested exception is io.lettuce.core.RedisCommandExecutionException: ERR unknown command 'CONFIG', with args beginning with: 'GET' 'notify-keyspace-events'

ただ、Spring Boot 3.0からは不要となります。

詳細は以下のブログを参照。

tech.excite.co.jp

アプリの実装は以下のような形で。これもSpring Boot 3.xからHttpSessionのimportがjakartaのものになるのが注意点です。

package com.github.miyohide.springboot_31;

import jakarta.servlet.http.HttpSession;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class GreetingController {
  private final HttpSession httpSession;
  private final RedisTemplate<String, String> redisTemplate;
  private static final Logger logger = LoggerFactory.getLogger(GreetingController.class);

  public GreetingController(HttpSession httpSession, RedisTemplate<String, String> redisTemplate) {
    this.httpSession = httpSession;
    this.redisTemplate = redisTemplate;
  }

  @GetMapping("/")
  public Greeting greeting(@RequestParam(value = "name", defaultValue = "World") String name) {
    logger.info("HTTP Session id = [" + httpSession.getId() + "]");
    if (httpSession.isNew()) {
      httpSession.setAttribute("name", name);
    }
    return new Greeting(
        httpSession.getId(),
        (String) httpSession.getAttribute("name"),
        httpSession.getCreationTime());
  }

  @GetMapping("/view")
  public String viewSession() {
    Set<String> redisKeys = redisTemplate.keys("spring:session:sessions:*");
    List<String> keysList = new ArrayList<>();
    for (String redisKey : redisKeys) {
      keysList.add(redisKey);
    }
    return keysList.toString();
  }

  @GetMapping("/goodbye")
  public String goodbye() {
    String httpSessionId = httpSession.getId();
    String name = httpSession.getAttribute("name").toString();
    httpSession.invalidate();
    return "bye. HTTP Session id = [" + httpSessionId + "], name = [" + name + "]";
  }
}

実行

環境変数REDIS_HOSTREDIS_PORTAmazon ElastiCacheのエンドポイントの値を入れてSpring Bootアプリを実行すると、Amazon ElastiCacheにセッション情報が格納されていることが確認できます。

ソース

以下にサンプルコードを載せています。

github.com

考察

Amazon ElastiCacheの使用例としてSpring Session Redisを使った例を実装してみました。Spring Bootのバージョン間で若干の差がありますが、単純にセッションの置き場としてでしたら設定する項目が少なければ少ないほど良いと考えており、今回の変更は大変嬉しいです。

ただ、Amazon ElastiCacheは非常に高機能ですし、せっかく使うのであればセッションの置き場だけで使うのはちょっともったいない感じもあります。なんらかの使用用途がないか模索しています。