493. NoSQL LSM 트리 (Log-Structured Merge-Tree)
⚠️ 이 문서는 빅데이터 시대에 1초에 10만 건씩 쏟아지는 센서 로그나 채팅 데이터를 저장할 때, 하드디스크의 바늘을 이리저리 움직이느라(Random Write) 서버가 죽어버리는 B-Tree의 한계를 극복하기 위해, **모든 데이터를 메모리에 모았다가 한 번에 통째로 디스크에 내려쓰는(Sequential Write) NoSQL의 핵심 엔진인 'LSM 트리'**를 다룹니다.
핵심 인사이트 (3줄 요약)
- 본질: B-Tree가 '읽기'에 최적화된 책갈피라면, LSM 트리는 '쓰기(Write)' 속도에 영혼을 갈아 넣은 극단적인 저장 엔진이다.
- 작동 원리: 데이터가 들어오면 하드디스크에 바로 쓰지 않는다. 일단 메모리(MemTable)에 차곡차곡 모아두었다가, 메모리가 꽉 차면 덩어리째로 디스크(SSTable)에 훅 밀어낸다(Flush).
- 활용: 압도적인 쓰기 속도 덕분에 Cassandra, HBase, RocksDB 등 대용량 데이터를 처리하는 NoSQL 데이터베이스의 표준 엔진으로 사용된다.
(※ 377번 문서에서 기초 개념을 다루었으며, 이 문서는 아키텍처 관점의 쓰기 최적화 메커니즘을 심화로 다룹니다.)
Ⅰ. 개요: 하드디스크의 비명 (Context & Necessity)
하드디스크(HDD)나 SSD는 치명적인 물리적 특성이 있다.
- Random Write (랜덤 쓰기): 여기저기 흩어진 빈 공간에 데이터를 찔끔찔끔 쓰는 것. (엄청나게 느리다)
- Sequential Write (순차 쓰기): 빈 공간의 처음부터 끝까지 멈추지 않고 데이터를 쭈욱 이어서 쓰는 것. (랜덤 쓰기보다 수십 배 이상 빠르다)
기존 RDBMS의 B-Tree는 랜덤 쓰기의 끝판왕이다. 5번 데이터 넣고, 900번 데이터 넣고, 3번 데이터 넣으려면 디스크 바늘이 미친 듯이 널뛰어야 한다. 데이터가 1초에 10만 건씩 들어오면 디스크는 비명을 지르며 뻗어버린다.
이 문제를 해결하기 위해 LSM 트리는 바늘을 움직이지 않기로 했다. "그냥 메모리에 다 모았다가, 꽉 차면 순서대로 이어서 디스크에 한 번에 쭉 써버리자!"
📢 섹션 요약 비유: B-Tree가 학생 한 명이 올 때마다 **'출석부의 가나다순 위치를 찾아서 중간에 끼워 넣는 깐깐한 선생님(Random Write)'**이라면, LSM 트리는 학생들이 올 때마다 **'일단 빈 종이에 온 순서대로 막 적어두고, 종이가 꽉 차면 한 번에 싹 묶어서 캐비닛에 보관하는 쿨한 선생님(Sequential Write)'**과 같습니다. 적는 속도는 비교할 수 없이 빠릅니다.
Ⅱ. LSM 트리의 3단계 쓰기 파이프라인 ★
LSM 트리가 데이터를 디스크에 안전하고 빠르게 밀어 넣는 3단계 메커니즘이다.
1. WAL (Write-Ahead Log) 에 기록
- 데이터를 메모리에만 모아두면 정전 시 다 날아간다.
- 그래서 메모리에 쓰기 직전에, 하드디스크 구석에 있는 '로그 파일(WAL)'에다가 "방금 5번 데이터 들어옴!"이라고 1초 만에 휘갈겨 적어둔다. (영속성 보장 - 456번 문서)
2. MemTable (메모리 테이블) 에 적재
- 로그를 무사히 썼으면, 이제 RAM(메모리)에 있는 MemTable이라는 공간에 데이터를 예쁘게(Key 순서대로 정렬해서) 쌓아둔다. 메모리니까 쓰는 속도는 빛의 속도다.
3. SSTable 로 Flush (디스크 밀어내기)
- 시간이 지나서 MemTable이 꽉 찼다 (예: 64MB).
- 이제 이 64MB 덩어리를 하드디스크에 **SSTable(Sorted String Table)**이라는 하나의 파일로 뭉텅이로 쏟아낸다.
- 이 파일은 한 번 쓰이면 절대 수정되지 않는다(Immutable). 즉, 디스크 바늘은 중간에 멈출 필요 없이 64MB를 한 번에 쭈욱 순차 쓰기(Sequential Write)를 하고 끝낸다.
Ⅲ. 읽기의 페널티와 병합(Compaction)
쓰기가 미친 듯이 빠르지만, 대가는 혹독하다. 읽기(Read)가 너무 느려진다. "10번 데이터 찾아줘!"
- 메모리(MemTable)를 뒤진다. 없다.
- 디스크에 밀려난 SSTable 1번 파일을 뒤진다. 없다.
- SSTable 2번 파일을 뒤진다... 결국 디스크에 쌓인 수십 개의 파일을 다 뒤져야 할 수도 있다.
이 끔찍한 읽기 속도를 살려내기 위해, 밤마다 **콤팩션(Compaction - 378번 문서)**이 돌아간다. 여러 개로 쪼개진 SSTable 파일들을 읽어 들여서, 쓰레기(삭제된 데이터)는 버리고 하나의 크고 깔끔한 SSTable 파일로 다시 뭉쳐주는(Merge) 작업이다.
┌──────────────────────────────────────────────────────────────┐
│ LSM-Tree의 쓰기 최적화 (Write Pipeline) 시각화 │
├──────────────────────────────────────────────────────────────┤
│ │
│ [ 👨💻 데이터 10만 건 쏟아짐! ] │
│ │ │
│ ├── 1. WAL 로그에 빠르게 휘갈김 (정전 대비용) │
│ ▼ │
│ [ 🧠 MemTable (RAM) ] ── (가득 차면?) ──▶ [ Flush! (밀어내기) ] │
│ (데이터를 Key 순으로 정렬) │ │
│ │ │
│ ▼ (한 번에 쭈욱 이어 씀)│
│ [ 💾 디스크 ] │
│ 파일 3: [SSTable_3] ◀── (방금 내려온 파일, 제일 최신) │
│ 파일 2: [SSTable_2] │
│ 파일 1: [SSTable_1] ◀── (가장 옛날에 내려온 파일) │
│ │
│ ★ 특징: 디스크는 "새 파일 만들어서 통째로 쓰기"만 반복하므로 랙이 안 걸린다! │
└──────────────────────────────────────────────────────────────┘
Ⅳ. 결론
"디스크의 물리적 한계를 가장 우아하게 우회한 소프트웨어 아키텍처." LSM 트리는 쓰기 증폭(Write Amplification - 콤팩션 때문에 데이터가 여러 번 다시 쓰이는 현상)이라는 페널티를 감수하면서까지, 오직 '순차 쓰기(Sequential Write)'가 주는 압도적인 성능적 이점을 취한 극단적인 트레이드오프의 산물이다. IoT 센서 데이터, 주식 차트의 초당 호가 데이터, 카카오톡의 실시간 채팅 기록처럼 "일단 미친 듯이 쏟아져 들어오고, 어쩌다 한 번씩 읽어보는" 빅데이터 환경에서 LSM 트리는 B-Tree를 완전히 밀어내고 NoSQL의 심장으로 완벽하게 자리 잡았다.
📌 관련 개념 맵
- 관련 데이터베이스: Apache Cassandra, RocksDB, LevelDB, HBase
- 필수 짝꿍 기술: Compaction (콤팩션 - 378번 문서), Bloom Filter (블룸 필터 - 안 열어보고 파일 안에 데이터 없는 거 맞추는 마법)
- 대척점 기술: B+Tree (읽기 최적화 엔진 - 422번 문서)
👶 어린이를 위한 3줄 비유 설명
- B-Tree는 단어장에 단어를 적을 때마다 '가나다순' 페이지를 펼쳐서 중간에 예쁘게 끼워 적는 방식이에요. 찾기는 쉽지만 적을 때 너무 귀찮죠.
- LSM 트리는 단어를 일단 연습장(MemTable)에 막 적어둬요. 그리고 연습장이 꽉 차면, 그 장을 찢어서 '다 쓴 연습장 철' 맨 뒤에 통째로 끼워 넣어요(SSTable).
- 적을 때는 엄청 빠르지만, 나중에 단어를 찾을 때는 '다 쓴 연습장 철'을 한 장씩 다 뒤져봐야 하는 단점이 있답니다!