시냅스

MongoDB 총 정리 (Index, Transaction, Lock, Replication 등) 본문

데이터베이스/MongoDB

MongoDB 총 정리 (Index, Transaction, Lock, Replication 등)

ted k 2024. 8. 14. 20:12

MongoDB

  • 문서(Document) 데이터베이스로 Key:Value 쌍으로 이뤄져있고 이는 JSON 객체와 유사.
  • 필드에는 다른 문서, 배열, 문서 배열 등이 포함될 수 있음
  • 문서 사용에 대한 장점
    • Document 는 다양한 프로그래밍 언어의 기본 데이터 유형에 해당
    • 포함된 문서와 배열은 비용이 많이 드는 조인의 필요성을 줄여 줌 (비정형)
    • 동적 스키마는 유창한 다양성을 지원 (유연성)
  • 주요 기능
    • 고성능
      • Embedded Data Model 지원으로 Disk IO 를 줄여 줌 (비정형 데이터 모델, 참조)
      • Indexing
    • Query
      • CRUD
      • Aggregation
      • Geo
      • FullText Search
    • HA
      • Replica Set
    • Scale-Out
      • Sharding
    • ACID
      • Transaction
      • Journaling
    • Storage Engine
      • WiredTiger Storage Engine
      • LSM
    • Search Engine
      • MongoDB Atlas
    • Time Series
  • 데이터 구조
    • 데이터베이스 > 컬렉션(Table) > 문서(Row)
    • 이때 문서는 JSON 을 직렬화하여 BSON(Binary JSON) 으로 만들어 Disk 에 적재함

 

MongoDB Data 구조

  • Database Namespace : 사용자가 하나의 데이터베이스를 만들었다면 MongoDB 는 데이터베이스와 관련된 한 개의 Namespace 를 만든다.
    • Collection Namespace : Collection 1 개당 1개의 Collection Namespace 가 만들어진다.
  • bucket : 인덱스는 레코드에 저장된 데이터를 빠르게 찾기 위해 B tree 형태로 저장된 노드 구조를 가지고 이를 bucket 이라고 부른다.
  • extent : Disk Block 에 접근에 용이하기 위해 사용하는 구조
  • record : BSON 객체를 저장하는 노드를 레코드로 정의, Double Linked List
    • MongoDB Record 최대 사이즈 16MB
  • Write 를 수행할 때 MongoDB 는 해당 레코드가 가리키는 가상 메모리 주소 공간에 데이터 적재
  • Read 를 수행할 대 해당 메모리 주소 공간에 할당된 데이터가 가상 메모리에 로딩되어 있는지 확인하고 없다면 적재
  • 주기적으로 확인하여 가상 메모리에 적재된 데이터 Disk 에 적재
  • 위에서 말하는 가상 메모리는 DB Level 이 아닌 OS Level (Memory Mapped Files)
    • page fault 를 줄이기 위해서는 Hot / Cold Data 를 잘 구분해서 메모리에 적재하도록 설계해야 한다.
    • 또한 Virtual Memory 이기 때문에 여전히 Swap 의 위험이 있다
  • MySQL 은 Data 가 buffer pool 없으면 바로 disk 로 내려가서 찾게 됨
    • 이때 PK 면 Clustering Key(B+Tree) 로 조회 -> 물리적으로도 정렬되어 있음, Random IO 없음
    • MongoDB 가 OS Layer 의 Cache 를 사용하는 것은 Record 가 B tree 로 조회시 O(logn) 으로 비교적 느릴 수 있고
    • MongoDB 의 태생이 Document Database 로 hash map 과 같아서 journaling 하는 것과는 별개로 record 가 덮어 씌워질 때 여러 연산을 중첩해서 disk 에 적용할 필요가 없기 때문이지 않을까 함
    • 또한 Data 접근에 대한 설계를 잘 했다면 (Hot / Cold) 성능상 이점이 있음

 

  • 위는 MySQL Data 구조
    • MongoDB 는 Extent 에서 Record 로 바로 접근하는 반면 MySQL 은 Extent - page - row 로 접근한다.
    • 또한 MySQL 은 Default 로 Page size 를 4KB 로 할당하기 때문에 하나의 row 가 너무 크거나, 작을 때에 발생할 수 있는 문제가 있음
      • 데이터가 너무 크면 큰 대로 읽어야 하는 page 가 너무 많아지고 이때 buffer에 기록해서 여러번 page 를 읽어야 하거나... (IO 증가)
      • page 보다 data size 가 너무 작으면 fragmentation 이 있는 등 (물론 이 때에는 여러개의 row 를 넣기도 한다.)

 

