DB를 덜 읽게 만들었는데, 사용자는 방금 바꾼 값이 안 보인다고 해요.지난 글에서는 복잡한 query를 어떻게 표현할지 봤어요. Querydsl, Specification,
@Query를 고르는 이유도 결국은 “DB에서 어떤 데이터를 어떻게 읽을까”였죠.
그런데 서비스를 운영하다 보면 query를 아무리 잘 써도 이런 순간이 와요.
“이 화면은 너무 자주 조회되는데, 매번 DB까지 가야 하나요?”그래서 cache를 붙여요. Redis를 넣고, 자주 읽는 값을 잠깐 보관하고, DB 부하를 줄여요. 또 서버가 여러 대가 되면 session도 Redis로 옮기고 싶어져요. 한 서버에만 로그인 정보가 있으면 load balancer 뒤에서 요청이 흔들릴 수 있으니까요. 처음에는 둘 다 비슷해 보여요.
- cache도 Redis에 저장해요.
- session도 Redis에 저장해요.
- 둘 다 TTL이 있어요.
- 둘 다 빠른 key-value 저장소를 써요.
이 글은 Spring Boot 4.0.3의 Redis cache auto-configuration, Redis 연결 설정, Spring Session Redis 문서를 기준으로 작성했어요. 핵심 모델은 Spring Boot 3.x 프로젝트에서도 비슷하게 읽을 수 있지만, starter 이름과 세부 property는 프로젝트가 쓰는 Spring Boot/Spring Session 버전 문서를 확인하세요.
Cache는 “정답”이 아니라 “다시 만들 수 있는 복사본”이에요
상품 상세 API가 있다고 해볼게요.“상품 정보는 자주 바뀌지 않으니까 Redis에 잠깐 넣어두면 되지 않을까요?”Spring Cache abstraction을 쓰면 method 결과를 cache에 넣는 흐름을 만들 수 있어요.
Redis CacheManager는 cache 이름과 key를 Redis key로 바꿔요
Spring Boot에서 Redis cache를 쓰려면 보통 Redis 연결과 cache provider가 준비되어야 해요. 개념적으로는 이런 설정이 들어가요.spring.data.redis.*는 Redis 서버에 어떻게 연결할지 말해요. spring.cache.*는 cache abstraction이 어떤 cache를 만들고 어떻게 보관할지 말해요.
Spring Boot는 Redis가 cache provider로 선택될 수 있으면 RedisCacheManager를 준비할 수 있어요. 이때 cache 이름과 method key가 합쳐져 Redis key가 돼요.
productDetail cache의 42와 categoryTree cache의 42가 같은 Redis key가 되면 안 되겠죠.
처음에는 property로 충분한지 먼저 보세요. 모든 cache에 같은 TTL을 둘 수 있고, 기본 직렬화 전략을 그대로 써도 된다면 별도 configuration class를 크게 만들 필요가 없어요.
반대로 cache마다 TTL이 다르거나, JSON 직렬화 방식을 명확히 고정해야 하거나, key prefix 정책을 프로젝트 규칙으로 잡아야 한다면
RedisCacheConfiguration을 직접 다루는 단계로 넘어가요.
Cache bug의 절반은 “언제 지울지”에서 나와요
Cache를 붙이면 읽기는 빨라질 수 있어요. 하지만 쓰기가 들어오는 순간 질문이 바뀌어요.ProductDetail이 남아 있으면 어떻게 될까요? 사용자는 수정했는데 화면에는 예전 이름이 보일 수 있어요.
이 장면이 cache invalidation이에요. Cache에 값을 넣는 것보다 “언제 버릴지”가 더 어렵다는 말이 여기서 나와요.
Spring Cache abstraction에서는 보통 이런 Annotation을 만나요.
TTL은 안전망이지 정답이 아니에요. “10분 뒤에는 알아서 사라져요”는 “10분 동안은 틀린 값을 보여줄 수 있어요”와 같은 말일 수 있어요.
Session은 cache보다 사용자 상태에 가까워요
이번에는 로그인된 사용자를 생각해볼게요.HttpSession 저장 위치를 Redis 같은 외부 저장소로 바꿔주는 역할을 해요. Spring Boot와 함께 쓰면 보통 session timeout과 Redis session namespace 같은 설정을 보게 돼요.
Session은 “cache처럼 빠르게 넣어두는 값”이 아니에요. 사용자가 지금 로그인되어 있는지, 장바구니를 어떤 방식으로 들고 있는지, OAuth2 login 상태를 어떻게 이어갈지 같은 흐름과 연결돼요.
Redis 하나를 같이 써도 key 공간은 나눠야 해요
작은 프로젝트에서는 Redis 하나에 cache와 session을 같이 넣을 수 있어요. 하지만 같은 Redis를 쓴다는 말이 같은 key 정책을 써도 된다는 뜻은 아니에요. 이 그림처럼 물리적으로는 Redis 하나여도 논리적으로는 key 공간을 나눠서 봐야 해요. Cache는 cache name과 prefix로, session은 namespace로 나누는 식이에요. 실무에서는 아래 질문을 먼저 확인해요.- cache와 session이 같은 Redis database를 써도 되나요?
- 운영에서 cache 전체 삭제를 해도 session은 남아야 하나요?
- session key를 지워야 하는 장애 대응과 cache key를 지워야 하는 장애 대응이 다르지 않나요?
- Redis memory eviction policy가 session까지 밀어내지는 않나요?
- cache TTL과 session timeout이 서로 다른 의도로 관리되고 있나요?
Cache를 붙이기 전에 “느린 이유”를 먼저 확인해요
Redis는 빠르지만, Redis를 붙인다고 모든 성능 문제가 좋아지는 건 아니에요. 예를 들어 목록 API가 느린 이유가 N+1 query라면 cache로 잠깐 가릴 수는 있어요. 하지만 cache miss 때마다 여전히 느린 query가 터지고, 데이터가 자주 바뀌면 cache hit rate도 낮아요. 또 key가 사용자별, 권한별, 검색 조건별로 갈라지면 cache entry가 폭발할 수 있어요.
처음에는 “어디에 cache를 넣을까?”보다 “어떤 응답이 반복되고, 원본은 어디서 느리고, 틀린 값을 얼마나 오래 보여줘도 되는가?”를 먼저 물어보는 편이 좋아요.
실무 코드 리뷰에서는 이 냄새를 먼저 봐요
Redis cache와 session은 붙인 순간부터 운영 도구가 돼요. 코드 리뷰에서는 Annotation이 있는지보다 경계를 먼저 봐야 해요.
디버깅할 때는 질문을 이렇게 바꿔보세요.
- 이 응답은 DB에서 온 값인가요, cache에서 온 값인가요?
- cache key에 모든 요청 조건이 들어 있나요?
- 이 값을 바꾸는 쓰기 path는 어떤 cache를 지우나요?
- TTL 동안 틀린 값을 보여줘도 괜찮은 데이터인가요?
- Redis에 같은 prefix의 key가 얼마나 쌓이고 있나요?
- session timeout과 cache TTL을 서로 다른 의도로 관리하고 있나요?
- Redis 장애 때 사용자는 느린 응답을 보나요, 실패를 보나요, 로그아웃을 보나요?
처음에는 여기까지만 잡아도 충분해요
오늘 내용을 한 장으로 줄이면 이 흐름이에요. 이 그림의 핵심은 Redis 도입보다 데이터의 의미를 먼저 나누는 거예요. 다시 만들 수 있으면 cache 후보가 될 수 있고, 사용자의 현재 상태라면 session 경계와 timeout을 따로 봐야 해요. 그래서 Redis를 붙일 때는 항상 이렇게 물어보세요.“이 값은 없어져도 되는 복사본인가요, 아니면 사용자의 현재 상태인가요?”이 질문 하나가 cache TTL, invalidation, session timeout, Redis 분리 전략을 한 줄로 연결해줘요.
참고한 링크
- Spring Boot Reference: Caching
- Spring Boot Reference: Redis
- Spring Session Reference: HttpSession with Redis
- Spring Session Reference: Redis Configuration
자, 정리해볼까요?
- Cache는 원본 데이터의 빠른 복사본이고, 사라져도 다시 만들 수 있어야 해요.
- Spring Boot의 Redis cache는
RedisCacheManager, cache name, key prefix, TTL 설정을 중심으로 읽으면 돼요. - Cache의 핵심 위험은 값을 넣는 순간보다 stale data를 언제 지울지에서 나와요.
- Session은 cache보다 사용자 상태에 가까워요. 사라지면 사용자는 로그아웃되거나 흐름을 잃을 수 있어요.
- Cache TTL과 session timeout은 서로 다른 설정이고, 같은 Redis를 쓰더라도 key prefix와 namespace를 나눠야 해요.
- Redis memory, eviction, 장애 대응은 cache와 session에서 서로 다른 사용자 증상으로 나타나요.
- Redis를 붙이기 전에는 반복 조회, 원본 query 성능, key 설계, invalidation, 운영 runbook을 같이 확인해야 해요.