규모가 커져 서버가 여러 개가 된다면, 세션을 어떻게 관리할 수 있을까요?

다중 서버 환경에서 세션을 관리하는 방법은 크게 Sticky Session, 세션 클러스터링, 외부 세션 저장소 세 가지가 있으며, 서비스 규모와 요구사항에 따라 선택합니다.

문제 상황

클라이언트 → 로드밸런서 → 서버A: 로그인 → 세션 생성 (메모리에 저장)
클라이언트 → 로드밸런서 → 서버B: 마이페이지 → 세션 없음 → 로그인 풀림 X

각 서버는 자신의 메모리에만 세션을 저장하므로
다른 서버로 요청이 가면 세션을 찾을 수 없음

해결 방법 1: Sticky Session

로드밸런서가 같은 클라이언트의 요청을 항상 같은 서버로 고정하는 방식입니다.

클라이언트A → 로드밸런서 → 항상 서버1
클라이언트B → 로드밸런서 → 항상 서버2
클라이언트C → 로드밸런서 → 항상 서버3

구현은 보통 로드밸런서가 쿠키 또는 IP 해싱을 사용합니다.

# Nginx 설정 예시 — IP Hash 기반 Sticky Session
upstream backend {
    ip_hash;
    server 192.168.0.1:8080;
    server 192.168.0.2:8080;
    server 192.168.0.3:8080;
}
장점단점
구현이 가장 단순특정 서버에 트래픽 집중 (불균형)
기존 코드 변경 불필요서버 장애 시 해당 서버의 모든 세션 유실
Scale-Out의 이점이 반감

해결 방법 2: 세션 클러스터링

서버 간에 세션 데이터를 복제하여 모든 서버가 동일한 세션을 보유하는 방식입니다.

All-to-All 복제

서버A ←복제→ 서버B
  ↕            ↕
서버C ←복제→ 서버D

모든 서버가 모든 세션을 보유
→ 어디로 요청이 가도 세션 조회 가능 O
→ 서버 N대 → 세션 1개당 N-1번 복제 필요

Primary-Backup 복제

세션 생성 → 서버A(Primary) + 서버B(Backup)만 보유
→ 복제 대상이 줄어 네트워크 부담 감소
→ Primary + Backup 동시 장애 시 유실 가능
<!-- Tomcat 세션 클러스터링 설정 -->
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster">
    <Manager className="org.apache.catalina.ha.session.DeltaManager"
             expireSessionsOnShutdown="false"
             notifyListenersOnReplication="true"/>
</Cluster>
장점단점
서버 장애 시에도 세션 유지서버 수 증가 시 복제 비용 기하급수적 증가
어떤 서버든 처리 가능메모리 사용량 N배
대규모 환경에 부적합

해결 방법 3: 외부 세션 저장소 (가장 권장)

세션을 서버 메모리가 아닌 Redis 같은 외부 저장소에 중앙 집중하는 방식입니다.

서버A ─┐
서버B ─┼─→ Redis (세션 저장소)
서버C ─┘

어떤 서버로 요청이 가든 Redis에서 세션 조회 O
서버 추가/제거가 자유로움 O
// Spring Boot + Redis 세션 저장소
// build.gradle
implementation 'org.springframework.session:spring-session-data-redis'
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
# application.yml
spring:
  session:
    store-type: redis
    timeout: 1800  # 30분
  redis:
    host: redis-server
    port: 6379
// 기존 세션 코드 변경 없이 그대로 동작
@PostMapping("/login")
public String login(HttpSession session) {
    session.setAttribute("loginMember", member.getId());
    // → Redis에 자동 저장됨
    return "ok";
}

@GetMapping("/mypage")
public String mypage(HttpSession session) {
    Long memberId = (Long) session.getAttribute("loginMember");
    // → Redis에서 자동 조회됨
    return "mypage";
}
Redis 내부 구조:
┌─────────────────────────────────────────────────┐
│ Key (Session ID)     │ Value                     │
├─────────────────────────────────────────────────┤
│ session:abc123       │ {loginMember: 1}          │
│ session:def456       │ {loginMember: 7}          │
└─────────────────────────────────────────────────┘
장점단점
서버 확장 자유로움Redis 장애 시 전체 세션 영향
서버 장애 시에도 세션 유지네트워크 I/O로 인한 약간의 지연
기존 코드 변경 최소Redis 인프라 관리 필요

Redis 장애 대응은 Redis Sentinel(자동 장애 복구) 또는 Redis Cluster(분산 구성) 로 해결합니다.

세 가지 방식 비교

항목Sticky Session세션 클러스터링외부 세션 저장소
세션 위치각 서버 메모리모든 서버 메모리Redis 등 외부
서버 확장제한적복제 비용 증가자유로움 O
장애 대응세션 유실복제본으로 복구Redis HA로 대응
구현 난이도가장 쉬움중간쉬움 (Spring Session)
적합 규모소규모소~중규모중~대규모 O

실무에서의 선택 흐름

소규모 (서버 2~3대)
→ Sticky Session으로 충분

중규모 (서버 5~10대)
→ Redis 세션 저장소 도입

대규모 (서버 수십~수백 대)
→ Redis 세션 저장소 + Redis Cluster
   또는 JWT 기반 인증으로 전환하여 세션 자체를 제거

면접 포인트

CSLOG에서 보기