Index

  • 인덱스를 사용하여 효율적으로 쿼리를 실행할 수 있도록 지원, 만약 인덱스가 없다면 모든 문서를 스캔해야 함.
  • MongoDB 의 인덱스 또한 B Tree 를 사용
    • 브랜치와 리프 노드에는 인덱스 키 엔트리와 Reacord-ID 로 구성 됨
      • 키 엔트리에는 key:value pair, 키 값은 인덱스 생성시 인덱스 구성 컬럼의 필드 값
      • Record-ID 는 MongoDB 내부적으로 관리 되는 값으로 인덱스 키 값과 연결된 도큐먼트의 저장 주소를 의미, 논리적인 주소 혹은 물리적인 주소
      • 이때 WiredTiger 는 물리적인 주소를 가지고 있고 이는 Long 형 정수 타입, Auto Increment
        • 위를 위한 내부 index 를 하나 더 가지고 있고, Clustering Index 로 사용
    • 각 쓰기 작업은 인덱스 또한 업데이트 해야 하기 때문에 성능에 부정적인 영향을 미칠 수 있다.
    • Index Range Scan
      • 범위 탐색, 시작 점의 리프 노드를 찾으면 이후부터 노드간의 링크를 사용하여 최종 지점까지 탐색
      • 리프 노드에서 실제 데이터를 읽어 오는 것은 Random IO 가 발생하므로 읽어야 하는 데이터가 15 - 20% 가 넘으면 Collection Full Scan 이 더 유리
    • Index Prefix Scan
      • MySQL에서 'asd%' 로 찾는 경우
      • MongoDB 는 PCRE 정규 표현식으로 검색할 수 있다.
    • Covering Index
      • index 에서 필요한 모든 데이터를 들고 있는 경우
      • index 조회 후 사용자에게 바로 응답하므로 Random IO 가 줄어들어 성능이 향상된다.
    • Index Full Scan
      • 모든 Index 를 탐색, Collection Full Scan 보다는 유용하다.
  • 유형
    • 단일 필드
      • 복합 필드
      • 멀티키 (배열, 임베디드 배열)
    • 멀티키가 할 수 없는 것 : 샤드 키, 해시 인덱스
      • 텍스트 인덱스 (Full Text Search Index)
    • 형태소 분석 방법은 지원하지 않음
    • 대안으로 Percona MongoDB 를 사용하면 N Gram 지원 가능
    • 또는 MongoDB Atlas 사용
      • 와일드카드
    • 컬렉션 내 문서 필드 이름이 다를 경우 와일드 카드를 사용하여 임의의 필드에 대한 인덱스를 지정할 수 있음
      • 지리 공간
      • 해시 인덱스
    • 특정 Key 값을 hash 연산하여 Indexing
    • 디스크 기반의 대용량 테이블용으로는 거의 사용되지 않음
    • 범용적이진 않지만 빠른 성능을 지원
    • MongoDB 는 Hash 를 위한 자료 구조체가 따로 없고 Hash Entry 에 bucket 을 B Tree 로 붙임

 

Lock

  • MongoDB 또한 충돌 문제를 방지하기 위해 Lock 을 사용
  • 네 가지 잠금 수준
    • Global : MongoDB 인스턴스 수준 잠금
    • Database : 언급된 데이터베이스가 잠기는 수준 잠금
    • Collection : 컬렉션 수준 잠금
    • Document : 특정 도큐먼트만 잠기는 수준 자금
  • 네 가지 잠금 모드
    • Shared(R)
      • S-Lock
    • Exclusive(W)
      • X-Lock
    • Intent Shared(r)
      • IS-Lock
    • Intent Exclusive(w)
      • IX-Lock

 

위 Locking 기법과 거의 비슷하게 이뤄지는 InnoDB Locking 기법입니다.
X-Lock, S-Lock 등 정리 되어있는 글입니다.

https://liltdevs.tistory.com/190

 

InnoDB Locking 기법 정리

InnoDB Locking MySQL 의 InnoDB 에서 사용하는 Locking 기법 Shared Lock, S-Lock 특정 레코드를 읽을 때 사용되는 Lock Shared Lock 끼리는 동시 접근이 가능하다. 하나의 레코드를 여러 트랜잭션이 동시에 읽을 수

liltdevs.tistory.com

 

