티스토리 뷰

DB/MongoDB

MongoDB

oneny 2025. 10. 6. 20:59

MongoDB

프로젝트 초기 설계 당시에는 어떤 DB를 사용하는지 결정하게 된다. 이때 시스템의 특성과 요구사항에 따라 관계형 데이터베이스 대신 NoSQL 데이터베이스를 채택하는 주된 이유는 다음과 같다.

  • 대규모 데이터셋이나 매우 높은 쓰기 처리량 달성을 관계형 데이터베이스보다 쉽게 할 수 있는 뛰어난 확장성의 필요
  • 관계형 모델에서 지원하지 않는 특수 질의 동작
  • 관계형 스키마의 제한에 대한 불만과 더욱 동적이고 표현력이 풍부한 데이터 모델에 대한 바람

NoSQL 데이터베이스는 이러한 요구사항에 따라 아래와 같이 크게 4가지 유형으로 구분된다. 이 중에서 MongoDB는 문서 지향(Document-oriented) 데이터베이스의 대표적인 예로 다양한 형태의 데이터를 유연하게 저장하고 확장할 수 있는 기능을 제공한다.

  • Key-Value Store(키-값 저장소)
    • 데이터를 고유한 키(Key)와 그에 대응하는 값(Value)의 쌍으로 저장하는 단순한 구조로 단순한 조회/캐시에 적합하다.
    • 대표적으로 Redis, AWS DynamoDB 등이 있다.
  • Document Store(문서 지향 데이터베이스)
    • 데이터를 문서(Document) 단위로 저장하며 각 문서는 JSON, BSON, XML 등의 스키마리스(Schemaless) 구조를 가진다.
    • 대표적으로 MongoDB, ElasticSearch 등이 있다.
  • Column-Family Store(열 기반 데이터베이스)
    • 데이터를 행(Row)이 아닌 열(Column) 중심으로 저장하는 방식으로 열 단위로 데이터를 묶어 저장하여 분석/집계 작업에 유리하다.
    • 대표적으로 Apache Cassandra, HBase 등이 있다.
  • Graph Database(그래프 데이터베이스)
    • 각 데이터를 노드(Node)는 엔터티(사람, 상품 등)으로, 엣지(Edge)는 관계(친구, 구매 등) 형태로 저장하여 관계 중심 질의(Relationship Query)가 매우 빠르다.
    • 대표적으로 Neo4j, ArangoDB 등이 있다.

 

MongoDB 특징

몽고DB는 관계형 데이터베이스(relational database)가 아니라 문서 지향 NoSQL 데이터베이스(document-oriented database)로, JSON과 유사하지만 효율적이고 더 많은 타입을 지원하는 BSON 문서에 데이터를 저장하여 스키마 유연성과 개발 생산성을 제공한다. 이러한 몽고DB는 다음 세 가지 큰 특징이 있다.

  • 개발 친화적인 데이터베이스
  • 쉬운 분산 확장
  • 유연한 스키마 구조

몽고DB는 내장 도큐먼트와 배열을 허용함으로써 문서 지향 모델은 복잡한 계층 관계(hierarchical relationship)를 하나의 레코드로 표현할 수 있다. 이 방식은 최신 객체 지향 언어를 사용하는 개발자의 관점에 매우 적합한 개발 친화적인 데이터베이스라고 할 수 있다.

몽고DB에서는 도큐먼트의 키와 값을 미리 정의하지 않는다. 따라서 고정된 스키마가 없으므로 필요할 때마다 쉽게 필드를 추가하거나 제거할 수 있다. 덕분에 개발 과정을 빠르게 반복할 수 있어 개발 속도가 향상되고, 서비스 요구사항 변화나 기능 확장에도 유연하게 대응할 수 있다.

몽고DB는 분산 확장을 염두에 두고 설계됐다. 도큐먼트 지향 데이터 모델은 데이터를 여러 서버에 더 쉽게 분산하게 해준다. 도큐먼트를 자동으로 재분배하고 사용자 요청을 올바른 장비에 라우팅함으로써 클러스터 내 데이터 양과 부하를 조절할 수 있다.

 

몽고DB 기본 개념

