
이전 포스팅에서 RDB와 NoSQL이 어떤 구조로 되어있고,
어느 상황에 사용하는게 적합한지를 다뤘다.
2024.04.17 - [데이터베이스] - RDBMS vs NoSQL 세기의 맞대결.
RDBMS vs NoSQL 세기의 맞대결.
백엔드 개발자로서 시스템에 사용,활용되는 데이터를 어떤 형식으로 저장해야 효율적 일지 판단할 필요가 있다. 오늘은 많은 데이터베이스 중에서 "관계형"과 "비관계형" 데이터베이스의 차이
jjunescoding.tistory.com
여기서 한 가지 궁금점이 생겼다.
NoSQL은 무슨 이유로 대용량 데이터를 다루는데 뛰어난걸까?
좀 더 기술적인 측면으로 들어가서 알아보자!!
RDB보다 NoSQL이 속도가 빠른 이유
결론부터 말하면 NoSQL 데이테베이스는 LSM Tree가 적용되어 동작한다.
그리고 이 LSM Tree는 Log Structured Storage Engine에 기반한 방식으로
Log Structured Storage Engine의 발전된 형태이다.
그렇다면, Log Structured Storage Engine 란?
- Log 파일 기반으로 작동하는 방식이다.
- 여기서 말하는 Log 파일은 Append-only 파일이라고 보면 된다.
즉, 한번 쓰여진 정보는 바뀌지 않고, 새로운 내용은 항상 파일의 끝에 추가된다는 의미이다.
예시로 한번 보자.
Key Value로 된 Database가 있고, 아래와 같이 db_get과 db_set을 하는 기능이 있다고 생각해보자.

그러면 아래와 같이 db_set(write)와 db_get(read)이 아래와 같이 Append-only 방식으로 동작하게 된다.

여기서 생각되는 것이 두 가지 있다.
1. db_set 퍼포먼스는 좋다. 왜냐하면 파일 마지막에 새로운 데이터를 추가하기만 하면 되기때문이다.
2. 그러나 db_get 퍼포먼스는 나쁘다. 왜냐면 db_get 이 요청될때마다 database를 full scan 해야하기 때문이다!
어떻게 하면 db_get을 더 빠르게 할 수 있을까?
바로 Index를 만들어서 해결할 수 있다.
Index란, 쿼리 퍼포먼스를 올리기 위하여 추가적으로 가지고 있는 데이터구조이다.
인덱스를 알고있다는 가정하에, 간략하게 장단점만 알고 넘어가겠다.
Index의 장점
- Index를 사용해서 Read 퍼포먼스를 더 좋게 만들 수 있다.
Index의 단점
- Index는 추자적으로 가지고 있는 데이터구조이기 때문에 추가적인 메모리와 디스크 용량을 사용한다.
- Index가 생기면 DB Write를 할때 마다 Index도 업데이트를 같이 해줘야하므로, Write 퍼포먼스가 안좋아 질 수 있다.
따라서 db_get을 통해 full scan을 해야했던 단점을 Index를 이용하면 해결할 수 있다.
메모리에 hash map 형태로 index를 사용해서 각각의 key 값이 disk 어디에 있는지 저장해 놓는 방식을 적용할 수 있다.

이렇게되면, 기존 full scan을 통해 disk에 저장된 값을 찾아야했던 것을,
Hash Index를 통해 데이터가 저장되어있는 디스크 주소를 알고 빠르게 접근할 수 있게 되는 것이다.
정리하자면, 메모리에 hash map index를 활용으로 기존 방식의 문제였던 db_set을 빠르게 할 수 있게 된 것이다.
다음으로 우리가 지금 하는 방식에는 또 하나의 문제가 있다.
"기존 동일한 key가 있음에도 상관하지 않고 그저 추가하는 방식"이다.
이렇게되면 update가 많을수록 쓸데 없는 데이터가 차지하고 있는 용량이 많아지게 된다.

이 낭비되는 용량을 어떻게 줄일 수 있을까?
이때 도입된 개념이 Segment File과 Compaction이라는 개념이다.
Segment : Database 파일을 하나로 가지고 있는게 아니라 일정 사이즈가 되면 새로운 파일을 만든다.
Compaction : SegmentFile을 대상으로 불필요한 데이터를 삭제하여 압축한다.

일정 사이즈가 되어 Segment된 파일은 이제 수정되지 않는 Immutable한 데이터이므로 우리가 원하는 처리를 해줄 수 있다.
이때 해당 Segment File을 대상으로 Compaction이 작동하여 불필요한(중복된 key값으로 된) 데이터를 지워주게된다!