Transaction

  • MongoDB 도 ACID 를 만족하는 Transaction 을 지원
    • Transaction 을 지원하기 위해 Replica Set 필요
      • MongoDB 는 명시적으로 commit / rollback 하지 않기 때문에 op log 및 read / write concern 을 고려해야 함
      • 아래 내용 참조
    • MongoDB Default engine 인 WiredTiger 는 최초 설계시에는 RDB 에 적합하게 설계했음, 따라서 ACID 를 RDB 와 비슷하게 만족
  • 단일 문서에 대한 원자적 연산과 여러 문서에 대한 분산 transaction 또한 지원
    • 분산 transaction 을 사용하여 여러 작업, 컬렉션, 데이터베이스, 문서 및 샤드에서 transaction 을 사용할 수 있음
  • 문서 수준 동시성 (Write Conflict)
    • Optimistic Lock, Intent Lock
    • 두 작업 간 충돌을 감지하면 한 작업이 쓰기 충돌을 발생하여 MongoDB 가 해당 작업을 재시도
  • MVCC
    • Snapshot(Repeatable Read) : MongoDB Default Isolation Level
    • 스냅샷은 인메모리 데이터에 대한 일관적인 뷰를 제공
    • minSnapshotHistoryWindowInSeconds parameter 로 스냅샷 기록 보관 기간 지정
    • 또한 Yeild 가 수행되는 경우 쿼리 도중 멈췄다 재개하기 때문에 phantom read 가 발생할 수 있음
      • 이를 위해 session.startTransaction() 로 명시적으로 transaction 을 수행
      • transactionLifetimeLimitSeconds 옵션으로 명시적으로 transaction 시간 제어

 

  • 위 이미지는 write concern w:"majority"
    • 아래에서 설명
  • Read / Write Concern
    • 분산 환경을 기본 아키텍처로 선택한 만큼 Consistency 에 대한 옵션을 제공함
    • Read Concern
      • MongoDB 는 기본적으로 Eventual Consistency 를 만족함, 이를 제어하기 위해 아래 옵션들을 제공
        • local
          • local 에 있는 가장 최신의 데이터 반환
          • 다른 Node 의 상태는 확인하지 않음
          • 또한 Snap Shot 인지 보장할 수 없기 때문에 phantom read 발생할 수 있음
        • majority
          • 복제본 세트 멤버의 과반수가 인정한 데이터를 반환
        • snapshot
          • MVCC 를 지원하거나 지원하지 않게 제공
          • Transaction 이 Casually Consistent Session 이 아니고 Write Concern 이 majority 인 경우 과반이 커밋된 데이터의 현재 스냅샷에서 읽음
          • Transaction 이 Casually Consistent Session 이고 Write Concern 이 majority 인 경우 과반이 커밋된 데이터의 직전 스냅샷에서 읽음
    • Write Concern
      • 명시적으로 Commit / Rollback 하는 RDB 와 다르게 트랜잭션을 commit 하겠다는 판단으로 문서를 저장할 때 사용자의 데이터 변경 요청을 응답하는 시점으로 지정
      • 이러한 응답 시점을 결정하는 옵션을 Write Concern 으로 규정
      • 옵션
        • W: 1
          • primary 에 적용된 후 승인 반환
          • 정수로 데이터에 동기화하는 멤버의 수를 지정할 수 있음, PSA 라면 W: 2 지정시 모든 Node 데이터 적용
        • W: "majority"
          • 과반수에 커밋이 적용된 후 승인을 반환
        • j: true
          • 요청한 멤버가 journal 에 기록한 후에 승인 반환
  • Read Write Split
    • MongoDB 는 분산 환경에 맞게 설계된 제품으로 접속 URI 에서 Read Write Split 을 지정할 수 있음
    • mongodb://.../{DATABASE}?{REPLICASET}=&readPreference=secondaryPreferred
    • 위 readPreference 옵션을 사용하여 읽기 분산 처리
      • primary : primary 에서 읽기
      • primaryPreferred : primary 가 밀려있다면 secondary 에서 읽음
      • secondary : secondary 에서 읽기
      • secondaryPreferred : secondary 가 밀려있다면 primary 에서 읽음
      • nearest : network 대기 시간이 가장 짧은 복제본 세트에서 읽음

Replication

  • 고가용성, 내결함성, 성능(Read/Write split) 을 지원하기 위한 시스템
  • opLog
    • Operation Log, 복제를 위해 사용되는 로그 (cf. mysql bin log)
    • primary에서 데이터베이스 연산을 적용한 후 oplog 에 연산을 기록한다.
    • 세컨더리는 위 연산을 복사하고 적용한다.
    • 각 작업은 멱등하게 이뤄짐 -> "oplog.rs" 라는 이름의 컬렉션으로 기록하고 적용하기 때문에
      • "oplog.rs" 구성 정보
      • ts(Timestamp) : 저장 순서를 결정하는 시간
      • t(Primary Term) : primary 선출하는 투표가 실행될 때마다 증가하는 값
      • h(hash) : Primary 멤버에서 실행된 데이터 변경 작업
      • v(version) : document version
      • op(Operation Type) : i(insert) d(delete) u(update) c(create)
      • ns(namespace)
      • o(Operation) : 실제 변경된 정보, 문서가 변경된 값을 저장하는 필드
  • Replica set 은 최소 3대 홀수로 유지하는 것을 권장
    • Split brain 상황에 어떤 곳이 master 가 될지 판단해야 함
    • primary
      • master node
      • client 와 직접적으로 쓰기 작업 주고 받음
      • primary 장애 발생시 secondary 가 primary 로 올라옴
    • secondary
      • primary 로부터 데이터를 동기화하고 장애시 역할 전환
      • 장애 발생시 어떤 노드가 primary 가 될지 투표
      • read 연산 분산
    • arbiter
      • 장애시 투표권만을 가진 node

 

  • 하나의 노드에서(primary) 쓰기 작업을 수행하고 나머지는 읽기 작업을 수행함

 

  • 하나의 노드(primary)에서 쓰기 작업을 수행하고
  • 하나의 노드(secondary)에서 데이터를 동기화 하고
  • 하나의 노드(arbiter)에서는 투표만 수행함

 

 

