규모가 커져 서버가 여러 개가 된다면, 세션을 어떻게 관리할 수 있을까요?
다중 서버 환경에서 세션을 관리하는 방법은 크게 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 기반 인증으로 전환하여 세션 자체를 제거
면접 포인트
- 세 가지 방식을 설명한 뒤, 실무에서는 Redis 외부 세션 저장소가 가장 보편적이라고 답하면 좋습니다.
- Spring 환경에서는
Spring Session + Redis조합으로 기존 코드 변경 없이 외부 세션 저장소를 적용할 수 있다는 점이 실무적 강점입니다. - 궁극적으로 세션 관리 부담 자체를 없애기 위해 JWT 기반 무상태 인증으로 전환하는 추세이며, 이 경우 세션 공유 문제 자체가 사라집니다.