서버 한 대로 잘 돌던 주문 서비스가 트래픽이 늘어 인스턴스를 2대로 늘렸다. 그런데 새로고침할 때마다 로그인이 풀린다는 문의가 들어온다. 세션과 장바구니를 서버 메모리에 들고 있었기 때문이다. 로드밸런서에 sticky session을 걸어 같은 사용자를 같은 인스턴스로 보낼지, 세션을 Redis로 빼서 어느 인스턴스든 같은 요청을 받게 할지 정해야 한다.
언제: 거의 항상 기본. 세션, 장바구니, 진행 중인 주문·offer 상태를 전부 Redis나 DB에 두면 어느 인스턴스든 같은 요청을 처리할 수 있다. 배포는 인스턴스를 그냥 갈아끼우면 되고, 스케일아웃은 대수만 늘리면 되고, 한 대가 죽어도 사용자는 아무것도 못 느낀다.
비용: 요청마다 Redis/DB 왕복이 붙어 수 ms의 지연이 추가되고, 상태 저장소가 새로운 단일 장애점이 된다(Redis가 죽으면 전원 로그아웃). 운영할 인프라가 하나 더 늘고, 갱신이 아주 잦은 상태는 외부 저장소 쓰기 비용이 만만치 않다.
언제: 상태가 연결 자체에 붙어 있어 밖으로 뺄 수 없을 때 — WebSocket 실시간 협업·게임 룸, 제조 설비 프로토콜 세션(장비별 시퀀스 번호, 연결 핸들) 같은 경우. 또는 상태 접근이 연결당 초당 수십 회로 너무 잦아서 외부 저장소 왕복 자체가 병목일 때.
비용: 배포·축소 때마다 그 인스턴스의 상태가 같이 날아가서 드레이닝, 재접속, 상태 핸드오프 설계가 따라온다. 한 대 장애는 곧 그 인스턴스에 붙은 사용자 전원의 상태 소실이다. LB가 부하를 못 섞어 인스턴스 간 쏠림이 생기고, 오토스케일링이 사실상 무력화된다.
기본은 stateless 앱 + 상태는 Redis/DB다. sticky session은 당장 편해 보여도 배포·장애·스케일링 비용을 뒤로 미루는 것뿐이라, 세션부터 Redis로 빼는 쪽을 먼저 한다. 특히 offer 상태 전이 같은 비즈니스 상태는 처음부터 DB에 둔다 — 인스턴스 메모리에 두면 배포하는 순간 진행 중이던 흐름이 증발한다. stateful은 WebSocket이나 설비 세션처럼 상태가 연결에 붙어 있거나, 상태 접근 빈도가 외부 저장소로 감당이 안 되는 게 숫자로 확인될 때만, 그 계층 하나만 얇게 분리해서 허용한다.
- 상태 저장소 왕복이 누적돼 p99의 절반 이상을 차지할 때 — 예: p99 200ms 중 100ms가 요청당 Redis 왕복 5회의 합. 먼저 왕복 횟수를 줄이고, 그래도 안 되면 그 경로만 인메모리 검토
- 연결 하나가 초당 10회 이상 상태를 갱신(게임 틱, 설비 100ms 주기 신호) — 매번 외부에 쓰면 저장소 쓰기가 먼저 무너진다. 연결에 붙은 상태는 인스턴스에 두고 주기적 스냅숏만 외부로
- sticky를 이미 쓰고 있다면: 인스턴스 간 트래픽 편차가 30% 이상 벌어지고 스케일아웃해도 새 인스턴스로 부하가 안 옮겨감 — stateful의 비용이 청구되기 시작했다는 신호
- 배포할 때마다 '로그인이 풀려요' 문의가 몰림 — 상태가 인스턴스 메모리에 있다는 증거, 즉시 Redis로 외부화
🔧Redis + Spring Session (세션 외부화)JWT (stateless 인증 토큰)AWS ALB sticky session (쿠키 기반)Kubernetes Deployment vs StatefulSetgraceful shutdown + connection draining
“I default to stateless services with state in Redis or Postgres; I only go stateful for connection-bound, latency-critical paths.”
checking microphone…