일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 29 | 30 | 31 |
Tags
- 디자인 패턴
- JPA
- Galera Cluster
- C
- 백준
- 알고리즘
- JavaScript
- 컴퓨터구조
- 파이썬
- Spring
- redis
- OS
- Proxy
- c언어
- spring webflux
- 자바
- Java
- react
- mongoDB
- Algorithm
- 네트워크
- Kafka
- Data Structure
- IT
- 운영체제
- MSA
- 자료구조
- MySQL
- Heap
- design pattern
Archives
- Today
- Total
시냅스
MongoDB 총 정리 (Index, Transaction, Lock, Replication 등) 본문
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 보다는 유용하다.
- 브랜치와 리프 노드에는 인덱스 키 엔트리와 Reacord-ID 로 구성 됨
- 유형
- 단일 필드
- 복합 필드
- 멀티키 (배열, 임베디드 배열)
- 멀티키가 할 수 없는 것 : 샤드 키, 해시 인덱스
- 텍스트 인덱스 (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
- Shared(R)
위 Locking 기법과 거의 비슷하게 이뤄지는 InnoDB Locking 기법입니다.
X-Lock, S-Lock 등 정리 되어있는 글입니다.
https://liltdevs.tistory.com/190
Transaction
- MongoDB 도 ACID 를 만족하는 Transaction 을 지원
- Transaction 을 지원하기 위해 Replica Set 필요
- MongoDB 는 명시적으로 commit / rollback 하지 않기 때문에 op log 및 read / write concern 을 고려해야 함
- 아래 내용 참조
- MongoDB Default engine 인 WiredTiger 는 최초 설계시에는 RDB 에 적합하게 설계했음, 따라서 ACID 를 RDB 와 비슷하게 만족
- Transaction 을 지원하기 위해 Replica Set 필요
- 단일 문서에 대한 원자적 연산과 여러 문서에 대한 분산 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 인 경우 과반이 커밋된 데이터의 직전 스냅샷에서 읽음
- local
- MongoDB 는 기본적으로 Eventual Consistency 를 만족함, 이를 제어하기 위해 아래 옵션들을 제공
- Write Concern
- 명시적으로 Commit / Rollback 하는 RDB 와 다르게 트랜잭션을 commit 하겠다는 판단으로 문서를 저장할 때 사용자의 데이터 변경 요청을 응답하는 시점으로 지정
- 이러한 응답 시점을 결정하는 옵션을 Write Concern 으로 규정
- 옵션
- W: 1
- primary 에 적용된 후 승인 반환
- 정수로 데이터에 동기화하는 멤버의 수를 지정할 수 있음, PSA 라면 W: 2 지정시 모든 Node 데이터 적용
- W: "majority"
- 과반수에 커밋이 적용된 후 승인을 반환
- j: true
- 요청한 멤버가 journal 에 기록한 후에 승인 반환
- W: 1
- 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 서버의 스토리지 엔진으로 사용할 경우에는 설정하지 않는 것이 좋음
- log_size
- Write Ahead Log
'데이터베이스 > MongoDB' 카테고리의 다른 글
MongoDB Sharded Cluster, Docker 로 빠르게 올려보기 (0) | 2024.08.14 |
---|
Comments