문제 발생

상품 상세 페이지는 풀 캐싱(Full Caching) 전략을 적용하기 어렵다는 근본적인 문제가 있었다. 일반적인 전시(GNB, 카테고리) 페이지는 주로 상품 목록이나 정적 데이터를 보여주기 때문에 Redis나 Caffeine 풀 캐싱으로 빠르게 응답할 수 있다.

하지만 상세 페이지는 다르다.

  • 로그인 사용자마다 달라지는 개인화 정보(좋아요 여부, 편성 알람 여부, 배송지 기반 도착 가능 여부 등)
  • 시점별로 달라지는 가격/프로모션 정책(시간제 쿠폰, 청구 할인 등)이 실시간 반영되어야 함
  • 재고 수량은 조회 시점 기준 최신 데이터가 보장되어야 하는 상황이 있음

단순히 캐시된 상품 데이터만 내보내면 사용자 경험이 무너지고, 잘못된 가격·재고 노출로 비즈니스 리스크가 발생한다.


원인 파악

1. 개인화 데이터의 존재

로그인 여부에 따라 노출 정보가 달라지고, 사용자별 배송지 기반 판단이 필요하다.

2. 복잡한 로직의 결합

가격 정책, 프로모션, 혜택 여부 등은 DB에서 최신성을 보장해야 하므로 단순 캐싱이 불가능하다.

3. 실시간성 요구

재고 수량은 초 단위로 변할 수 있으며, 잘못된 데이터 제공은 구매 실패로 이어질 수 있다.


해결

STEP 기반 로직을 설계해 데이터 성격별로 DB와 캐시를 분리했다.

STEP 1 — 로그인 사용자 전용 데이터 (무조건 DB)

좋아요 여부, 편성 알람 여부, 배송지 기반 내일배송 가능 여부 등 사용자별로 다른 데이터는 항상 DB에서 조회한다.

STEP 2 — 프로모션 여부 (무조건 DB)

시간제 쿠폰, 청구 할인 등 자주 변경되는 가격·혜택 정보는 항상 DB에서 최신값을 가져온다.

STEP 3 — 상품 기본 정보 (CACHE 활용)

상품 상세, 기본 가격, 브랜드, 옵션 정보 등 변동 주기가 긴 데이터는 Redis 캐시를 사용한다.

STEP 4 — 데이터 조합/필터링 (Java 로직)

STEP 1~3에서 가져온 데이터를 합쳐 최종 응답 구조를 생성한다. 비회원의 경우 해당 step이 최소화되어 더 빠른 응답이 가능하다.

STEP 5 — 재고 수량 최신화 (DB or CACHE 선택)

옵션 재고는 Redis 캐시에 저장되지만, 필요 시 실시간 DB 조회로 보정 가능하도록 ON/OFF 설정을 제공한다. 특정 이벤트의 경우 재고 수량이 중요하지 않은 상황(충분한 재고 + 유저 경험이 더 중요)이 있어 분기 처리가 가능하도록 설계했다.

STEP 6 — 추천 상품 조회 (DB)

사용자 이력 기반 DAP 추천 데이터. 추후 비동기 호출로 전환 예정이다.


검증

  • 캐시 가능한 데이터(상품 기본 정보)는 Redis를 통해 빠르게 제공 → 응답 속도 단축
  • 반드시 최신성이 필요한 데이터(프로모션, 재고)는 DB 조회로 보장 → 데이터 정합성 유지
  • Java 레이어에서 데이터 조합을 수행해 API 응답 구조의 일관성을 확보
  • 재고 조회 방식(DB vs Redis)을 설정값으로 분리해 운영 상황에 맞는 선택이 가능

실제 트래픽 환경에서 검증 결과, 평균 응답 속도는 개선되면서도 데이터 오류는 크게 감소했다.


효과 / 깨달음

  • 캐싱과 DB 조회를 적절히 혼합해 응답 속도와 정합성을 동시에 확보할 수 있었다.
  • 상품 상세 페이지처럼 개인화와 실시간성이 필요한 경우, 풀 캐싱 전략은 불가능하다는 것을 명확히 확인했다.
  • 단순히 캐시 비중을 늘리는 것이 아니라, 데이터 성격에 따라 캐시/DB를 구분하는 것이 핵심이다.
  • Java 레이어에서 조합/필터링을 수행하는 구조가 유지보수성에도 유리하다.

추후 개선 사항

  • 추천 상품 영역은 화면 단에서 비동기 호출로 전환해 첫 로딩 속도를 추가 단축
  • 프로모션/혜택 영역도 단기 캐싱(수 초 단위) 적용 가능 여부 검토
  • 불변 객체 패턴(Immutable Object) 도입으로 데이터 조합 과정의 안전성 강화
  • Redis 캐시 TTL 정책을 상품 속성별로 세분화해 캐시 효율 극대화