안녕하세요!😄
현재 진행 중인 프로젝트의 백엔드 서버에 적용된 Session Clustering
에 대해 이야기 해보려 합니다.
여기서는
Load Balancing
,Reverse Proxy
와 같은 개념이 등장합니다.이젠에 작성된 해당 글을 참조해주세요!
세션 클러스터링이란?
Session Clustering
이란 말 그대로 Session
을 Clustering
즉, 군집화한다고 생각하면 이해가 빠를 것 같습니다.
우리가 웹사이트에 로그인하는 과정을 생각해봅시다.(쿠키-세션 방식을 이야기합니다.)
먼저, 클라이언트는 서버로 자신의 인증 정보를 전달합니다.
서버는 인증 정보를 검증한 후 인증된 사용자라면 해당 사용자의 정보를 서버 내 Session
에 저장하게 됩니다.
서버가 한 대만 존재한다면 사용자의 요청은 항상 동일한 서버로만 갈 것이기 때문에 Session
이 만료되지 않는 한 별도의 로그인 요청 없이 인증을 통과할 수 있습니다.
하지만, 현재 저희 서버와 같이 두 대의 서버가 존재하고 Load Balancing
을 사용해 사용자의 요청을 분산하여 전달하고 있다면 어떨까요?😯
사용자의 요청이 로그인한(자신의 세션 정보가 저장된) 서버로 간다는 보장이 없습니다.
최악의 경우에는 페이지를 이동할 때마다 로그인 정보를 요구할 수도 있는것이죠..😱😱
이러한 대참사를 막기 위해 사용하는 것이 바로 Session Clustering
입니다.
여러 서버에 대한 Session
을 공유하게 하여 사용자의 요청이 어느 서버로 가든 Session
정보가 존재한다면 인증 시켜줍니다.
적용해보기
Redis
는 Key-Value
구조로써 매우 빠르고 가볍습니다.
또한, 저희가 다루는 Spring Boot
와 매우 잘 연동되어 있기 때문에 코드 몇 줄만 추가하는 것으로 간단하게 Session Clustering
을 적용할 수 있습니다.
레디스에 대한 자세한 정보는 아래글을 참고해주세요.
먼저, 의존성을 추가해야합니다.
org.springframework.boot:spring-boot-starter-data-redis
spring-boot-starter-data-redis
는 spring
애플리케이션에서 redis
에 접근할 수 있게 해주는 라이브러리입니다.
공식 문서에서는 이를 아래와 같이 언급합니다.
더 큰 Spring Data 제품군의 일부인 Spring Data Redis는 Spring 애플리케이션에서 Redis에 대한 쉬운 구성 및 액세스를 제공합니다. 상점과 상호 작용하기 위한 저수준 및 고수준 추상화를 모두 제공하여 사용자를 인프라 문제로부터 해방시킵니다.
의존성을 주입했다면 다음은 yml
에 redis
설정을 추가해야합니다.
spring:
redis:
host: 호스트
password: 비밀번호(없다면 생략해도됨)
port: 6379(6379가 redis 기본포트)
위와 같이 설정을 했다면 ConnectionFactory
를 Spring Bean
으로 등록하기위해 Configuration
클래스를 만들어
야합니다.
@Configuration
public class RedisConfiguration {
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.password}")
private String password;
@Value("${spring.redis.port}")
private int port;
@Bean
public LettuceConnectionFactory lettuceConnectionFactory() {
final RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration(host, port);
redisStandaloneConfiguration.setPassword(RedisPassword.of(password));
return new LettuceConnectionFactory(redisStandaloneConfiguration);
}
@Bean
public RedisTemplate<String, Object> redisTemplate() {
final RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(lettuceConnectionFactory());
template.setDefaultSerializer(new StringRedisSerializer());
return template;
}
}
yml
에 등록한 설정을 @Value
를 사용하여 가져와 RedisStandaloneConfiguration
을 생성해주는데
RedisStandaloneConfiguration
의 생성자는 위 3개(기본 생성자, host, host+port)만 존재하므로
host
와 port
를 인수로 넘겨 생성한 후 setPassword
를 사용하였습니다.
이를 통해 최종적으로 ConnectionFactory
를 생성하여 반환합니다.
Lettuce
외에도 redis client
로써 Jedis
가 존재하지만
현 시점에서는, Jedis
에 많은 단점이 존재(멀티 쓰레드 불안정, Pool 한계)하여 deprecated
되고 Lettuce
를 권장하고 있습니다.
이에 대해 궁금하다면 향로님의 블로그글을 참조해주세요! Lettuce Vs Jedis
위 설정으로 인해 우리는 redis
에 접근할 수 있게 되었습니다.
이제 저장을 해야겠죠?😊
redis
에 저장하기 위한 방법은 두 가지가 존재합니다.
- RedisRepository
- RedisTemplate
RedisRepository
는 도메인 객체(Entity)를 Redis Hash
로 저장할 수 있습니다.
RedisTemplate
는 RedisRepository
처럼 도메인 객체를 저장할 수도 원하는 타입(String, Set, Hash 등)을 저장할 수도 있습니다.
더 유연한 것이죠!
저희는 현재 도메인 객체를 저장하는 용도가 아니라 Session
저장소로써 redis
를 사용하고자 하므로 RedisTemplate
을 사용하면 될 것 같네요.
다시 위의 코드를 살펴봅시다.
@Bean
public RedisTemplate<String, Object> redisTemplate() {
final RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(lettuceConnectionFactory());
template.setDefaultSerializer(new StringRedisSerializer());
return template;
}
저는 String
타입의 key와 Object
타입의 value를 템플릿으로 지정하였습니다.
그 이유는 저희가 spring security
를 통해 spring session
을 사용하고 있기 때문인데요.
결과적으로 클라이언트가 로그인에 성공했을 시 redis
에 저장될 값은 아래와 같습니다.
spring:session:sessions:expires:(session id)
==> 해당 세션의 만료 키- 저장될 값 타입 :
String
- 저장될 값 타입 :
spring:session:expirations:(expire time)
==> expire time에 삭제될 세션 정보(만료되면 해당하는 세션 정보 삭제)- 저장될 값 타입 :
Set
- 저장될 값 타입 :
spring:session:sessions:(session id)
==> 세션 생성 시간, 마지막 세션 조회 시간, 최대 타임아웃, 해당 세션에 저장한 데이터- 저장될 값 타입 :
Hash
- 저장될 값 타입 :
이렇게 저장될 값 타입이 각자 다르기 때문에 Object
로 지정했습니다.
다음으로 template
에 위에서 만든 ConnectionFactory
를 넣어주고, DefaultSerializer
를 통해 key
와
value
에 사용할 역/직렬화를 StringRedisSerializer
로 사용하도록 하였습니다.
여기까지가 기본 설정이지만, 저희는 한 단계가 더 남았죠!
org.springframework.session:spring-session-data-redis
앞서 얘기했듯이 저희는 spring session
을 사용하고 있기 때문에 spring session
이 redis
에 저장될 수 있도록 설정을 해줘야 합니다.
위에서는 spring session
을 저장하기 위한 사전 작업이었던 것이죠!
이 또한, Spring의 고도화된 추상화 덕분에 설정 몇 줄을 추가하는 것으로 끝이 납니다.
spring:
session:
store-type: redis
끝입니다! 😉😉 (진짜에요..)
이제부터 우리가 Spring Bean
으로 등록한 ConnectionFactory
를 사용하여 redis
에 접근하며 지정된 template
로 spring session
이 저장될 것입니다.
저희 서버에 성공적으로 배포되어 세션 클러스터링이 적용된 모습입니다.
이제부터는 별도의 외부 서버에 존재하는 redis
에 세션이 저장될 것이며 두 대의 내부 서버는 이 세션을 공유하게 되었습니다! 😀
'Spring' 카테고리의 다른 글
yml에서 List Object 사용법 (0) | 2022.04.29 |
---|---|
@ModelAttribute와 @RequestBody 그리고 Setter (4) | 2021.11.24 |
패키지 구조 설계 (0) | 2021.07.17 |
Thymeleaf와 Spring (0) | 2021.07.04 |
Spring MVC의 HiddenMethod 기능 사용하기 (0) | 2021.06.21 |