본문 바로가기
Infra/MongoDB

MongoDB - (9) - 애플리케이션 설계(2)

by Inventer 2023. 4. 22.

 

연결된 포스팅이다 이전 글을 참고하라.

 

  1. 스키마 설계 고려 사항 - (현재지점)
  2. 데이터 embed 방식과 참조 방식 중 결정하기
  3. 최적화를 위한 팁
  4. 일관성 고려 사항
  5. 스키마 마이그레이션 방법
  6. 스키마 관리 방법
  7. 몽고 DB가 데이터 스토리지로 적합하지 않은경우

 

스키마 설계 패턴

아래와 같이 다양한 패턴이 존재한다.

  • 다형성 패턴(Polymorphic pattern)
  • 속성 패턴(Attribute pattern)
  • 버킷 패턴(Bucket pattern)
  • 이상치 패턴(Outlier pattern)
  • 계산된 패턴 (Computed pattern)
  • 서브셋 패턴(Subset pattern)
  • 확장된 참조 패턴(Extended Reference pattern)
  • 근사 패턴(Approximation pattern)
  • 트리 패턴(Tree pattern)
  • 사전 할당 패턴(Preallocation pattern)
  • 도큐먼트 버전 관리 패턴(Document versioning pattern)

 

기재한 모든 패턴마다 책에 있는 내용을 기술하고,

더불어 공식 홈페이지를 참고하여 자세한 사례를 기술한다.

 

 

다형성 패턴(Polymorphic pattern) - 몽고DB 공식 홈페이지 설명

컬렉션 내 모든 도큐먼트가 유사하지만, 동일하지 않은 구조를 가질 때 적합하다.

단일 컬렉션의 정보에 쿼리하는 경우 유용하다.

 

아래 그림을 보면 공통영역이 있고, Other sports, event 등으로 영역이 구분된다.

 

이는유사하지만, 동일하지 않은 구조를 의미한다.

 

따라서 도큐먼트 내에 차이점보다, 유사점이 많을 때 사용하는 패턴이다.

 

 

 

 

속성 패턴(Attribute pattern)

정렬을 위한 패턴,

 

유사한 필드가 많은 큰 도큐먼트가 있고,

공통 특성을 공유하는 필드 하위 집합도 존재.

이 때, 해당 필드의 하위 집합을 정렬하거나 쿼리하려고 할 때 유용

 

정렬해야 하는 필드는 문서의 작은 하위 집합에서만 찾을 수 있음

 

위 조건들이 충족해야 사용 가능

 

아래는 이해를 돕기위한 영화 컬렉션

 

현재 "릴리즈 날짜"를 검색하는 가정임

각 국 마다 release date를 기록해놓은 데이터가 있고

출시 날짜를 검색하려면 여러 필드를 한번에 살펴봐야함.

 

또한, 출시 날짜를 빠르게 검색하려면 영화 컬렉션에 복합 인덱스가 필요할 것,

인덱스 예시


{release_US : 1, release_KR : 1, release_Italy : 1}

 

이 때 속성 패턴을 사용하면 아래와 같이 정리할 수 있음.

따라서 위 데이터를 통해 인덱싱을 하면

위와 같은 결과로 정리하여 빠른 sorting을 지원

도큐먼트 당 많은 유사한 필드를 대상으로 문서를 더 쉽게 인덱싱할 수 있도록 구성

속성 패턴을 사용하면 더 적은 수의 인덱스가 필요하고

쿼리 작성이 더 간단해지고 쿼리 속도가 빨라짐.

 

버킷 패턴(Bucket pattern)

실시간 분석, 일반적인 시계열 데이터에 적합하다.

데이터를 함께 묶음으로서 특정 데이터 그룹을 더 쉽게 구성할 수 있다.

 

온도를 저장하는 센서는 아래와 같이 시간을 기준으로 온도를 기록한다.

이 때 우리는 평균 온도를 보고 싶다.

 

위 DB 설계는 굉장히 관계지향적인 접근이다.

애플리케이션이 확장함에 따라 모든 단일 측정에 대해 sensor_id로 인덱싱 해야할 일이 발생할 수 있다.

 

따라서 계산에 사용할 일부 필드를 미리 빼자.

생각보다 별거 없다.

하지만 해당 패턴은 이제 아래 이상치 패턴을 유심히 고려해야한다.

 

이상치 패턴(Outlier pattern)

 

온라인 서점을 운영한다고 해보자.

위와 같은 책 데이터가 하나의 도큐먼트로 존재할 것이다.

여기서 MongoDB는 16MB의 도큐먼트 크기 제한을 갖고있다.

근데 마침 베스트셀러라서 customer_purchased가 급증하면 어쩔 것인가?

 

이를 고려한게 아웃라이어 패턴이다.

일부 쿼리 수행등이 느려질 수 있지만 고려해야한다.

위처럼 has_extras를 통해 구매자의 배열 오버플로우를 측정할 수 있다.

 

 

계산된 패턴 (Computed pattern)

계산된 패턴은 응용프로그램에서 반복적으로 계산해야하는 데이터가 있을 때 활용한다.

즉 벡엔드를 담당하는 WAS(Web Application Server)에서 이를 퍼올려서 데이터를 계산하는 것이 아닌,

DB 자체에서 계산을 해서 보내는 방식이다.

 