Storage Engine

  • 스토리지 엔진 : 사용자의 데이터를 디스크와 메모리에 저장하고 읽어오는 역할
  • WiredTiger
    • 기본 스토리지 엔진
    • 옵션
      • engineConfig.cacheSizeGB : 어느 정도의 메모리를 사용할 것인지
      • collectionConfig.blockCompressor : 데이터 파일을 압축할 것인지
        • zstd 권장, 무손실 데이터 압축, 압축 속도와 해제 속도 준수한 편
    • 데이터 저장소 타입
      • Record Store
      • Column Store
      • LSM
    • 지원하는 기능
      • Write Ahead Log
        • Journal Log
        • 데이터 디렉토리 하위에 journal 이라는 디렉토리에 저장됨
        • 위 journal log 를 사용해서 mongodb 는 데이터 복구를 진행
        • 참고. Data가 적용되는 순서 
          • 1. WAL
          • 2. Data Memory 적용
          • 3. OpLog
          • 4. Disk Flush
      • 공유 캐시
        • mysql 의 buffer pool 과 같은 기능
        • 데이터를 메모리에 적합한 트리 형태로 재구성하며 적재
        • mysql 의 경우 데이터가 caching 될 때 b tree 상의 주소를 사용하는 반면 mongodb 는 메모리 주소를 적재
        • 이런 변환 과정 덕분에 caching 되는 속도는 느릴 수 있지만 caching 이 되었다면 rdb 보다 훨씬 빠름
      • Hazard Pointer (Lock Free Algorithm)
        • Hazard Pointer 에 현재 데이터를 참조하고 있는 메모리를 등록하고 캐시에서 제거할 때 hazard pointer 에 등록된 데이터라면 evict 되지 않게 함
        • Disk Flush 여부 또한 결정할 수 있음
      • skip list (Lock Free Algorithm)
        • undo log 를 skip list 로 사용하며 레코드가 변경된 이후에 데이터를 skip list 에 추가
      • cache eviction
        • cache 의 빈 공간을 적절히 유지해서 적재할 수 있도록 도움
        • 주로 백그라운드 스레드로 동작하지만 백그라운드 스레드가 여유 공간을 확보하지 못하면 포그라운드 스레드에서 실행하기도 함
        • 이때 성능은 현저히 떨어짐
        • 튜닝 파라미터
          • threads_max: 이빅션 쓰레드의 최대 개수 설정 (1~20)
          • threads_min: 이빅션 쓰레드의 최소 개수 설정 (1~20)
          • eviction_dirty_target: 공유 캐시의 더티 페이지 비율 유지 (기본 80%)
          • eviction_target: 데이터 페이지 비율 유지 (기본 80%)
      • 체크포인트
        • WAL 로 데이터 영속성을 보장
        • 체크포인트는 데이터 파일과 트랜잭션 로그가 동기화되는 시점을 의미
        • 체크포인트는 DB 장애로 재실행할 때 복구할 시점을 결정하는 기준이 됨
        • MongoDB는 샤프 체크포인트 사용
          • 체크포인트가 실행되는 시점에 한 번에 더티 페이지를 모아서 내려쓰는 패턴
        • 옵션
          • log_size
            • 트랜잭션 로그가 log_size 만큼 쓰여지면 체크포인트가 실행.
            • 기본 값은 0으로, 이 경우 WiredTiger가 체크포인트 시점을 자동으로 결정
          • wait
            • 지정된 시간(초 단위) 동안 대기한 후 주기적으로 체크포인트를 실행하도록 설정
            • 기본 값은 0으로, WiredTiger가 체크포인트 시점을 자동으로 결정
          • name
            • 체크포인트의 이름을 지정하는 옵션으로, WiredTiger를 응용 프로그램에 임베디드하여 사용할 때 필요
            • MongoDB 서버의 스토리지 엔진으로 사용할 경우에는 설정하지 않는 것이 좋음
Comments