몽고DB의 기본 개념을 간략히 설명하면 다음과 같다.

  • 몽고DB 데이터의 기본 단위는 도큐먼트이며, 이는 관계형 데이터베이스의 행과 유사하다(하지만 더 다양한 자료 표현이 가능하다).
  • 같은 맥락에서 컬렉션(collection)은 동적 스키마(dynamic schema)가 있는 테이블과 같다.
  • 몽고DB의 단일 인스턴스는 자체적인 컬렉션을 갖는 여러 개의 독립적인 데이터베이스를 데이터베이스를 호스팅한다.
  • 모든 도큐먼트는 컬렉션 내에서 고유한 특수키인 "_id"를 가진다.
  • 몽고DB는 몽고 셸(The mongo Shell)이라는 간단하지만 강력한 도구와 함께 배포된다. mongo 셸은 몽고DB 인스턴스를 관리하고 몽고DB 쿼리 언어로 데이터를 조작하기 위한 내장 지원을 제공한다. 또한 사용자가 다양한 목적으로 자신의 스크립트를 만들고 로드(load)할 수 있는 완전한 기능의 자바스크립트 해석기(Javascript Interpreter)다.

 

도큐먼트

몽고DB의 핵심은 정렬된 키와 연결된 값의 집합으로 이뤄진 도큐먼트다. 도큐먼트 표현 방식은 프로그래밍 언어마다 다르지만 대부분의 언어는 맵(map), 해시(hash), 딕셔너리(dictionary)와 같이 도큐먼트를 자연스럽게 표현하는 자료구조를 가진다. 도큐먼트의 키는 문자열이다. 다음 예외 몇 가지를 제외하면 어떤 UTF-8 문자든 쓸 수 있다.

  • 키는 \0(null 문자)을 포함하지 않는다. \0은 키의 끝을 나타내는 데 사용된다.
  • .과 $ 문자는 몇 가지 특별한 속성을 가지며 특정 상황에만 사용해야 한다. 이 문자들은 보통 예약어(reserved word)로 취급해야 하며 부적절하게 사용하면 드라이버에서 경고가 발생한다.

 

컬렉션

컬렉션은 도큐먼트의 모음이다. 몽고DB의 도큐먼트가 관계형 데이터베이스의 행에 대응된다면 컬렉션은 테이블에 대응된다고 볼 수 있다.

컬렉션은 동적 스키마를 가진다. 하나의 컬렉션 내 도큐먼트들이 모두 다른 구조를 가질 수 있다는 의미다. 하지만 인덱스를 만들려면 도큐먼트는 특정 구조를 가져야 한다. 이러한 인덱스는 컬렉션별로 정의한다. 같은 유형의 도큐먼트를 하나의 컬렉션에 넣음으로써 컬렉션을 효율적으로 인덱싱할 수 있다.

서브컬렉션(subcollection)의 네임스페이스(namespace)에  .(마침표) 문자를 사용해 컬렉션을 체계화한다. 예를 들어, 블로그 기능이 있는 애플리케이션은 blog.posts와 blog.authors라는 컬렉션을 가질 수 있다. 이는 단지 체계화를 위함이며 blog 컬렉션이나 자식 컬렉션(child collection)과는 아무런 관계가 없다.

 

 

스키마 설계와 데이터 모델링

 

RDBMS 한계

과거에는 주로 MySQL, Oracle, PostgreSQL과 같은 관계형 데이터베이스, 즉 RDBMS를 사용했다. 이런 데이터베이스들은 테이블 형태를 구성하고 데이터를 저장한다.

소셜미디어의 급격한 성장으로 관리해야 되는 데이터가 급증하게 되면서 다양한 데이터를 관리하고, 구조가 매우 복잡해지게 구성이 될 수 밖에 없어졌다. 사용자마다 다른 형태의 정보를 가져와야 하는 경우도 있고, 데이터 간의 관계도 되게 복잡해지기 때문에 RDBMS와 같은 구조화된 형식은 한계가 되게 명확했다. 또한, 정해진 틀에서 데이터가 저장되는 형태이기 때문에 스키마 변경이 어려워 다양한 데이터들을 수용하기에는 큰 어려움이 있다.

그리고 수평적인 확장이 어렵다. MySQL 같은 경우에는 클러스터 형태로 관리되는 형태가 아니기 때문에 데이터의 확장에 있어 좀 더 큰 어려움이 있다. 마지막으로 복잡한 데이터 구조를 표헌하기에 적합하지 않다. 

 

몽고DB를 위한 스키마 설계

# 사용자 컬렉션의 사용자 문서 예시
{
    "_id": "5ef2d4b45b7f11b6d7a",
    "user_id": "Sherlock Holmes",
    "age": 40,
    "address": {
        "Country": "England",
        "City": "London",
        "Street": "221B Baker St."
    },
    "Hobbies": ["violin", "crime-solving"]
}

{
    "_id": "6ef8d4b32c9f12b6d4a",
    "user_id": "John Waston",
    "age": 45,
    "address": {
        "Country": "England",
        "Street": "221B Baker St."
    },
    "Medical license": "Active",
    "Job": "Software Engineer"
}

