본문 바로가기
카테고리 없음

[#15] 다중 서버 환경에서 로그인 정보는 어디에 저장할까?

by 풍댕이 2026. 1. 23.

이 글은 세션 방식에 대해 다룹니다.

크게 많이 사용하는 로그인 방식으로는

  • 세션 방식
  • 토큰 방식

세션 방식은 보통 서버에 로그인 정보를 저장합니다.

 

Scale-out을 하기 전에는 한 대의 WAS 서버로 세션을 처리했습니다.

하지만 서버의 대수를 늘린 후에는 세션을 어느 서버에 저장할 것인지 이슈가 발생합니다.
만약 1번 서버에 어떤 사용자가 세션을 저장하고 E-Book을 구매하는 Request가 2번 서버로 전달된다면 2번 서버에서는
이 사용자의 세션이 없기 때문에 로그인이 유지되지 않는 문제가 발생합니다. 따라서 이러한 Session 정합성 문제를 해결해야 합니다.

Session 정합성 문제를 해결하기 위해 고려한 방법

1. Sticky Session

어떠한 사용자의 세션이 1번 서버에서 생성되었다면 이 사용자의 Request는 1번 서버로만 보내지는 방식입니다.

이러한 방법은 로드밸런서에 의해 이루어집니다. 세션이 만료되기 전까지 A 사용자의 세션이 생성된 서버로 로드밸런스가 A 사용자의 요청을 리다이렉트합니다.

위 그림은 request를 아무 서버에서나 보내지만 스티키세션이 적용된 밑 그림은 request를 정해진 서버로만 보냅니다.

 

스티키세션의 단점

  • 특정 사용자의 세션은 한 서버에 의존하고 있기 때문에 특정 서버의 트래픽이 집중된다면 장애가 발생할 수 있습니다.
    • 서버의 대수가 많고 다른서버가 여유롭더라도 트래픽이 몰린 서버로만 요청을 보내야하는 경우가 생길 수 있기 때문입니다.
  • 하나의 서버에 문제가 발생했을 시, 그 서버에 저장된 세션 정보들이 분실될 수도 있고 그동안 그 서버에 저장된 세션을 이용하지 못할 수 있습니다.

2. Tomcat에서 지원하는 Session Clustering

세션 클러스터링 방식은 여러대의 WAS가 있어도 동일한 세션으로 관리하여 Sticky Session의 단점을 극복했다는 장점이 있습니다.

 

Session Clustering이란?

Session clustering은 WAS가 2대 이상 설치되어 있을 경우 모든 세션 정보를 여러대의 서버에 다 가지고 있는 것입니다.
따라서 세션이 변경 될 때 마다 세션정보를 모든 다른 서버에도 저장시킵니다. 즉 밑 그림에서처럼 1번서버에 세션이 생성되면 2번, 3번 서버에도 그 세션 정보를 저장시키는 것입니다. Tomcat의 deltamanager라는 이름의 all to all 방식이 이 방식에 해당합니다.

세션 클러스터링의 단점

  • 모든 서버에 세션 정보를 다 저장해야하기 때문에 서버 메모리의 비효율이 생깁니다.
  • 또한 세션 정보를 추가해야할 때마다 모든 서버에 세션 정보를 다 추가해야하기 때문에 모든 서버에 네트워크 요청을 해야하므로 많은 네트워크 요청이 발생합니다.
  • 이러한 특징때문에 세션 클러스터링 정보는 성능에서 비효율적인 방식일 수 있습니다.

3. 세션서버를 레디스에 따로두어 세션 스토리지를 관리하는 방법

레디스는 Inmemory DB이며 Session Storage로 사용될 수 있습니다. 서버에 세션 정보를 저장하는 것이 아닌
외부에 레디스 서버를 띄우고 이 서버에 모든 세션 정보를 저장하는 것입니다. 즉 WAS 서버들이 레디스에서 세션 정보를 읽어오는 것입니다.

서버들끼리 네트워크 요청을 할 필요도 없고 서버를 stateless하게 유지할 수 있다는 점에서 세션 클러스터링 방식의 단점을 극복한 방식입니다.

또한 한 서버에 문제가 생겨도 외부에 세션정보를 저장하여 서버 장애 문제를 극복하고 한대의 서버에 트래픽이 몰릴일이 없어졌기 때문에 스티키 세션의 방법을 극복한 방식입니다.

  • 대규모 트래픽을 처리해야하는 현대 웹 시스템에서 Stateless가 압도적으로 유리한 이유
    • Stateful(상태 유지) : 서버가 유저의 정보를 자기 메모리에 들고 있다면, 그 유저는 반드시 자기를 기억하는 그 서버로만 접속해야 합니다. (이걸 Sticky Session이라고 합니다.) 서버 한 대가 터지면 그 서버에 있던 유저들은 모두 로그아웃됩니다.
    • Stateless(무상태) : 서버는 아무것도 기억하지 않습니다. 대신 유저가 누구인지 알 수 있는 정보(세션 ID 등)를 공용 저장소(Redis)에서 꺼내옵니다. 어떤 서버로 접속해도 똑같은 서비스를 받을 수 있습니다. 서버를 10대, 100대로 늘리기(Scale-out)가 매우 쉬워집니다.

이러한 장점들이 있어 세션서버를 Redis에 따로두어 세션 스토리지를 관리하는 방식을 택했습니다.

실제로 session 정보를 Redis Session Storage로 관리하기

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

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

인메모리 DB란?

데이터 저장을 메모리에 의존하는 특수 제작된 데이터베이스입니다. 디스크, SSD에 저장하는 데이터베이스와는 다릅니다. In-memory 데이터 저장소는 디스크에 접근을 없애므로 최소한의 응답시간을 가지도록 설계되었습니다. 모든 데이터가 메인 메모리에 저장되기 때문에, in-memory 데이터베이스는 서버 실패 혹은 작업 도중 데이터를 유실 할 위험이 있습니다. In-memory 데이터베이스는 스냅샷을 통해 혹은 각각 작업을 디스크에 저장함으로 데이터를 영속화 시킬 수 있습니다.

 

캐시는 일반적으로 일시적인 데이터의 하위 집합을 저장하는 고속 데이터 저장 계층입니다. 따라서, 캐시를 이용한 데이터요청은 데이터가 저장된 저장소로 접근하는 것보다 훨씬 빠르게 제공됩니다. 캐싱으로 이전에 검색했거나 계산한 데이터를 효율적으로 재사용 할 수 있습니다. 캐시의 주된 목적은 느린 저장소 계층의 접근을 줄이고 데이터 성능을 향상시키기 위함입니다.

 

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

  • 로그인 요청마다 DB I/O 요청이 발생하여 성능 문제가 발생할 수 있습니다.
  • key-value 형식의 인메모리 DB로 메모리에 저장하여 jdbc보다 빠르게 세션 데이터 접근 및 업데이트가 가능합니다.

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

인메모리 DB의 종류인 Redis와 Memcached중에서 무엇을 선택할까?

Memcached와 Redis 공통점

  1. in-memory cache이다.
  2. key-value 저장소이다.(redis는 데이터 구조저장소 성격에 가까움)
  3. 데이터관리를 위해 NoSQL을 사용한다.
  4. RAM에 데이터를 보관한다.

Memcached와 Redis의 차이점

  • Memcached
    • 정적 데이터 캐싱에 효과적
      • HTML같은 작은, 정적 데이터를 캐싱할 때 효율적입니다.
    • 멀티 쓰레드 기능 지원
      • Memcached는 멀티쓰레드이기 때문에, Redis에 비해 스케일링에 유리합니다. 

 

그래도, 인메모리 DB의 종류인 Redis와 Memcached중에서 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타입)

https://github.com/f-lab-edu/book-community-service

 

GitHub - f-lab-edu/book-community-service: 책에 대한 정보를 공유하고 소통하는 커뮤니티 서비스입니다.

책에 대한 정보를 공유하고 소통하는 커뮤니티 서비스입니다. Contribute to f-lab-edu/book-community-service development by creating an account on GitHub.

github.com