Spring Session과 Redis를 활용한 세션 관리와 캐싱
웹 애플리케이션을 하나의 서버에서 운영할 때는 세션 관리가 비교적 간단하다. 하지만 서버가 여러 대로 늘어나면 사용자의 세션 정보를 어떻게 공유할 것인지에 대한 문제가 발생한다.
이번 글에서는 Spring Boot의 세션 관리부터 Sticky Session, Redis를 활용한 세션 공유, 그리고 Redis의 대표적인 캐싱 전략까지 정리해본다.
1. JSESSIONID와 HttpSession
일반적인 Spring Boot 애플리케이션에서 별도의 설정을 하지 않는다면 내장 Tomcat이 세션을 관리한다.
사용자가 처음 서버에 접근해 세션이 생성되면 서버는 사용자에게 JSESSIONID라는 값을 쿠키로 전달한다.
브라우저
│
│ 최초 요청
▼
Spring Boot / Tomcat
│
│ 세션 생성
▼
HttpSession
브라우저 ◀── JSESSIONID 쿠키 전달
이후 브라우저는 서버에 요청할 때 JSESSIONID 쿠키를 함께 전송한다.
Tomcat은 전달받은 JSESSIONID를 통해 해당 사용자의 세션을 찾아 사용한다.
즉,
JSESSIONID는 서버에 저장된 세션을 식별하기 위한 값이다.
여기서 주의할 점은 JSESSIONID 자체에 세션 데이터가 저장되는 것은 아니라는 것이다. 실제 세션 데이터는 서버에 저장되고, JSESSIONID는 해당 세션을 찾기 위한 식별자 역할을 한다.
2. 서버가 여러 대라면?
하나의 서버만 사용한다면 큰 문제가 없다.
하지만 서비스를 확장하여 다음과 같이 여러 서버를 사용한다고 생각해보자.
Load Balancer
/ \
/ \
Server A Server B
:8080 :8081
Session A Session B
사용자가 처음에는 Server A로 요청을 보내 세션을 생성했다고 가정한다.
그런데 다음 요청이 Server B로 전달된다면 문제가 발생한다.
Server A와 Server B가 각각 자신의 메모리에 세션 정보를 저장하고 있기 때문에 Server B는 Server A에서 만들어진 세션 정보를 알지 못한다.
따라서 여러 서버를 운영하는 환경에서는 세션 정보를 어떻게 관리할 것인지 고민해야 한다.
3. Sticky Session
이 문제를 해결하는 방법 중 하나가 Sticky Session이다.
Sticky Session은 Load Balancer가 특정 사용자의 요청을 처음 연결된 서버에 계속 전달하도록 하는 방식이다.
예를 들어 사용자의 첫 요청이 Server A로 전달되었다면 이후 요청도 계속 Server A로 전달한다.
사용자 A ──→ Load Balancer ──→ Server A
│
├──────→ Load Balancer ──→ Server A
│
└──────→ Load Balancer ──→ Server A
이렇게 하면 Server A가 가지고 있는 세션 정보를 계속 사용할 수 있다.
Sticky Session의 한계
하지만 Sticky Session에도 문제가 있다.
특정 서버에 많은 사용자가 연결되면 요청이 한쪽 서버에 집중될 수 있다.
사용자 그룹 A ──→ Server A 요청 적음
사용자 그룹 B ──→ Server B 요청 매우 많음
Server A가 여유로운 상태라고 하더라도 사용자 그룹 B의 요청은 계속 Server B로 전달되기 때문에 부하가 균등하게 분산되지 않을 수 있다.
또 다른 문제는 서버 장애다.
세션이 Server B의 메모리에만 저장되어 있는 상황에서 Server B에 장애가 발생하면 해당 서버가 가지고 있던 세션 정보에 접근할 수 없게 된다.
4. 세션 정보를 서버 밖에서 관리하기
이러한 문제를 해결하는 방법 중 하나는 세션 정보를 외부의 공용 저장소에 저장하는 것이다.
Load Balancer
/ \
/ \
Server A Server B
\ /
\ /
Redis
Session Data
Server A와 Server B가 자신의 메모리에 세션을 따로 관리하는 것이 아니라 공통된 저장소에 세션 정보를 저장한다.
따라서 사용자의 요청이
첫 번째 요청 → Server A
두 번째 요청 → Server B
세 번째 요청 → Server A
처럼 서로 다른 서버로 전달되더라도 두 서버 모두 같은 세션 저장소를 사용하기 때문에 세션 정보를 유지할 수 있다.
Spring에서는 Spring Session을 사용하여 Redis 등을 세션 저장소로 사용할 수 있다.
외부 저장소를 사용하면 네트워크 통신이 추가되기 때문에 서버 메모리에 직접 접근하는 것보다 비용이 발생한다. 따라서 빠른 읽기/쓰기가 가능한 Redis와 같은 인메모리 데이터 저장소가 세션 저장소로 많이 활용된다.
5. Cache란?
Cache(캐시)란 자주 사용하는 데이터를 빠르게 접근할 수 있는 곳에 임시로 저장해두는 공간이다.
예를 들어 매번 데이터베이스에 다음 요청을 한다고 생각해보자.
Client
↓
Spring
↓
RDB
↓
Spring
↓
Client
조회가 매우 빈번한 데이터라면 매번 데이터베이스를 조회하는 것은 비효율적일 수 있다.
이때 Redis를 캐시로 사용하면 다음과 같은 구조를 만들 수 있다.
┌── Redis (Cache)
Spring ───────┤
└── RDB (원본 데이터)
자주 조회되는 데이터를 Redis에 저장해두고 Redis에서 먼저 조회하면 데이터베이스의 부하와 응답 시간을 줄일 수 있다.
6. 캐싱(Caching)
캐싱은 자주 접근하는 데이터를 캐시에 저장하여 데이터 접근 속도를 높이고 원본 데이터 저장소의 부하를 줄이는 기법이다.
Redis는 데이터를 메모리에 저장하기 때문에 디스크 기반 데이터베이스보다 빠르게 데이터에 접근할 수 있어 캐시로 많이 사용된다.
다만 캐시는 기본적으로 언제든 사라질 수 있는 임시 데이터라고 생각하는 것이 좋다.
따라서 캐시에는 어떤 데이터를 저장할지, 얼마나 오래 저장할지, 언제 삭제할지 등을 결정하는 전략이 필요하다.
7. Cache Hit과 Cache Miss
캐시를 사용하면 크게 두 가지 상황이 발생한다.
Cache Hit
캐시에서 원하는 데이터를 찾은 경우다.
요청
↓
Cache
↓
데이터 존재!
↓
바로 반환
Cache Hit 비율이 높을수록 원본 데이터베이스에 접근하는 횟수를 줄일 수 있다.
Cache Miss
캐시에 원하는 데이터가 존재하지 않는 경우다.
요청
↓
Cache
↓
데이터 없음
↓
RDB 조회
이 경우 원본 데이터베이스에서 데이터를 가져와야 한다.
8. Eviction Policy
캐시는 메모리를 사용하기 때문에 데이터를 무한정 저장할 수 없다.
따라서 캐시 공간이 부족해지면 어떤 데이터를 제거할 것인지 결정하는 정책이 필요하다.
이를 Eviction Policy라고 한다.
Redis에서도 메모리가 설정된 한도에 도달했을 때 어떤 데이터를 제거할지 다양한 Eviction Policy를 설정할 수 있다.
9. 대표적인 캐싱 전략
Cache-Aside (Lazy Loading)
가장 대표적인 캐싱 전략 중 하나다.
데이터를 조회할 때 먼저 캐시를 확인한다.
데이터 조회
↓
Redis 확인
/ \
HIT MISS
↓ ↓
반환 RDB 조회
↓
Redis 저장
↓
반환
캐시에 데이터가 존재하면 바로 반환하고, 없다면 원본 데이터베이스에서 데이터를 가져온 후 캐시에 저장한다.
장점
- 실제로 요청된 데이터만 캐시에 저장할 수 있다.
- Cache Hit가 발생하면 빠르게 데이터를 조회할 수 있다.
단점
- 최초 요청은 Cache Miss이기 때문에 상대적으로 느리다.
- 원본 데이터가 변경되었는데 캐시가 갱신되지 않으면 오래된 데이터가 반환될 수 있다.
Write-Through
데이터를 작성할 때 캐시와 원본 저장소를 함께 갱신하는 방식이다.
데이터 변경
↓
Cache
↓
RDB
따라서 캐시와 원본 데이터의 일관성을 유지하기 쉽다.
장점
- 캐시와 원본 데이터의 일관성을 유지하기 쉽다.
- 조회 시 최신 데이터를 캐시에서 얻을 가능성이 높다.
단점
- 데이터를 저장할 때 캐시와 원본 저장소 모두에 쓰기 작업이 필요하다.
- 자주 조회되지 않는 데이터까지 캐시에 저장될 수 있다.
Write-Behind (Write-Back)
데이터를 우선 캐시에 기록하고, 일정 시간 또는 일정 조건에 따라 여러 변경 사항을 모아서 원본 데이터베이스에 반영하는 방식이다.
데이터 변경
↓
Cache
↓
일정 시간 후
↓
RDB
장점
- 쓰기 요청이 많은 환경에서 데이터베이스의 부하를 줄일 수 있다.
- 여러 쓰기 작업을 모아서 처리할 수 있다.
단점
- 캐시의 데이터가 데이터베이스에 반영되기 전에 장애가 발생하면 데이터가 유실될 위험이 있다.
정리
Spring Boot에서 기본적으로 세션은 Tomcat의 메모리에 저장된다. 단일 서버에서는 간단하지만 서버가 여러 대로 늘어나면 세션 공유 문제가 발생한다.
Sticky Session을 사용하면 사용자를 특정 서버에 고정할 수 있지만 부하 분산과 장애 대응 측면에서 한계가 존재한다.
이 때문에 여러 서버가 공통으로 접근할 수 있는 Redis 같은 외부 저장소에 세션을 저장하는 방법을 사용할 수 있다.
Redis는 세션 저장소뿐만 아니라 캐시로도 많이 사용되며, 캐시를 사용할 때는 단순히 데이터를 Redis에 넣는 것에서 끝나는 것이 아니라 Cache Hit/Miss, 데이터 일관성, TTL, Eviction Policy, Cache-Aside/Write-Through/Write-Behind 같은 전략을 함께 고려하는 것이 중요하다.
'심화_AI를 활용한 백엔드 아키텍처 심화 과정' 카테고리의 다른 글
| [내일배움캠프 사전캠프] 24회차 TIL(7/29 수) - RabbitMQ 구조 설계 및 이해, Kafka 개념 정리 (0) | 2026.07.29 |
|---|---|
| [내일배움캠프 사전캠프] 23회차 TIL(7/27 월) - 대규모 시스템 설계 (0) | 2026.07.27 |
| [내일배움캠프 사전캠프] 21회차 TIL(7/23 목) - Redis (0) | 2026.07.23 |
| [내일배움캠프 사전캠프] 20회차 TIL(7/22 수) - Docker, Docker-Compose (0) | 2026.07.22 |
| [내일배움캠프 사전캠프] 19회차 TIL(7/21 화) - Docker Image, Container (0) | 2026.07.21 |