몽고DB는 기존 관계형 데이터베이스의 접근 방식과는 다른 모델링 전략이 요구된다. 이러한 전략적 변화는 각 애플리케이션의 고유한 데이터 활용 패턴을 고려하여 이루어져야 한다.

효과적인 몽고DB 설계의 핵심은 사용자의 데이터 조회 요구사항을 정확히 파악하는 것이다. 이는 시스템 엔티티의 구조를 결정하는 데 결정적인 역할을 한다. 관계형 데이터베이스가 정규화를 중시하고 데이터 중복을 지양하는 것과 달리, 몽고DB는 성능 최적화와 유연성 확보를 위해 의도적으로 데이터 중복과 비정규화를 활용한다.

몽고DB의 문서 모델은 독특한 강점을 제공한다. 하나의 컬렉션 내에서도 각 문서는 서로 다른 구조를 가질 수 있으며, 같은 필드명이라도 다른 데이터 타입을 포함할 수 있다. 위 사용자 컬렉션의 두 문서를 확인하면 기본적인 구조는 유사하지만, 세부적인 내용에서 차이를 보이는 것을 확인할 수 있다.

 

몽고DB의 데이터 타입

 

기본 데이터형

몽고DB는 도큐먼트의 값으로 기본 데이터형부터 날짜, 배열 등 다양한 데이터형을 지원한다. 

타입 표현 설명
null {"x": null} null 값과 존재하지 않는 필드를 표현하는 데 사용한다.
불리언 {"x": true} 참과 거짓 값에 사용한다.
숫자 {"x": 3.14}, {"x": 3}
{"x": NumberInt("3")}
{"x": NumberLong("3")}
셸은 64비트 부동소수점 수를 기본으로 사용한다.
4바이트 혹은 6바이트의 부호 정수(signed integer)는 각각 NumberInt 혹은 Number 클래스를 사용한다.
문자열 {"x": "foobar"} 어떤 UTF-8 문자열이든 문자열형으로 표현할 수 있다.
날짜 {"x": new Date()} 몽고DB는 1970년 1월 1일부터의 시간을 1/1000초 단위로 64비트 정수로 날짜를 저장한다. 표준 시간대(time zone)은 저장하지 않는다.
정규 표현식 {"x": /foobar/i} 쿼리는 자바스크립트의 정규 표현식 문법을 사용할 수 있다.
배열 {"x": ["a", "b", "c"]} 값의 셋(set)이나 리스트(list)를 배열로 표현할 수 있다.
내장 도큐먼트 {"x": {"foo": "bar"}} 도큐먼트는 부모 도큐먼트의 값으로 내장된 도큐먼트 전체를 포함할 수 있다.
객체 ID {"x": ObjectId()} 객체 ID는 도큐먼트용 12바이트 ID다.
이진 데이터   이진 데이터는 임의의 바이트 문자열이며 셸에서는 조작이 불가능하다. 이진 데이터는 데이터베이스에 UTF-8이 아닌 문자열을 저장하는 유일한 방법이다.
코드 {"x": function() { /* ... */ }} 쿼리와 도큐먼트는 임의의 자바스크립트 코드를 포함할 수 있다.

몽고DB에서 도큐먼트는 자바스크립트 객체와 개념적으로 닮았다는 점에서 JSON과 닮았다고 할 수 있다. 하지만 데이터형이 null, 불리언, 숫자, 문자열, 배열, 객체만 지원하기 떄문에 JSON의 표현력은 제한적이여서 몽고DB는 JSON의 키/값 쌍 성질을 유지하면서 추가적인 데이터형을 지원한다. 각 데이터형 값을 표시하는 방식은 언어에 따라 다르지만, 위 목록은 흔히 지원되는 데이터형이 셸에서 어떻게 도큐먼트의 일부로 표현되는지 나타낸다.

 

_id와 ObjectId

몽고DB에 저장된 모든 도큐먼트는 "_id" 키를 가진다. "_id" 키 값은 어떤 데이터형이어도 상관없지만 "ObjectId"가 기본 데이터형이다. 하나의 컬렉션에서 모든 도큐먼트는 고유한 "_id" 값을 가지며, 이 값은 컬렉션 내 모든 도큐먼트가 고유하게 식별되게 한다.

ObjectId 클래스는 몽고DB의 분산 데이터베이스를 고려하여 설계됐다. 여러 서버에 걸쳐 자동으로 증가하는 기본 키를 동기화하는 작업은 어렵고 시간이 걸리기 때문에 샤딩된 환경에서 12 바이트 고유 식별자(unique identifier)로 생성된다. 생성 시점, 서버, 프로세스, 카운터 값을 조합해 전역적으로 중복이 거의 없도록 설계되어 정렬, 샤딩, 분산 환경에서 빠르고 안정적으로 유니크성을 보장할 수 있다.

