본문 바로가기

Backend Development/Spring boot

[Spring boot] Spring Redis Session Clustering 설정하기

Backend 개발 시 HA 구성이나 여러 유관 시스템 연동 시 세션  Clustering을 통해 정보를 공유해야할 경우가 생긴다. 이럴 경우에 Tomcat, Nginx, Jboss 등의 웹 서버 단에서 Sticky Session 설정을 할수도 있으나 Spring framework에서 제공하는 session redis 기능을 활용하면 수월하게 Session Clustering 환경을 구축 할 수 있다.

 

Spring Session 기능은 아래 공식 문서에서 찾아볼 수 있다.

https://docs.spring.io/spring-session/reference/index.html

 

중요한 부분은 언급되어 있는 아래 최소 사항 항목이다.

Java 17+ 및 Spring 6.0.x 사항이 언급되어 있다. 나름 최신 사양으로 보인다.

Minimum Requirements

The minimum requirements for Spring Session are:

  • Java 17+.
  • If you run in a Servlet Container (not required), Servlet 3.1+.
  • If you use other Spring libraries (not required), the minimum required version is Spring 6.0.x.
  • @EnableRedisHttpSession requires Redis 2.8+. This is necessary to support Session Expiration
  • @EnableHazelcastHttpSession requires Hazelcast 3.6+. This is necessary to support FindByIndexNameSessionRepository

 

현재 필자가 테스트하는 환경은

Spring boot 3.0.2 버전이고 Spring framework web 6.0.4 버전 + java 17을 사용하고 있다. 위 기능을 충족하는 사양이다.

 

pom.xml

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
    <version>3.0.2</version>
</dependency>
<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-data-redis</artifactId>
    <version>3.0.0</version>
</dependency>

레디스에 세션을 적재하므로 redis 관련 라이브러리 및 spring session 라이브러리를 다운 받는다.

 

 

RedisConfig.java

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Profile("!unittest")
@Configuration
public class RedisConfig {

    @Value("${spring.data.redis.host}")
    private String host;

    @Value("${spring.data.redis.port}")
    private int port;

    @Bean
    public RedisConnectionFactory redisConnectionFactory() {
        RedisStandaloneConfiguration redisConfiguration = new RedisStandaloneConfiguration();
        redisConfiguration.setHostName(host);
        redisConfiguration.setPort(port);
        redisConfiguration.setDatabase(0);
        return new LettuceConnectionFactory(redisConfiguration);
    }

    @Bean
    public RedisConnectionFactory redisConnectionFactoryToken() {
        RedisStandaloneConfiguration redisConfiguration = new RedisStandaloneConfiguration();
        redisConfiguration.setHostName(host);
        redisConfiguration.setPort(port);
        redisConfiguration.setDatabase(1);
        return new LettuceConnectionFactory(redisConfiguration);
    }

    @Bean(name = "redisTemplate")
    public RedisTemplate<?, ?> redisTemplate() {
        RedisTemplate<?, ?> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory());
        redisTemplate.setDefaultSerializer(new StringRedisSerializer());
        return redisTemplate;
    }

    @Bean(name = "redisTemplateToken")
    public RedisTemplate<?, ?> redisTemplateToken() {
        RedisTemplate<?, ?> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactoryToken());
        redisTemplate.setDefaultSerializer(new StringRedisSerializer());
        return redisTemplate;
    }
}

redis 서버를 컨트롤할 드라이버 설정을 한다.

 

 

application-local.yml

spring:
  application:
    name: Test
  servlet:
    multipart:
      enabled: true
  mybatis:
    common:
      config: classpath:mybatis/config/mybatis-config.xml
      mapper: classpath*:mybatis/sql/**/*.xml
    pops:
      mapper: classpath*:mybatis/sql/**/*.xml
  data:
    redis:
      host: 172.30.1.45
      port: 49153

위와 같이 redis 서버 정보를 yml에 입력하여 redis session 설정시 참조 하도록 한다.

 

CommonApplication.java

import lombok.Generated;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
import org.springframework.session.web.http.CookieSerializer;
import org.springframework.session.web.http.DefaultCookieSerializer;


@EnableConfigurationProperties()
@SpringBootApplication(scanBasePackages = "com")
@EnableRedisHttpSession
public class CommonApplication {

    @Bean
    public CookieSerializer cookieSerializer() {
        DefaultCookieSerializer serializer = new DefaultCookieSerializer();
        serializer.setCookieName("TEST_SESSIONID");
        serializer.setCookiePath("/");
        serializer.setDomainName("test.com");
        return serializer;
    }

    @Generated
    public static void main(String[] args) {
        SpringApplication.run(CommonApplication.class);
    }
}

Spring boot main entry에 위와 같이 @EnableRedisHttpSession 을 추가하면 spring session redis 설정이 진행된다.

이와 함께 세션이 적재될 Cookie의 속성을 변경하고자 한다면 CookieSerializer bean을 추가해 주도록 한다.

 

        serializer.setCookieName("TEST_SESSIONID");
        serializer.setCookiePath("/");
        serializer.setDomainName("test.com");

 

setCookieName은 브라우저에 표시될 Cookie key 이름이고 CookiePath는 Cookie가 참조될 request url path, setDomainName은 쿠키를 공유할 서브 도메인을 말한다.

 

 

TestController.java

@Tag(name = "테스트", description = "테스트 관련 API")
@RestController
@RequestMapping("/api/v1/iam")
public class TestController {

    @Operation(summary = "레디스 세션을 생성한다.", description = "디버깅용 테스트 세션을 생성한다." + "\n\n" +
            "필수 파라미터 : ")
    @ApiResponses(value = {
        @ApiResponse(responseCode = "200", description = "Success", content = @Content(schema = @Schema(implementation = ResultDVO.class)))
    })
    @RequestMapping(value = "/test/session", method = RequestMethod.POST, produces = "application/json")
    public ResponseEntity<ResultDVO> createTestSession(HttpServletRequest request) throws Exception{

        HttpSession session = request.getSession(true);
        session.setAttribute("TEST_DATA", System.currentTimeMillis());

        return new ResponseEntity<>(new ResultDVO(), HttpStatus.OK);
    }
}

 

간단하게 세션에 현재 시간을 저장하는 테스트 Rest api를 만들어 본다.

 

Swagger-UI를 열람하고 테스트 Api를 실행해본다.

 

브라우저의 Cookie 결과를 보면 설정한대로 Cookie 속성이 설정되어 있음을 볼 수 있다.

 

P3X REDIS Client tool을 깔고 레디스 내용을 살펴보면 spring -> session 항목에 세션이 생성되어 있음을 볼 수 있고 세션 내용을 열람하면 아래와 같이 테스트 Rest api에서 저장한 TEST_DATA 세션 값이 있음을 볼 수 있다.

 

-- The End --