여기어때 전시개발팀은 ES 단일 대문서 → MongoDB v1 RDB 1:1 파편화 → v2 도메인 단위 통합이라는 세 차례 구조 전환을 거쳐 전체 동기화 시간을 약 1시간에서 10분으로 단축했다. 이 글은 3부작의 마지막으로, v2 통합 문서 구조에 맞춰 "$set/$unset 필드 단위 부분 갱신 + 이벤트 발행" 기반 동기화를 어떻게 재설계했는지 구체적인 MongoDB 패턴과 함께 설명한다.
핵심 포인트- MongoDB 원칙 "Model your schema according to your application's queries"를 따라 RDB 1:1 컬렉션(v1)에서 도메인 단위 통합(v2)으로 전환하여 동기화 시간 1시간→10분 단축
- 역정규화(Read 최적화)의 대가는 Write 비용 증가 — `$set/$unset` 부분 갱신 + `ordered:false bulkWrite`가 필수 짝
- 같은 문서를 출처가 다른 두 동기화(객실/숙소)가 각자 담당 필드만 갱신해 서로 간섭 없이 공유
- 변경 이벤트 논블로킹 발행으로 Redis 캐시를 최신화하는 "저장 → 알림" 패턴 추가
- v1·v2 병행 운영으로 기존 경로 유지하며 비중을 단계적으로 이행
상세 정리- ES판: 한 숙소 모든 정보를 문서 하나에 담아 수십 MB 거대 문서 → 직렬화/전송 느림
- v1: RDB 테이블 구조를 MongoDB에 1:1 매핑해 수십 개 컬렉션 → 조회마다 aggregation join 비용 (MongoDB 공식 안티패턴)
- v2: 함께 읽히는 데이터를 도메인 단위로 묶어 소수 컬렉션, 16MB 제한 고려해 도메인별 문서 분리
- 공용 저장 함수: 변환 로직 중앙화 → 각 동기화는 "갱신할 필드 목록"만 전달
- 부분 갱신 패턴: `$set: {"rooms.$[room].price": nextPrice}` + 부모 객체 비면 `$unset`으로 명시적 제거
- `bulkWrite(ops, {ordered: false})`: N건 한 번에 묶어 처리, 한 건 실패해도 나머지 처리 계속
- 증분 동기화(이벤트 기반)와 수동 동기화(API 트리거, 청크 단위) 명확히 분리; 수동 동기화는 대상 도메인 선택 가능
- 변경 이벤트 메시지: 변경 키 목록, 도메인 종류, 변경 유형(생성·수정/삭제) 포함
- 발행 실패는 동기화를 막지 않음(논블로킹), 로깅·알림으로만 처리
왜 읽나MongoDB 역정규화 설계 도입 시 불가피한 쓰기 비용을 필드 단위 부분 갱신과 이벤트 발행 패턴으로 제어하는 실전 설계를 배울 수 있다.