따라서 지금까지 설명한 Log Structured Storage Engine을 도식화하면 아래 그림과 같다.
참고로, hash index 역시 segment File에 따라 메모리에 분리되어 저장된다

동작방식
1. db_get() 요청이 온다.
2. 가장 최근에 생성된 Hash index3을 scan 한다.
3. 찾고자하는 key값이 hash index에서 발견된다면, byte Offset(데이터가 저장된 disk 주소)를 통해 데이터를 조회한다. 그리고 이미 찾았으므로 hash index2와 hash index1은 조회하지 않고 끝낸다.
4. 그러나, 해당 hash index3에서 발견되지 않는다면, hash index 2 와 hash index 1 을 차례로 조회하며 3번 과정을 반복하여 조회한다.
아직 해결해야할 Log Structured Storage Engine의 단점이 존재한다.
바로 모든 데이터에 대한 Hash Index가 memory에 전부 다 들어가 있어야한다.
하나라도 안들어가있으면 그 키를 get할떄는 full scan을 하게된다.
이런 단점을 LSM Tree는 해결해준다.
LSM Tree란?
Sorted String Table(SSTable)을 활용한 방법이다.
즉, Segment File과 다르게 key 값이 정렬되어 저장되는 특징을 가지고 있다.

하지만 이때 이런 생각을 할 수 있다. 우리는 분명 앞에서 append-only로만 데이터를 추가한다고 했다.
그런데 이렇게 key로 정렬된 database를 어떻게 만들어낼 수 있을까?
방법은 데이터를 추가할때 바로 disk에 넣는 것이 아닌, memory에 있는 binary tree에 먼저 추가하게 된다.
그리고 이렇게 memory에 추가된 tree를 memtable이라고 통칭한다.

그리고 Segment File과 동일하게 memtable가 일정 사이즈가 되면
이때 바로 SSTable에 memtable에 저장했던 정렬된 데이터를 append-only로 추가하게 된다.

이런 방식으로 우리는 SSTable에 append-only 방식을 유지하여 Write 성능을 좋게 유지할 수 있다.
눈치가 빠르다면 생각할 수 있는데, 그러면 일정 사이즈가 되기 전에
즉, 메모리에 memtable만 생성되고 disk에는 SSTable은 하나도 생성되지 않은 상태에서
DB가 Crash 되어 메모리에 올라가있던 것이 다 날라가버리는 문제가 있을 수 있다.
그래서 실제로 memtable에 데이터를 추가함과 동시에, Disk에 SSTable이 아니라 처음에 Log File로 저장했던 방식대로 append하면서 기록을 남겨준다. 그리고 추후 메모리에 문제가 생겼을 시, Log File을 통해 복구를 해주는 것이다.

그리고 memTable이 일정 사이즈가 넘어가게되면,
SSTable에 추가함과 동시에 memTable과 Log File을 비워주고 다시 데이터를 추가하게 된다.

동작과정을 보면,
1. db_get() 요청이 오면,
2. memtable에 해당 key값으로된 데이터가 있는지 확인한다. 만약 발견하면 바로 조회 끝.
3. memtable에 없으면 가장 최근 생성되었던 Segment File 순서대로 조회를 진행한다.

그리고 여기에서, SSTable은 Disk에 있으니까 아래와 같이 memory에 hash index를 통해 저장하면 조회 퍼포먼스를 더 좋게 할 수 있다.

위의 그림을 보면 알겠지만, 기본적인 Log Structured Storage Engine과는 다르게, 모든 key들을 memory에 저장할 필요가 없다.
왜냐면, SSTable의 key값들이 정렬이 되어 있으므로 해당 SSTable의 가장 첫번째와 가장 마지막 데이터의 주소만 알고 있으면 범위를 통해 어떤 SSTable에 속한 데이터인지 확인이 가능하기 때문이다.
자, 이제 마지막 정리이다.
LSM-Tree를 이용한 특징
1. Write 이 빠르다.
- Memtable과 Log File에 append만 하면 되기 때문이다.
2. memory index에 모든 key 값을 저장할 필요가 없다.
- SSTable에 key값들이 정렬되어 저장되기 때문이다.
그리고 우리가 아는 대부분의 NoSQL이 LSM-Tree 방식을 이용해서 동작하고 있다.
공부를 했다면, 이제는 좀 더 정확하게 무엇이 RDB에 비해 빠른지 말할 수 있어야한다.
Write Throughput이 높기 때문에 NoSQL이 데이터 추가 연산에 빠르다고 하는 것이다.
'데이터베이스' 카테고리의 다른 글
| RDBMS vs NoSQL (0) | 2024.11.21 |
|---|---|
| Index란 무엇인가. (0) | 2024.10.17 |