ObjctId의 앞 9바이트는 1초 동안 여러 장비와 프로세스에 걸쳐 유일성을 보장한다. 마지막 3바이트는 단순히 증분하는 숫자로, 1초 내 단일 프로세스의 유일성을 보장한다. 고유한 ObjectId는 프로세스당 1초에 256^3(1677만7216)개까지 생성된다.

 

JSON과 BSON 차이와 활용

  JSON BSON
Encoding UTF-8 String Binary
Readability Humans and Machines Machines Only
Data Types String, Boolean, Number, Array String, Boolean, Number (Integer, Float, Long, Decimal128, ...), Array, Date, Raw Binary

JSON은 Key-Value 형태로 구성되어 일반적으로 사람이 읽고 쓰기 쉽게 구성이 되어 있고 기계가 해석하고 생성하기 쉬운 UTF-8 기반 데이터 교환 포맷이다. 문자열, 숫자, 객체 및 배열 형태 등 기본적인 타입들을 모두 지원하여 언어나 플랫폼에 관계없이 대중적으로 많이 사용하는 것이 장점이라고 할 수 있다. 하지만 JSON은 텍스트 기반이라는 특성상, 성능과 효율성 측면에서 한계가 존재하기 때문에 이러한 한계를 보완하기 위해 몽고DB는 BSON(Binary JSON)이라는 이진 형태의 직렬화 포맷을 내부적으로 사용한다.

BSON(Binary JSON)은 이진 형태로 직렬화된 데이터 포맷을 지원하여 몽고DB가 데이터를 저장하고 네트워크를 통해 전송할 때 사용하는 기본 데이터 표현 방식이다. 또한, 텍스트 기반의 JSON 보다 날짜, 정수, 이진 데이터 등 다양한 타입을 지원하면서 바이너리 포맷이기 때문에 JSON에 비해 직렬화/역직렬화가 더 빠르고 전송 데이터 크기 감소로 네트워크 전송 효율성이 향상된다.

 

샤딩(Sharding)

몽고DB에서 샤딩(Sharding)은 분할이라는 뜻으로 대용량의 데이터를 여러 노드로 분산해서 저장하는 기법을 말한다. 단일 서버에서 모든 데이터가 저장되면 서버 자체가 부담이 되기 때문에 읽기 및 쓰기 처리량에 대해 반드시 한계치가 찾아올 수 밖에 없다. 따라서 몽고DB는 샤딩을 활용하여 데이터를 동시에 여러 노드에서 읽고 쓸 수 있도록 하여 효율적으로 처리할 수 있다.

MongoDB 샤딩 클러스터는 위 그림과 같은 컴포넌트로 구성되고, 컬렉션 수준에서 데이터를 샤딩하여 클러스터의 샤드 전체에 컬렉션 데이터를 분산한다.

  • 샤드
    • 실제 데이터를 저장하는 서버로 각 샤드에는 샤드 데이터의 하위 집합이 포함된다.
    • 각 샤드는 레플리카 셋으로 배포되어야 한다.
  • mongos 사용한 라우팅
    • mongos는 클라이언트 애플리케이션과 샤딩된 클러스터 간의 인터페이스를 제공하는 쿼리 라우터 역할을 한다.
    • 클라이언트에 요청이 들어오면 어떤 샤드에 데이터가 있는지를 판단하고 해당 요청을 데이터가 존재하는 샤드로 라우팅해준다.
  • config 서버
    • config 서버는 클러스터에 대한 메타데이터와 구성 설정을 저장한다. config 서버는 레플리카 셋으로 배포되어야 한다.

몽고DB는 샤드 키를 사용하여 샤드에 대해 컬렉션 문서를 분산하고, 샤드 키는 문서의 필드 하나 또는 여러 필드로 구성될 수 있다. 샤드 키를 통해 데이터 저장 용량이 수평적으로 나눠 저장될 수 있고, 처리량을 향상시킬 수 있다. 즉, 샤드 키를 잘못 선택하는 경우 부하가 한 샤드에 집중될 수도 있기 때문에 알맞는 샤드 키를 선택하는 것이 중요하다.

 

 

 

 

출처

몽고DB 완벽 가이드 : 실전 예제로 배우는 NoSQL 데이터베이스 기초부터 활용까지

샤딩 - 공식 문서

3개 노드로 구성된 복제본 세트

 

'DB > MongoDB' 카테고리의 다른 글

MongoDB 인덱싱  (0) 2025.10.06
MongoDB 트랜잭션  (0) 2025.10.06
몽고DB CRUD  (0) 2025.09.17
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2026/02   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
글 보관함