[Redis] Redis에 로그인 Session정보를 저장하여 사용하기 (세션 불일치 해결)

서버가 한대일 경우에는 해당 서버에 세션 정보를 저장해서 사용할 수 있겠지만, 대용량 트래픽을 고려해 Scale-out이 적용된 환경에서는 세션 불일치 문제가 발생할 수 있다.

Scale-out은 여러 대의 서버로 트래픽을 분산하기 때문에 로드 밸런싱이 필수로 적용되는데,

이 로드 밸런싱으로 인한 분산 처리 과정에서 서버마다 가지고 있는 세션 저장소에 있는 세션을 공유하지 않기 때문에 세션 불일치 문제가 발생할 수 있다.

이런 세션 불일치 문제가 발생하면 새 요청을 할 때마다 로그인을 해야하는 아주 좋지 않은 사용자 경험을 발생시킬 것이다.

 

세션 불일치 문제를 해결하기 위한 방법으로 아래 3가지 방법들이 있다.

  • Sticky Session
  • Session Clustering
  • Session Storage

이 중 Redis를 Session Storage로 활용하여 세션을 저장하는 방법을 사용할 예정이다.


Session storage 방식

세션 불일치 문제를 해결하기 위한 방법 중 하나인 Session Storage에 대해 간단히 설명하자면

각각의 서버에 세션 정보를 저장하는 것이 아닌, 외부에 세션 저장소를 두고 이 세션 저장소에 모든 세션 정보를 저장하는 방식이다.

서버가 늘어나도 외부 저장소의 정보만 각각의 서버에 입력해주면 데이터를 읽어올 수 있다.

그렇기 때문에 특정 서버로 트래픽이 몰리는 문제가 발생하지 않으며, 세션이 재설정되어도 세션 저장소에 있는 데이터만 수정하면 되어 WAS간의 네트워크 통신이 필요하지 않다.

즉, 하나의 독립된 저장소에서 세션을 공유하므로 대규모 클러스터 환경에서 성능을 향상시킬 수 있다.


Redis를 세션저장소로 선택한 이유

기존에는 세션 저장소를 JDBC로 하고 있었다.

spring.session.store-type=jdbc

그 이유는 설정이 아주 간단했고, 다른 세션 저장소에 대하 알고 있던게 없기 때문이였다.

하지만 이번에 Redis를 프로젝트에 적용하면서 세션 저장소를 인메모리DB인 Redis로 변경한 이유는 다음과 같다.

 

jdbc -> redis 변경 이유

jdbc로 세션 저장소를 사용할 경우 위처럼 프로퍼티에 설정 값만 입력해주면 DB에 아래의 두 테이블이 생성된다.

하지만 이 방식은 설정이 간단하지만 로그인 요청마다 DB I / O 요청이 빈번히 발생해 성능 문제를 일으 킬 수 있다. (해당 방법은 로그인 요청이 많이 없는 백오피스, 사내시스템에서 주로 사용)

 

key-value 형식의 인메모리 DB로 메모리에 저장하여 jdbc 보다 빠르게 세션 데이터 접근 및 업데이트가 가능하다.

다만, 인메모리 DB는 서버가 다운되면 해당 서버가 갖고 있는 정보가 유실된다는 문제점이 있다.

그럼에도 불구하고, 인메모리 DB의 종류인 Redis와 Memcached 중에서 Redis를 선택한 이유는 Redis는 영속성을 보장하기 때문에 선택하게 되었다.


Redis를 세션 저장소로 설정하기

Redis를 세션 저장소로 설정하는 방법은 매우 간단하다.

나는 테스트 개발 환경으로 임베디드 Redis를 사용하여 세션 저장소를 설정하였는데 실제 서비스로 사용하기 위해서는 외부 메모리 서버가 필요하다.

 

라이브러리 설치
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
implementation 'org.springframework.session:spring-session-data-redis'

 

application.properties 설정
# Redis Setting
redis.host=localhost
redis.port=6379

spring.session.store-type=redis

 

이걸로 설정은 끝났다.

이제 서비스에 로그인을 하고 명령어 프롬프트에서 redis-cli를 입력하고 keys * 를 입력하면 세션 정보가 저장되어 있는 것을 확인할 수 있다.

  • spring:session:sessions:(session id) = 세션 정보. (hash타입)
  • spring:session:sessions:expires:(session id) = 세션 만료 키. (string타입)
  • spring:session:expirations:(expire time) = 만료시간에 삭제될 세션 정보. (set타입)