서버 개발을 할때 여러 was에서 세션 정보를 공유해야할 경우가 있다. 이럴때 세션 저장소로 redis cache 를 많이 활용하게 되는데 Spring boot 내장 embedded tomcat에서는 어떻게 설정을 하면 되는지 확인해 본다.
Tomcat cluster redis session 라이브러리는 아래 사이트에 가면 다운로드 받을 수 있다.
https://github.com/ran-jit/tomcat-cluster-redis-session-manager/wiki
여러 버전이 있는데 제일 최근 버전인 4.0 버전을 사용해 보기로 한다.
다운로드 library maven project에 추가하기
위에서 다운로드 압축파일을 풀면 아래 파일들이 나온다.
commons-pool2-2.6.2.jar
jedis-3.0.1.jar
tomcat-cluster-redis-session-manager-4.0.jar
redis-data-cache.properties
jar 파일들은 mvn 패키지 빌드시에 포함되어야 하므로 원하는 폴더에 라이브러리를 넣고 아래와 같이 local repository를 라이브러리 path로 잡는다. (아래 예시에서 library local 위치는 ${basedir}/src/main/webapp/WEB-INF/lib)
pom.xml
<dependency>
<groupId>jedis</groupId>
<artifactId>jedis</artifactId>
<version>3.0.1</version>
<scope>system</scope>
<systemPath>${basedir}/src/main/webapp/WEB-INF/lib/jedis-3.0.1.jar</systemPath>
</dependency>
<dependency>
<groupId>omcat-cluster-redis-session-manager</groupId>
<artifactId>omcat-cluster-redis-session-manager</artifactId>
<version>4.0.0</version>
<scope>system</scope>
<systemPath>${basedir}/src/main/webapp/WEB-INF/lib/tomcat-cluster-redis-session-manager-4.0.jar</systemPath>
</dependency>
<dependency>
<groupId>commons-pool</groupId>
<artifactId>commons-pool</artifactId>
<version>2.6.2</version>
<scope>system</scope>
<systemPath>${basedir}/src/main/webapp/WEB-INF/lib/commons-pool2-2.6.2.jar</systemPath>
</dependency>
Tomcat session clustering 설정 생성
Spring boot에서 위에서 사용할 redis session manager를 구동시키기 위해서는 Configuration Bean을 등록해야 한다.
아래와 같이 테스트용 confi를 작성해 본다.
package com.sdp.common.config;
import org.apache.catalina.Context;
import org.springframework.boot.web.embedded.tomcat.TomcatContextCustomizer;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.context.annotation.Configuration;
import tomcat.request.session.redis.SessionHandlerValve;
import tomcat.request.session.redis.SessionManager;
@Configuration
public class TomcatClusterConfig implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {
@Override
public void customize(TomcatServletWebServerFactory factory) {
factory.addContextValves(new SessionHandlerValve());
factory.addContextCustomizers(new TomcatContextCustomizer() {
@Override
public void customize(Context context) {
context.setSessionTimeout(30);
context.setSessionCookieName("testSession");
context.setManager(new SessionManager());
}
});
}
}
Embedded tomcat basedir 지정
다운로드 받은 라이브러리에는 redis-data-cache.properties 파일이 들어있고 여기에는 세션 저장을 위한 redis cache server 정보를 입력하게 된다. Embedded Tomcat에서 아래 설정 파일을 읽어와야 하므로 tomcat basedir를 지정하고{tomcat_base}/conf 폴더에 redis-data-cache.properties를 복사해 둔다.
#-- Redis data-cache configuration
# - ${ENV_VARIABLE_NAME}
#- redis hosts. ex: 127.0.0.1:6379, 127.0.0.2:6379, 127.0.0.2:6380, ....
redis.hosts=127.0.0.1:6379
#- redis password.
#redis.password=
#- set true to enable redis cluster mode. (default value: false)
redis.cluster.enabled=false
#- set true to enable redis sentinel mode. (default value: false)
redis.sentinel.enabled=false
# redis sentinel master name. (default value: mymaster)
redis.sentinel.master=mymaster
#- redis database. (default value: 0)
#redis.database=0
#- redis connection timeout. (default value: 2000 ms)
#redis.timeout=2000
#- enable redis and standard session mode. (default value: false)
# If enabled,
# 1. Must be enabled sticky session in your load balancer configuration. Else this manager may not return the updated session values.
# 2. Session values are stored in local jvm and redis.
# 3. If redis is down/not responding, requests uses jvm stored session values to process user requests. Redis comes back the values will be synced.
lb.sticky-session.enabled=false
#- session persistent policies. (default value: DEFAULT) ex: DEFAULT, SAVE_ON_CHANGE
# policies - DEFAULT, SAVE_ON_CHANGE, ALWAYS_SAVE_AFTER_REQUEST
# 1. SAVE_ON_CHANGE: every time session.setAttribute() or session.removeAttribute() is called the session will be saved.
# 2. ALWAYS_SAVE_AFTER_REQUEST: force saving after every request, regardless of whether or not the manager has detected changes to the session.
session.persistent.policies=DEFAULT
#- single-sign-on session timeout. (default value: 0 ms (-infinite))
redis.sso.timeout=0
테스트로 tomcat basedir은 .으로 지정하였다.
application.properties
server.addr=xxx
server.port=8080
server.tomcat.basedir= .
세션 공유 테스트 하기
테스트를 위해 세션에다 데이터를 쓰고 읽는 간단한 Rest api를 만들어보고 세션 공유 테스트를 한다.
@ApiOperation(httpMethod = "GET", value = "공개키 생성 - Get public key value of application.properties", produces = "application/json", consumes = "application/json")
@RequestMapping(value = "/api/v1/public-key", method = RequestMethod.GET)
public ResponseEntity<RSAKeyResult> cratePublicKey(HttpServletRequest req) throws Exception {
RSAKey rsaKey = RSAHelper.generateRSAKeyAndStoreInSession();
HttpSession session = req.getSession(true);
session.setAttribute("rsaKey", rsaKey);
RSAKeyResult result = new RSAKeyResult();
result.setPublicKeyExponent(rsaKey.getPublicKeyExponent());
result.setPublicKeyModulus(rsaKey.getPublicKeyModulus());
return ResponseEntity.ok(result);
}
@ApiOperation(httpMethod = "GET", value = "공개키 조회 - Get public key value of application.properties", produces = "application/json", consumes = "application/json")
@RequestMapping(value = "/api/v1/public-key/read", method = RequestMethod.GET)
public ResponseEntity<RSAKeyResult> getPublicKey(HttpServletRequest req) throws Exception {
HttpSession session = req.getSession();
RSAKey rsaKey = (RSAKey) session.getAttribute("rsaKey");
RSAKeyResult result = new RSAKeyResult();
result.setPublicKeyExponent(rsaKey.getPublicKeyExponent());
result.setPublicKeyModulus(rsaKey.getPublicKeyModulus());
return ResponseEntity.ok(result);
}
Spring boot application 을 포트만 달리해서 2개로 빌드한다. 그리고 각 서버를 실행한다. swagger-ui 를 실행한후 위 rest api를 실행해본다.
우선 localhost:8080의 swagger-ui로 들어가서 세션에 데이터를 생성한다. 아래와 같이 api가 정상응답을 주었고 세션에 데이터가 생성 되었을 것이다.
세션 클러스터링을 하고 있는 다른 서버 (localhost:8081)를 같은 브라우저의 다른 탭으로 실행 (이때 기 생성된 세션을 넘겨준다.) 하고 테스트 데이터 읽기 rest api를 수행해 본다.
위 결과에서 볼수 있듯이 redis에 세션이 저장되어 있기 때문에 세션 공유를 받은 다른 서버에서 바로 세션 데이터를 읽어보면 앞에서 다른 서버에서 설정한 값을 읽어 올수 있게 된다.
-- The end --
'Backend Development > Spring boot' 카테고리의 다른 글
[Spring boot] RestTemplate 으로 http 통신하기 (0) | 2023.04.29 |
---|---|
[Spring boot] MultipartFile 파일 업로드 구현 (0) | 2023.04.11 |
Embedded Redis 로 redis junit 작성하기 (0) | 2023.02.20 |
kakao 로그인 (javascript) (1) | 2023.01.28 |
Tomcat redis session cluster 설정 (0) | 2022.12.21 |