#Backend

데이터 통합— MongoDB 원칙으로 document를 통합하고 동기화를 재설계하다 (3/3)

데이터 통합— MongoDB 원칙으로 document를 통합하고 동기화를 재설계하다 (3/3)
01

Summary

역정규화의 함정을 깨부수다: 여기어때의 MongoDB 스키마 통합 및 동기화 생존기

1:1 파편화에서 도메인 기반 통합으로, 전체 동기화 1시간을 10분으로 단축한 MongoDB 최적화 레시피

이 아티클은 여기어때 전시개발팀이 대용량 전시 데이터 조회 속도를 끌어올리기 위해 MongoDB 데이터 스키마를 고도화한 여정을 다룹니다. 단순히 문서를 합치는 것에 그치지 않고, 그에 따라 무거워진 쓰기 부하를 해결하기 위해 필드 단위 부분 갱신과 비동기 캐시 갱신 파이프라인을 재설계한 구체적인 해결책을 담았습니다. 최종적으로 무중단 마이그레이션 전략을 통해 시스템 안정성과 성능을 모두 확보한 실무 노하우를 공유합니다.

  • 01RDB 구조를 무비판적으로 MongoDB에 1:1 이식하는 안티패턴과 Aggregation 조인 비용 문제 극복
  • 02MongoDB의 핵심 원칙인 '애플리케이션 쿼리 기준 스키마 모델링' 및 '역정규화' 적용 과정
  • 03문서 전체를 덮어쓰는 대신 변경된 중첩 필드만 콕 집어 업데이트하는 필드 단위 부분 갱신 설계
  • 04서로 다른 데이터 출처를 가진 동기화 주체들이 충돌 없이 하나의 문서를 업데이트하는 협업 구조
  • 05전체 동기화 소요 시간을 1시간에서 10분으로 83% 이상 단축시킨 성능 개선 성과

RECOMMENDATION

MongoDB 도입 후 조인(Join) 성능 문제나 대대적인 데이터 동기화 지연을 겪고 있는 백엔드 엔지니어들에게 권장합니다. 특히 Read 최적화를 위한 역정규화 설계 시 발생할 수 있는 Write 병목을 해결하는 현실적인 동기화 아키텍처 힌트를 얻을 수 있습니다.

The Problem

기존 v1 구조에서 RDB 테이블과 MongoDB 컬렉션을 1:1 매핑하면서, 조회 시 수십 개의 컬렉션을 Aggregation하는 과정에서 심각한 성능 저하가 발생했습니다. 이를 해결하기 위해 도메인 단위로 문서를 통합(v2)했으나, 데이터의 국소적인 변경 시에도 큰 문서 전체를 통째로 다시 써야 하는 새로운 쓰기 성능 병목에 직면했습니다.

The Solution

조회 성능 향상을 위한 도메인 통합 구조를 유지하면서 쓰기 비용을 줄이기 위해, 필드 단위 부분 갱신(Partial Update) 방식을 도입하고 공용 저장 함수를 통해 실제 변경된 필드만 $set 및 $unset으로 업데이트하도록 동기화를 재설계했습니다. 또한, 이종 데이터 소스별로 갱신 필드 역할을 분리하고, 변경 사항을 DB에 쓴 즉시 비동기 이벤트를 발행하여 하위 Redis 캐시를 최신화하는 구조를 설계했습니다.

The Result

동기화 시 여러 컬렉션을 분산 갱신하던 부하가 안정화되었으며, 전체 동기화 소요 시간이 기존 1시간에서 10분 수준으로 대폭 단축되었습니다. v1과 v2를 병행 운영하는 이중 적재 및 수동 청크 동기화 시스템을 통해 서비스 장애 없이 안전하게 데이터 구조를 전환했습니다.

Trade-off

Read 성능을 극대화하기 위해 역정규화를 선택한 대가로, Write 동기화 로직의 복잡도가 크게 증가했습니다. 특히 부분 갱신을 지원하기 위해 복잡한 공용 변환 로직이 필요해졌으며, DB 저장 후 Redis 캐시를 갱신하기 위한 비동기 이벤트 발행 단계가 추가되어 아키텍처적 관리 포인트가 늘어났습니다.

03

Key Concepts

Concept · 01

Query-Based Modeling

관계형 데이터베이스의 정규화 패턴과 달리, 애플리케이션의 조회(Read) 패턴과 쿼리 성능 향상을 최우선으로 고려하여 데이터 구조를 역정규화하는 NoSQL 스키마 설계 기법입니다.

  • v1의 1:1 파편화된 테이블 구조에서 벗어나 조회 패턴에 맞게 도메인 단위로 문서를 묶는 v2 구조의 근간이 되었습니다.
  • 한 숙소에 연관된 객실, 이미지, 정책 등의 데이터를 단일 혹은 소수의 결합된 문서로 통합 설계했습니다.
Concept · 02

Field-level Partial Update

문서 전체를 덮어쓰지 않고 변경 사항이 있는 특정 중첩 필드만 부분적으로 업데이트하는 기술로, 대형 문서의 직렬화 비용과 쓰기 I/O를 대폭 줄여줍니다.

  • 공용 저장 함수를 통해 객실의 가격 등 국소적인 변경 시 해당 필드만 $set 연산자로 갱신하도록 처리했습니다.
  • 데이터가 소실되거나 비어 버린 부모 객체에 대해서는 $unset 연산자를 활용하여 정합성을 정밀하게 제어했습니다.
Concept · 03

Dual Write Migration

기존 시스템(Legacy)과 신규 시스템을 동시에 가동하여 변경 사항을 양쪽에 모두 적재하고 점진적으로 트래픽 비중을 전환하는 안전한 마이그레이션 기법입니다.

  • v1 스키마와 v2 스키마를 동시 적재 상태로 유지하면서 데이터의 누락 및 동기화 검증을 무장애 상태에서 진행했습니다.
  • 수동 청크 동기화 툴을 결합하여 부분 정합성 오차를 잡아가며 다이얼을 돌리듯 단계적으로 서비스 비중을 전환했습니다.