Redis 세션 스토어
Redis 세션 스토어 (Session store)
무상태(stateless) 애플리케이션 서버들 사이에서 사용자별 세션 상태(로그인 컨텍스트, 장바구니, 환경설정)를 스티키 세션이나 DB 왕복 없이 공유하는 세션 저장 패턴입니다. Redis 해시로 세션을 저장하고 TTL로 자동 만료시킵니다.
언제 세션 스토어를 쓰는가
무상태 애플리케이션 서버들 사이에서 사용자별 세션 상태를 스티키 세션이나 DB 왕복 없이 공유해야 할 때 사용합니다.
왜 이 문제가 어려운가
HTTP는 무상태이므로 요청 사이에 재방문 사용자를 인식하려면 외부 상태에 의존해야 합니다. 대표적인 접근법에는 심각한 단점이 있습니다:
- 개별 앱 서버에 세션 저장: 스티키 라우팅이 필요해 핫스팟이 생기고 장애 조치가 불가능해집니다.
- 세션 읽기를 관계형 DB로 이동: 요청당 5~20ms가 추가됩니다. 동시 사용자가 수천 명이면 세션 읽기가 커넥션 풀을 지배합니다. 모든 페이지 로드가 경합점이 되어 다른 워크로드의 주 DB도 저하시킵니다.
세션은 외부 스윕(sweep) 작업 없이 자동 정리가 필요합니다. 세션 유실 시 직접적인 비즈니스 비용(버려진 장바구니, 강제 재인증, 중단된 결제)이 발생하므로 순수 캐싱보다 내구성이 더 중요합니다.
운영 규모에서는 여러 세션을 대상으로 쿼리도 해야 합니다(예: 리콜된 제품을 담은 모든 장바구니 찾기, 테넌트별 세션 수 세기). 이는 단순히 개별 세션 읽기보다 복잡합니다.
Redis 솔루션에서 기대할 수 있는 것
- 스티키 세션 제거 — 로드 밸런서 뒤에서 어떤 인스턴스든 어떤 사용자든 서빙
- 정리 작업·DB 스윕 없이 비활성 세션 자동 만료
- 전체 세션을 재직렬화하지 않고 개별 세션 필드 업데이트
- 사용자당 여러 기기 세션 추적(전체 로그아웃 포함)
- 키 스캔 없이 운영·보안 작업을 위한 활성 세션 간 쿼리
- 구성 가능한 내구성으로 배포·노드 재시작에도 세션 데이터 유지
Redis가 이 솔루션을 어떻게 지원하는가
실제로 각 세션은 Redis 해시(세션 ID당 하나의 해시)로 저장되고, 키는 자동 만료되도록 설정되어 비활성 세션이 외부 작업 없이 정리됩니다.
- Hashes로 전체 세션 블롭을 역직렬화하지 않고 필드 수준 세션 접근
EXPIRE+ 슬라이딩 TTL — 매 요청마다 리셋되어 활성 세션은 유지되고 비활성 세션은 자동 정리- Sets(
SADD,SMEMBERS)로 사용자당 모든 세션 추적 → 다중 기기 관리(DEL+SREM으로 명시적 로그아웃·전체 로그아웃) - AOF·RDB persistence로 만료 창 내에서 프로세스·노드 재시작에도 세션 생존
- Redis Search를 통한 보조 인덱싱(키가 아닌 필드 값으로 조회)으로 런타임 크로스 세션 쿼리(영향 받은 장바구니 찾기, 테넌트별 세션 수 세기)를 키 스캔 없이 지원
- 대부분 스택에서 이미 같은 인스턴스에 있는 Redis의 요청 경로 서브 밀리초 대기 시간
에코시스템
- Java: Spring Session Data Redis
- Node.js:
connect-redis(express-session 스토어) - Python: Flask-Session, django-redis
- API 게이트웨이: Kong, Envoy(Redis 기반 세션·토큰 저장)
더 알아보기 (Learn more)
- Redis 세션 스토어를 직접 만드는 코드 예제: redis-py, node-redis, go-redis, Jedis, Lettuce, StackExchange.Redis, Predis, redis-rb, redis-rs — 각 라이브러리용 실행 가능한 예제(기본 로컬 웹 서버 포함).
- Redis 영속성·백업 — AOF/RDB로 세션 생존 보장.
- Redis 메모리 레이어 — 세션 스토어가 아닌 에이전트형 장기 메모리와의 차이.