pile·
백엔드·여기어때 (GC컴퍼니)여기어때 (GC컴퍼니)·

트랜잭션 스크립트에서 숙소 메타 + 가격 계산 모듈로 — 전시 아키텍처 개선기 (2/3)

여기어때 전시개발팀이 숙소 상세(PDP) API를 해부한 결과, 코드상으로는 DB 호출 3번처럼 보이던 요청이 실제로는 MongoDB $lookup 체인으로 컬렉션을 19회 접근하는 구조였다. 이 트랜잭션 스크립트 방식의 핵심 문제는 "aggregation이 I/O를 가린다"는 점으로, 독립적인 쿼리 10개가 단일 파이프라인에 직렬화되어 병렬화 기회를 잃고, 가격 때문에 거의 안 바뀌는 이미지까지 매 요청마다 읽어야 하는 읽기 증폭이 발생했다. V3에서는 "조회 시점 조립"을 "쓰기 시점 사전 조립"으로 전환하고, 화면별로 복제되던 가격 계산 로직을 goodsprice 단일 모듈로 수렴했다. 4개 API(PLP/PDP/RDP/ILP)의 반복 마이그레이션은 Claude Code skill로 절차를 고정하고 쉐도잉 + 동일성 검증으로 안전망을 마련하는 방식으로 진행됐다.

핵심 포인트
  • V2 PDP: $lookup 파이프라인 2개로 컬렉션 19회 접근, 독립 쿼리들이 직렬 실행되어 I/O 합산 지연 발생
  • 읽기 증폭 구조: 가격 데이터가 캐싱 병목이 되어 이미지 등 정적 데이터까지 매 요청마다 디스크 재조회
  • V3 해결: 읽기 최적화 문서를 쓰기 시점에 미리 조립, 조회는 ID 기반 단건/IN 쿼리로 단순화
  • goodsprice 모듈화: roomprice/policy/coupon/commission 4개 서브모듈로 가격 로직 단일화, 화면 간 불일치 구조적 방지
  • Claude Code skill 기반 마이그레이션: 6단계 고정 워크플로우 + 쉐도잉 + 운영 트래픽 동일성 검증으로 AI 코드 생성의 안전망 확보
  • 트레이드오프 명확화: 조회 단순화를 얻은 대신 쓰기/동기화 복잡도, 계층 복잡도, 팀 인지 비용을 새로 떠안음
상세 정리
  • V2 aggregation 문제 1 — 직렬화된 쿼리 묶음: $lookup 내 서브 파이프라인의 join 조건이 베이스 문서 필드가 아닌 외부 파라미터라, 실제로는 독립 쿼리 10개를 MongoDB 안에서 순차 실행한 것
  • V2 aggregation 문제 2 — 중복 I/O: 쿠폰 컬렉션을 사용일 조건만 다르게 파이프라인 내 2회 조회; 애플리케이션에서 한 번 읽어 분기하면 될 작업
  • V2 aggregation 문제 3 — 단일 거대 문서: 연박 조회 시 판매가 데이터가 객실 수×박수만큼 중첩, BSON 16MB 제한을 의식할 수준까지 팽창
  • V2 aggregation 문제 4 — 캐시 전략 불가: 변동 주기가 다른 데이터(이미지 vs 가격)가 한 파이프라인에 묶여 가장 자주 바뀌는 데이터 기준으로 전체 I/O 증폭
  • V2 분기 폭발: 카테고리(4종)×숙박형태(단박/연박)×화면 변형마다 aggregation 메서드 복제, PDP 하나에 파이프라인 10개 × 약 1,600줄 JSON
  • V3 읽기 최적화 문서: properties/rate plan/product 단위로 화면 읽기 패턴에 맞게 사전 조립, 적재 파이프라인이 조립 책임 인수
  • 숙소 메타 모듈 캐시 전략: 거의 안 바뀌는 숙소 메타는 Cache-Aside로 길게, 요금제/상품은 Cache-First로 짧게, 다건 조회는 애플리케이션에서 배치 병렬 실행
  • 가격 정확성 회복: V2는 무거운 조회 탓에 계산된 가격을 Redis 캐싱(정확성 훼손), V3에서는 조회가 가벼워져 요청마다 실시간 계산 가능
  • goodsprice 구조: roomprice(객실 정상가)/policy(특가 정책)/coupon(쿠폰 판정)/commission(수수료) 4개 서브모듈, JSON 파이프라인 대신 자바 코드로 이전되어 단위 테스트 가능
  • Composer 패턴: 화면 API는 조합만 담당, V2의 10벌 파이프라인 분기가 Composer 선택 한 곳으로 수렴
  • Claude Code skill 6단계: V2 분석 → 마이그레이션 Plan(사람 리뷰) → V3 구현 → 테스트 → 쉐도잉(운영 트래픽 복제, 응답은 V2) → 동일성 검증(V2/V3 응답 비교)
  • 안전망의 핵심: "AI가 코드를 잘 짜서"가 아니라 운영 트래픽 전수 검증이 있었기 때문에 코드 작성자와 무관하게 정확성 보장 가능
  • V3 새로 떠안은 복잡도: 이벤트 기반 동기화 파이프라인(유실/순서 역전 대응), 문서 갱신-캐시 무효화 타이밍 조정, 계층 추적(Dispatcher→Composer→메타모듈→캐시→문서), 팀 전체 새 구조 온보딩
왜 읽나MongoDB $lookup 과다 사용과 트랜잭션 스크립트 패턴에서 읽기 최적화 문서 + 도메인 모듈화로 전환하는 실전 과정을, I/O 병목 진단부터 Claude Code 기반 안전한 마이그레이션까지 단계별로 따라갈 수 있다.
여기어때 (GC컴퍼니)
여기어때 (GC컴퍼니) 블로그
원문은 여기서 이어서 읽을 수 있어요
원문 읽기
읽음 (0)

이 글과 비슷한

  1. 백엔드·무신사 테크무신사 테크·

    의심했던 범인은 알리바이가 있었다.

    무신사 물류기술실 WMS팀이 Jenkins에서 Spring Batch 배치 작업 실행 시 5~12분간 hang이 발생하는 문제를 Java Flight Recorder(JFR)로 추적한 디버깅 사례다. 콘솔 로그 상 'Creating AWSLogs Client' 직후 침묵이 이어져 AwsLogsAppender가 범인으로 의심됐지만, JFR 분석 결과 실제 원인은 Aurora DB에 대한 N+1 쿼리 138회 반복이었다. 통합 쿼리로 개선 후 단건 평균 처리 시간이 41.2초에서 30초 수준으로 줄었고 hang은 완전히 사라졌다.

    #profiling#aurora#spring-batch+2