자세한 데이터 사례는 존재하지 않지만

시스템이 동일한 계산을 반복적으로 수행하고 읽기 대비 쓰기 비율이 높을 때 계산된 패턴을 고려하라.

 

 

서브셋 패턴(Subset pattern)

RAM이 부족할 때 적용을 고려하는 패턴이다.

 

보통 쇼핑몰 상품에는 상품에 달린 댓글을 다 보여주지 않는다.

상위 10개만 최신 기준에 따라 보여주곤한다.

 

내가 주로 썻던 Spring Data JPA로 MySQL을 사용하여 이런 페이징 처리할일이 많았는데,

참 관계형에서는 N:1, N:M, 1:N에서 N 페이징 처리 등 어려운 상황이 많이 발생한다.

본 예시는 제품(1) : 리뷰(N) 을 저장하는 예시이다.

하지만 이처럼 하지말란다.

프로덕트와 리뷰 컬렉션으로 나누고,

프로덕트에 상위 10개의 최신 리뷰를 지속적으로 업데이트 하란다.

자주 접근하지 않는 이전 리뷰, 제품 이력 같은 경우를 리뷰 컬렉션으로 빼버리고

더보기 버튼을 누르면 제공하란다.

 

최고다.

 

실제로도, NoSQL을 고려할 때

에브리타임 등(불확실)에서

"대댓글"과 같은 N:M의 관계를 가질 수 있는 페이징 부분을

NoSQL로 구축했다고 알고있다.

 

결론은 문서 내부에 많은 양에 데이터가 있고, 거의 사용하지 않는 데이터일 때 분리하라.

라는 요점이다.

 

 

확장된 참조 패턴(Extended Reference pattern)

RDBMS 처럼 엔티티를 나눴고, JOIN이 필요한 경우에 JOIN 대신

위 서브셋 패턴처럼 일부 데이터를 한 컬렉션에서 저장하여 JOIN을 하지 않는 패턴이다.

이 때 데이터의 업데이트나 삭제 등 수정에 관련된 사항이 리소스를 많이 사용하니

email이나 user_id 처럼 거의 바뀌지 않는 데이터를 미리 복제해놓은 패턴이다.

 

 

위처럼 컬렉션이 존재할 때 특정 주문에 대해서 정보를 모아 쿼리해야 할 일이 생긴다.

이 때 커스터머 컬렉션은 변동이 적은 데이터이고, 이를 Order에 아래와 같이 함께 저장한다면

몽고 DB 입장에서 보다 쉬운 쿼리를 작성할 수 있다.

 

 

보통 N대 1 관계에 주로 사용한다.

조회 측면에서 필드를 식별하고 자주 엑세스하는 필드를 기본값으로 두어 성능을 향상시키는 방법이다.

하지만 데이터 복제라는 trade-off가 발생한다.

 

근사 패턴(Approximation pattern)

근사패턴은 리소스가 많이 드는 계산이 필요하지만, 높은 정확도가 반드시 필요하지는 않은 상황에 유용하다.

이미지나 게시글의 추천 수, 페이지 조회 수 등을 예로 들며 이때

근사 패턴을 적용해 추천이나 조회 수가 1회가 아니라 100회가 될 때마다 카운터를 갱신하면 쓰기 횟수를 줄일 수 있다.

 

더 자세한 예는 공식홈페이지를 참고하라.

 

트리 패턴(Tree pattern)

트리 형태를 가지는 계층적 구조 데이터에 어울리는 패턴이다.

 

위 그림은 직원 간 계층을 예시로 들었으며, report 방향은 노드의 구조를 나타낸다.

 

위 상위 노드가 있는 회사 구조 중 부모 구조를 MongoDB로 표현하면 아래와 같이 배열로서 표현된다.

 

하지만 회사 구조가 변경이 된다면 필요에 따라 업데이트 해야하는 단점이 있지만

쿼리시 항상 계신하지 않아도 된다는 장점에 비해서는 작은 비용이다.

 

 

 

사전 할당 패턴(Preallocation pattern)

영화관 좌석에 해당하는 컬렉션이 있다.

매 예약마다 컬렉션에 집어 넣는다면

NoSQL 의 특성상 아래 형태로 데이터가 저장이 될 것이다.

 

하지만 영화관 좌석은 2D array 형식으로 생겼다.

따라서 위 처럼 하나 들어올 때 마다 좌석을 만들지말고,

미리 2D Array 형태로 컬렉션을 만들고, 빈 값을 채워넣어 놓자는 의미이다.

 

도큐먼트 버전 관리 패턴(Document versioning pattern)

 

해당 패턴은 특정 시점 버전이 필요한 경우에 유용하다.

금융이나, 의료 산업에서는 특정 시점에 대한 자료만을 보존해야할 것이다.

 

아래는 현재의 최신 도큐먼트를 저장하고, 과거 도큐먼트를 보존하는 저장방식이다.

 

 

 

위에서 나뉜 현재 저장 도큐먼트와, 과거 작성했던 도큐먼트를 "사용자"로 구분지어 보관하는 개념이다.

current_policies collection은 각 사용자의 최신 도큐먼를 기록하고 있고,

revisions collection은 사용자가 작성했던 도큐먼트를 누적하는 방법으로 서술된다.

 

 

 

 

 

다음장 바로가기

https://inventer.tistory.com/30

 

 

댓글