ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [MongoDB] MongoDB란?
    Computer Science/Database 2024. 1. 3. 01:11

    기존의 사용하던 RDB는 당시 Disk Storage가 매우 고가의 제품이라 데이터 중복을 줄이는데 집중했다. 방대한 양의 데이터를 처리하기 위해서 성능 향상이 필요했지만 수직적 확장의 경우 비용이 많이 소모되고, 수평적 확장의 경우 관계 테이블을 모두 동일한 서버에 보관해야했기에 확장이 어려웠다.

     

    이후 Disk Storage가 더이상 큰 이슈가 아니게 되면서 데이터베이스의 확장성과 성능을 위해 NoSQL이 등장했다. NoSQL은 RDB가 하지 못했던 것들을 해결하며 다양한 장점을 제공한다.

    • 데이터 가시성이 좋고 Join없이 조회할 수 있어 읽기 성능, 응답 속도가 빠르다.
    • 스키마가 유연해서 어플리케이션의 요구사항에 맞게 데이터를 수용할 수 있다.
    • Scale-Out이 간편하다.
    • 역정규화에 따라 데이터 중복이 발생한다.
    • 스키마 설계를 못하면 성능 저하가 발생한다.

     

     

    MongoDB

    MongoDB는 NoSQL의 하나로 Document 지향 Database이다. (여기서 document는 MongoDB의 자료구조!) 

    NoSQL의 특징과 함께 다양한 기능을 제공한다. HA와 Scale-Out 솔루션을 제공하여 확장이 쉽고, 다양한 종류의 인덱스를 제공하며 응답속도가 빠르다.

     

     

     

     

    MongoDB의 구조

    기존 RDBMS에서의 개념들이 MongoDB에서는 다음과 같이 대응된다.

    RDBMS MongoDB
    Database Database
    Table Collection
    Row Document
    Column Field
    쿼리 결과로 레코드(Record) 반환 쿼리 결과로 커서(Cursor) 반환

     

    MongoDB는 쿼리 결과를 커서로 반환하는데, 커서란 쿼리 결과 집합에 대한 포인터이다. 응용 프로그램이나 MongoDB 클라이언트 프로그램에서 커서를 통해 반복적으로 실제 document를 가져올 수 있다. MongoDB에서 쿼리의 결과로 커서를 반환하는 이유는 쿼리의 결과를 클라이언트 서버의 메모리에 담아두지 않아도 처리할 수 있게 하기 위해서이다. 쿼리 결과를 한번에 메모리에 로드하는 것보다 커서를 통해 일부분을 필요할 때마다 전달하는 것이다. (지연 로딩 방식을 사용, 실시간 스트리밍)

     

     

    Database

    MongoDB 인스턴스는 여러 개의 데이터베이스를 호스트할 수 있고, 각각의 데이터베이스는 컬렉션의 컨테이너로 작용한다. 데이터베이스는 디스크의 별도 파일에 데이터를 저장하며, 각 데이터베이스는 고유한 이름 공간이 있다. 

    MongoDB는 기본적으로 아래 3개의 데이터베이스를 제공한다.

    • admin : 인증과 권한 부여 역할. shutdown 등의 명령어는 해당 DB에 대한 접근이 필요.
    • local : replication에 필요한 oplog와 같은 컬렉션 저장. instance 진단을 위한 startup_log와 같은 정보 저장. 복제 대상에서 제외됨.
    • config : sharded cluster에서 각 shard의 정보를 저장한다.

     

     

    Collection

    MongoDB의 Collection은 Document의 그룹이며 관계형 데이터베이스의 테이블과 유사하다. Collection은 단일 데이터베이스 내에 존재하며 스키마를 강제하지 않으므로 Collection 내의 Document는 다른 필드와 구조를 가질 수 있다.

    Collection 단위로 Index를 생성하거나 Shard를 나눌 수 있다. Index나 Sharding Key등의 활용을 하기 위해서는 Schema는 어느정도 유지를 해줘야 한다.

     

     

     

    Document

    MongoDB에서의 기본 데이터 단위로 관계형 데이터베이스의 행과 유사하다. Document는 BSON(Binary-JSON)형태로 저장하며, 필드와 값 쌍으로 구성된다. 모든 Document에는 _id 필드가 있고, 없이 생성하면 고유한 ObjectId를 지원한다. 생성 시 상위 구조인 Database나 Collection이 없다면 먼저 생성하고 Document를 생성한다. 최대 크기는 16MB로 고정되어 있다.

     

     

     

    BSON(Binary-JSON)

    BSON은 MongoDB에서 문서를 저장하고, 원격 프로시저 호출(RPC)와 같은 분산 시스템에서 데이터를 저장하고 전송하기 위해 만들어진 이진 직렬화 형식이다. 이진 형식으로 텍스트보다 적은 용량을 사용하며 처리속도가 빠르다. BSON은 문자열, 숫자, 이진데이터, ObjectId 등 다양한 데이터 유형을 지원하고, 이러한 데이터 유형을 효율적으로 저장할 수 있으며, 덕분에 데이터를 빠르게 찾고 처리할 수 있다.

    • 데이터를 이진 직렬화하여 데이터 크기가 작아 데이터 전송 시 빠르게 통신할 수 있다.
    • 이진 형식으로 처리 속도가 빨라 전체 응답시간이 감소한다.
    • 다양한 데이터 유형을 제공한다.

     

     

     

     

    MongoDB 물리적 데이터 저장 구조

    MongoDB는 기본적으로 memory mapped file(OS에서 제공되는 mmap을 사용)을 사용한다. 데이터를 쓰기할 때 디스크에 바로 쓰기 작업을 하는 것이 아니라 논리적으로 메모리 공간에 쓰기를 하고, 일정 주기에 따라서 이 메모리 block들을 주기적으로 디스크에 쓰기 한다. 이 디스크 작업은 OS에 의해서 이루어진다.

     

    | mmap(memory mapping)

    파일 처리의 성능을 높이는 방법 중 하나로 메모리에 파일을 매핑하는 방식이다. 프로세스에서 파일을 읽을 때 OS의 시스템 콜을 시작으로 저장 매체에 접근하여 파일을 읽기까지의 과정이 복잡하고 오래걸린다. 또한 내부적으로 OS가 처리해야하는 과정(시스템 콜, 인터럽트, 스케줄링)이 많이 때문에 CPU 성능이 떨어지기 마련이다. 파일에 접근하는 과정의 효율성을 높이기 위해 사용하는 함수가 mmap()이다. 메모리의 특정 공간에 파일을 매핑하고 프로세스는 해당 파일을 읽기 위해서 저장 매체에 접근하는 것이 아니라 메모리의 데이터에 접근한다. 내부적인 OS 처리 과정이 필요없기 때문에 성능이 향상된다.

     

     

    OS에 의해서 제공되는 가상 메모리를 사용하게 되는데, 물리 메모리 양이 작더라도 가상 메모리는 훨씬 큰 공간을 가질 수 있다. 가상 메모리는 페이지(Page)라는 블럭 단위로 나뉘어지고, 이 블럭들은 디스크 블럭에 매핑되고, 이 블럭들의 집합이 하나의 데이터 파일이 된다.

     

     

    메모리에 저장되는 내용은 실제 데이터 블록과 인덱스 자체가 저장된다. MongoDB에서 인덱스를 남용하지 말아야하는 이유도 인덱스 생성 및 업데이트 하는데 자원이 들어가며, 인덱스가 메모리에 상주하고 있어야 제대로된 성능을 낼 수 있기 때문이다. 

     

    만약에 물리 메모리에 해당 데이터 블록이 없다면 page fault가 발생하게 되고 디스크에서 그 데이터 블록을 로드하게 된다. 물론 그 데이터 블록을 로드하기 위해서는 다른 데이터 블록을 디스크에 써야한다. 즉, page fault가 발생하면, page를 메모리와 disk 사이에 switchingg하는 현상이 일어나기 때문에 disk io가 발생하고 성능 저하를 유발하게 된다.

     

    즉 메모리 용량을 최대한 크게해서 page fault를 예방해야 하지만 메모리 용량은 한정적으로 page fault는 발생할 수 밖에 없어 page fault를 줄이는데 초점을 둬야한다.

    page fault 시 disk로 write되는 데이터는 LRU(Least Recently Used)에 의해서 결정된다. 가장 오랫동안 참조되지 않은 page가 disk로 out되는데, 일반적인 애플리케이션에서 자주 쓰는 데잍 비율은 크지 않다. 이렇게 자주 액세스되는 데이터를 Hot Data라고 하는데, 이 데이터들이 집중돼서 메모리에 올라가도록 Key 설계를 하는 것이 핵심이다. 쓸데없이 전체 데이터를 scan하는 등의 작업을 하게 되면 무조건 page fault가 발생하기 때문에 table scan 등이 필요한 시나리오는 별도의 index table(summary table)을 만들어서 사용하는 등의 전략이 필요하다.

     

     

     

     

    MongoDB 인덱스

    인덱스는 DB검색을 빠르게 하기 위하여 데이터 순서를 미리 정리해두는 과정이다. MongoDB는 고정된 스키마는 없지만, 원하는 데이터 필드를 인덱스로 지정하여 검색 결과를 빠르게 하는 것이 가능하다.

     

    MongoDB index는 한 쿼리에 한 index만 유효하다. 따라서 두 개의 index가 필요하다면 복합 인덱스를 사용한다. index는 어떤 데이터가 document에 추가되거나 수정될 때(write 작업) 그 Collection에 생성되어 있는 index도 새로운 document를 포함시켜 수정된다. 이로인해 index 추가 시 write 작업은 느려질 수 있다. 따라서 index는 read 작업 위주의 애플리케이션에서 유용하고 읽기보다 쓰기 작업이 많으면 index를 추가하는 것은 고려해야한다.

     

    MongoDB의 인덱스 종류는 다음과 같다.

    • 단일 필드 인덱스
    • 복합 인덱스
    • 다중키 인덱스 
    • Geospatial 인덱스
    • 해쉬 인덱스

     

     

    Single Field Indexes (단일 필드 인덱스)

    기본적인 인덱스 타입으로 하나의 필드 인덱스를 사용하는 것을 단일 필드 인덱스라고 한다. MongoDB는 기본적으로 Collection에 _id라는 단일 필드 인덱스가 생성된다. 원하는 field와 오름차순, 내림차순을 설정하여 인덱스를 생성할 수 있다.

     

     

     

    Compound Indexes (복합 인덱스)

    두 개 이상의 필드를 사용하는 인덱스를 복합 인덱스라고 한다. 인덱스의 첫 번째 필드 별로 그룹화된 다음 각 후속 필드 별로 그룹화된다.

     

     

     

    Multikey Indexes (멀티키 인덱스)

    배열을 포함하는 필드에 사용하며, 배열의 각 요소에 대해 인덱스 키를 자동으로 생성한다.

     

     

    Geospatial  Indexes (지리 공간 인덱스)

    2차원 지리 공간 데이터에 사용되는 인덱스와 쿼리

     

     

    Text Indexes (텍스트 인덱스)

    문자열 콘텐츠가 포함된 필드에 지정하는 인덱스이다.

     

     

    Hashed Indexes (해쉬 인덱스)

    B-Tree 인덱스 구조로 인덱스를 구성한다. Hashed Indexes는 해시된 샤드 키를 이용한 샤딩을 지원한다. 해시 인덱스를 샤드키로 이용하여 샤딩된 클러스터에 데이터를 분할한다.

     

     

     

     

    MongoDB 배포 형태

    MongoDB의 배포 형태는 3가지가 있다.

    • StandAlone
    • Replica Set
    • Sharded Cluster

     

     

    StandAlone

    가장 일반적인 방법으로 1개의 client가 1개의 server에 read/write를 모두하는 형태이다. 해당 DB가 죽으면 사용자들이 이용을 못하게 되고, 부하를 1대의 서버가 전부 감당하게 된다.

     

     

    Replica Set

    장애 대응 및 부하 감소를 위해 Replica Set 방식을 사용할 수 있다. Replica Set 방식을 Primary Database와 동일한 서버를 여러 대 띄워서 동일한 데이터를 Secondary Database에 복제한다.

     

    자동 장애 조치

    Primary Database가 장애가 나도 계속 운영할 수 있는 HA(High Availability)를 제공한다. Primary Database가 죽으면 Secondary Database는 자신을 Primary로 선택하도록 요청하고 클러스터가 선택한다.

     

    ▷ Primary

    • Read/Write 요청을 모두 처리할 수 있다.
    • Write를 처리하는 유일한 멤버이다.
    • Replica Set에 하나만 존재할 수 있다.

     

    ▷ Secondary

    • Read에 대한 요청만 처리할 수 있다.
    • 복제를 통해 Primary와 동일한 데이터 셋을 유지한다.
    • Replica Set에 여러개 존재할 수 있다.
    • Primary가 죽으면 선출을 통해 Primary가 될 수 있다.

     

     

    Sharded Cluster

    Replica Set을 사용하여도 부하는 1대의 DB서버가 감당하고 있다. 해당 DB 서버가 트래픽을 많이 받아 무리가 있다면 DB 서버를 부하 분산해야한다. MongoDB에서는 샤딩을 위해 Sharded Cluster를 제공한다.

     

    Sharded Cluster는 shard, mongos, config servers로 구성된다.

    • shard : 샤딩된 데이터의 집합. 샤드는 replica set으로 구성된다.
    • mongos : 샤드 클러스터의 쿼리 라우터. 클라이언트 어플리케이션과 샤드 클러스 사이의 인터페이스. 샤딩된 클러스터의 라우팅 및 로드밸런싱 처리
    • config servers : 클러스터 내 메타데이터와 설정을 저장하는 인스턴스

     

    MongoDB는 Collection 수준에서 데이터를 샤딩하여 클러스터의 샤드 전체에 Collection 데이터를 배포한다. 데이터베이스에는 샤딩된 Collection과 샤딩되지 않은 Collection이 섞여있다.

     

    Sharded Cluster를 사용하면 다음과 같은 이점이 있다.

    • 읽기와 쓰기를 분산하여 처리할 수 있고, 샤드를 추가하여 수평적 확장할 수 있다.
    • 하나 이상의 Replica Set을 사용할 수 없게 되어도 계속 읽기/쓰기 작업을 수행할 수 있어 가용성이 향상된다.

     

     

     

     

    MongoDB의 장단점

    장점

    ▷ 유연성 : 스키마 리스 디자인

    RDBMS는 데이터 요구 사항이 변경될 때 미리 정의된 스키마를 필요로 하는 것과 다르게 MongoDB는 요구 사항이 변경될 때 유연하게 적용할 수 있다.

     

     

    ▷ 확장성

    MongoDB는 읽기 기능 확장을 위한 Replica Set와 쓰기 기능 확장을 위한 샤딩을 제공하여 수평적 확장에서 뛰어나다.

     

     

    ▷ 성능

    MongoDB 클러스터를 통해 Read/Write 성능이 뛰어나다.

     

     

     

    장점

    ▷ 트랜잭션 지원의 한계

    MongoDB는 다중 document 트랜잭션을 지원하지만, RDB와 같이 엄격하지 않다. MongoDB의 트랜잭션 처리는 ACID가 아닌 BASE 기반이다.

    ACID(원자성, 일관성, 고립성, 지속성)는 데이터베이스 트랜잭션 처리의 전통적인 특성이다. MongoDB는 BASE(Basically Available, Soft State, Eventual Consistency)를 기반으로 한다. BASE 기반의 트랜잭션 처리는 ACID보다 느슨한 일관성 모델을 사용하며 높은 가용성과 분산시스템에 적합한 성능을 목표로 한다.

    • 기본적으로 사용가능(Basically Available) : 시스템을 항상 응답을 제공하며, 일시적인 고장이나 네트워크 지연에도 높은 가용성을 유지한다.
    • 소프트 상태 (Soft State) : 시스템의 상태는 시간에 따라 변할 수 있으며, 일관성이 보장되지 않는다.
    • 최종 일관성(Eventual Consistency) : 시스템은 일정 시간이 지난 후에야 최종적으로 일관된 상태를 달성한다.

    따라서 RDB의 ACID 트랜잭션 처리만큼 엄격한 트랜잭션 처리를 보장하지 않는다.

     

     

    대용량 데이터 저장

    BSON 형식으로 인해 다른 데이터베이스에 비해 저장공간이 더 많이 필요할 수 있다. (유연한 데이터 구조 정보 저장, 필드의 인덱스 및 메타데이터 포함 가능 등) 특히 대량의 작은 Document를 다룰 때 그렇다. (패딩, 인덱스 크기, 프리 할당 공간 등)

     

     

    Join

    RDB와 같은 네이티브 조인을 지원하지 않는다. 그러나 LeftOuterJoin을 수행하는 $lookup 연산자를 제공하며, 전통적인 조인에 비해 효율성이 떨어질 수 있다.

     

     

     


    참고

    댓글

Designed by Tistory.