View

728x90
반응형

Kafka 내부 구조를 살펴보면 RocksDB가 등장한다. TiKV 문서를 보면 또다시 RocksDB가 나온다. CockroachDB의 옛 버전도 RocksDB를 썼고, MyRocks라는 MySQL 변종 역시 RocksDB 기반이다. 도대체 이 컴포넌트가 무엇이길래 이렇게 광범위하게 채택되는 것인가?

 

다만 한국어로 RocksDB를 제대로 정리한 글은 많지 않다. 위키백과는 너무 짧고, 개발 블로그들은 LSM-Tree만 깊게 파고들거나 코드만 던져둔다. "이게 무엇이고 왜 쓰며 어디서 쓰이는지"가 한 번에 잡히는 글이 부족하다고 느껴 직접 정리한다.

 

각설하고 한 줄로 요약하면, RocksDB는 데이터베이스라기보다 "데이터베이스의 부품"에 가깝다. 그래서 직접 사용할 일은 거의 없지만, 그럼에도 알아 두어야 백엔드 시스템 내부를 제대로 이해할 수 있다.

 

RocksDB는 도대체 무엇인가

 

 

출처: logo.wine

 

한 줄로 정의하면 페이스북(현 Meta)이 만든 임베디드 키-밸류 스토어다. C++로 작성되었고 Java, Python, Go, Rust 바인딩이 모두 제공된다. 라이선스는 GPLv2와 Apache 2.0 듀얼 라이선스이므로 상용 프로젝트에서도 부담 없이 도입할 수 있다.

 

핵심 키워드는 "임베디드"와 "키-밸류"이다. 이 두 단어가 RocksDB의 정체성을 결정한다.

 

임베디드 DB란 무엇인가

 

임베디드(embedded)는 "박혀 있다"는 뜻이다. MySQL이나 PostgreSQL처럼 별도 서버 프로세스로 띄우는 것이 아니라, 애플리케이션 안에 라이브러리 형태로 박혀서 함께 동작하는 DB를 말한다. 네트워크 통신도 없고 별도 데몬도 없다. 그저 프로세스 메모리 안에서 함수 호출하듯 데이터를 읽고 쓴다.

 

비슷한 사례로 SQLite가 있다. SQLite도 임베디드이지만 SQL을 지원한다. 반면 RocksDB는 SQL을 사용하지 않고 Put(key, value), Get(key) 같은 단순 KV 인터페이스만 제공한다.

 

서버형 DB(MySQL, PostgreSQL)는 별도 데몬으로 떠 있고 TCP나 Unix Socket으로 통신하므로 다중 클라이언트가 붙을 수 있는 대신 모니터링이나 백업 등 운영 부담이 크다. 반면 임베디드 DB는 라이브러리로 링크해 함수 호출로 마무리되므로 단일 프로세스에서만 사용하지만 운영 부담이 거의 없다.

 

키-밸류 스토어란

 

key를 던지면 value를 돌려주는 단순한 모델이다. SQL의 JOIN이나 복잡한 쿼리는 존재하지 않는다. user:123 키에 JSON 값 하나를 박아 두고 꺼내 쓰는 방식이다. 단순한 만큼 빠르고, 단순한 만큼 분산 시스템에 끼워 넣기 쉽다.

 

왜 만들어졌는가: 페이스북이 LevelDB를 포크한 이유

 

 

출처: influxdata.com

 

RocksDB는 2012년 페이스북에서 출발했다. 새로 작성된 것이 아니라 구글이 만든 LevelDB를 포크한 결과물이다. LevelDB는 2011년 구글의 Jeff Dean과 Sanjay Ghemawat(BigTable을 만든 그 두 사람)이 오픈소스로 공개한 임베디드 KV 라이브러리다.

 

다만 LevelDB가 페이스북 워크로드에서 한계를 드러냈다. 가장 큰 문제는 LevelDB가 HDD 시절의 디자인 그대로였다는 점이다. 2011년이면 SSD가 막 보급되던 시기였는데 LevelDB는 그 변화를 반영하지 못했다. 거기에 싱글 스레드 위주여서 멀티코어 서버에서 CPU를 놀리고 있었고, 페이스북 규모의 쓰기 부하를 받아내기에는 write throughput이 부족했다. 옵션도 빈약해 워크로드별 튜닝이 거의 불가능한 수준이었다.

 

페이스북이 이 코드를 포크해 SSD 최적화, 멀티스레드, 풍부한 튜닝 옵션을 더해 RocksDB를 만들었다. 현재는 Meta 내부에서만 수백 개 서비스가 사용 중이며, 외부에서도 사실상 임베디드 KV의 디폴트 선택지로 자리 잡았다.

 

LevelDB와 무엇이 다른가

 

핵심 차이를 표로 정리하면 다음과 같다.

 

항목 LevelDB RocksDB
출시 2011 (Google) 2012 (Facebook)
동시성 단일 스레드 위주 멀티스레드 Compaction
Column Family 없음 지원 (네임스페이스 분리)
Bloom Filter 기본만 다양한 옵션
Compression Snappy 정도 Snappy, Zlib, LZ4, ZSTD 등
트랜잭션 없음 Optimistic/Pessimistic 지원
Backup/Checkpoint 없음 있음
튜닝 옵션 적음 100개 가까이

 

RocksDB는 LevelDB에 SSD 시대의 옷을 입히고 멀티코어 활용을 더한 강화판이라고 보면 된다.

 

LSM-Tree 구조: RocksDB의 진짜 핵심

 

 

출처: scylladb.com

 

RocksDB가 빠른 이유는 LSM-Tree(Log-Structured Merge-Tree) 구조 때문이다. 이 구조를 모르면 RocksDB를 안다고 할 수 없다. 그래서 다소 자세히 다룬다.

 

데이터가 어떻게 흐르는가

 

쓰기가 들어왔을 때의 흐름은 대략 이렇다. 먼저 WAL(Write-Ahead Log)에 append로 기록한다. 크래시 복구용이다. 그다음 메모리의 MemTable에 정렬된 자료구조(보통 Skip List) 형태로 보관한다. MemTable이 가득 차면 Immutable MemTable로 전환해 더 이상 쓰기를 받지 않고, 백그라운드 스레드가 이를 SSTable로 디스크에 flush한다. SSTable이 여러 개 쌓이면 다시 백그라운드에서 Compaction이 동작하면서 레벨별로 병합한다.

 

읽기는 그 반대다. MemTable을 먼저 보고, 없으면 Immutable MemTable, 그래도 없으면 디스크 SSTable을 Level 0부터 차례로 뒤진다. 그래서 읽기가 느려질 수 있는데, Bloom Filter로 "이 SSTable에 키가 없음"을 빠르게 걸러 내고 Block Cache로 자주 사용되는 블록을 메모리에 유지하면서 어느 정도 보완한다.

 

왜일까? Write가 빠른 이유

 

핵심은 Sequential Write이다. B-Tree 기반 DB(MySQL InnoDB 등)는 데이터를 디스크의 정해진 위치에 직접 써야 한다. 그러면 디스크 헤드가 여기저기 점프해야 하는 Random Write가 발생한다. HDD에서는 이것이 치명적으로 느렸고, SSD에서도 부담이다.

 

LSM-Tree는 일단 메모리에 쓰고, 디스크에는 큰 덩어리로 한 번에 sequential하게 떨어뜨린다. write-heavy 워크로드에서 차이가 크게 벌어지는 이유가 여기에 있다. RocksDB 공식 벤치마크 기준으로 random write 처리량이 LevelDB의 수 배 수준에 이른다.

 

B-Tree(MySQL InnoDB)와 비교하면

 

이 부분이 입문자가 가장 궁금해하는 지점인데, 한국어로 정리된 자료가 적어 다소 풀어 적는다.

 

B-Tree 계열(InnoDB, PostgreSQL)은 한 번의 lookup으로 데이터 위치를 바로 찾기 때문에 read가 빠르고, range query도 트리 구조 덕분에 강하다. 다만 write가 들어올 때마다 정해진 페이지를 갱신해야 해서 random IO가 발생하고, 페이지 단위 빈 공간 때문에 공간 효율은 떨어진다. 그래서 read-heavy OLTP에 적합하다.

 

LSM-Tree(RocksDB)는 정반대 성향이다. write는 sequential로 떨어뜨리므로 빠르지만, read는 여러 레벨의 SSTable을 뒤져야 하므로 상대적으로 느리다. range query는 약점이 더 두드러진다. 대신 정렬된 채로 압축되므로 공간 효율이 좋고, write-heavy나 시계열 데이터에 잘 맞는다. 운영 측면에서는 Compaction 튜닝이라는 골치 아픈 포인트가 추가된다.

 

쉽게 말하면 읽기 위주는 B-Tree, 쓰기 위주는 LSM-Tree다. 다만 SSD가 보편화되고 Bloom Filter나 Block Cache 같은 보조 장치가 발달하면서 LSM-Tree의 read 약점은 상당히 좁혀졌다.

 

Compaction이란 무엇인가

 

LSM-Tree에서 가장 골치 아픈 부분이자 핵심 메커니즘이다. SSTable이 레벨별로 쌓이는데, 시간이 지나면 같은 키에 대한 여러 버전이 여러 SSTable에 흩어져 있을 수 있다. 이를 백그라운드에서 병합하면서 오래된 버전을 제거하고 정리하는 작업이 Compaction이다.

 

문제는 이 작업이 공짜가 아니라는 점이다. CPU와 IO를 동시에 잡아먹고, 같은 데이터를 여러 번 다시 쓰게 된다. 이를 Write Amplification이라 부른다.

 

Write Amplification이란

 

사용자가 1MB를 썼는데 Compaction 때문에 디스크에는 10MB가 쓰일 수 있다. 이 비율(10배)이 Write Amplification이다. SSD 입장에서는 수명에 영향을 주는 부분이다. 다만 SSD가 워낙 빨라서 trade-off로 받아들이는 추세이다.

 

RocksDB는 이를 줄이기 위해 Universal Compaction, Tiered Compaction 같은 여러 전략을 옵션으로 제공한다. 워크로드에 따라 골라 쓸 수 있다.

 

어디서 RocksDB를 사용하는가: 실제 사용 사례

 

 

출처: tikv.org

 

이 부분이 진짜 중요하다. RocksDB는 그 자체로 사용되기보다 다른 시스템의 부품으로 박혀 있는 경우가 압도적으로 많다.

 

Apache Kafka (Kafka Streams)

 

Kafka Streams의 state store 기본 구현이 RocksDB다. 스트림 처리 도중 중간 상태(예: 윈도우 집계, 조인 테이블)를 저장해야 하는데, 이를 메모리에만 두면 OOM이 나고 외부 DB에 두면 느리다. 따라서 로컬 디스크에 임베디드 KV로 박는 것이 정답이고, 그 자리를 RocksDB가 차지한다.

 

TiKV / TiDB

 

PingCAP이 만든 분산 DB다. TiKV가 RocksDB를 노드별 스토리지 엔진으로 사용한다. 그 위에 Raft 합의 알고리즘을 얹어 분산 트랜잭션을 구현한다. 즉 RocksDB는 단일 노드 KV 역할만 하고, 분산 부분은 위 레이어에서 처리하는 구조이다.

 

CockroachDB

 

CockroachDB도 초기에는 RocksDB를 사용했다. 그러나 2020년 무렵 자체 스토리지 엔진인 Pebble(Go로 작성)로 갈아탔다. 이유는 GC 호환성, Go 생태계 일관성, Cgo 오버헤드 제거 등이었다. RocksDB가 뛰어나도 만능은 아니라는 좋은 사례이다.

 

MyRocks (MySQL)

 

페이스북이 직접 만든 MySQL 스토리지 엔진이다. InnoDB(B-Tree) 자리를 RocksDB(LSM-Tree)로 갈아 끼운 것이다. 페이스북 내부에서 UDB(User Database)에 실제로 운영 중이다. 압축률이 InnoDB 대비 2~3배 좋아 SSD 비용을 크게 절감했다는 점이 도입 사유였다. 자세한 도입기는 Meta Engineering 블로그의 MyRocks 포스트에 잘 정리되어 있다.

 

그 외

 

  • YugabyteDB: TiKV처럼 RocksDB 기반 분산 DB
  • Dgraph: 그래프 DB. 초기에 RocksDB를 썼다가 자체 Go 구현인 Badger로 완전히 이전
  • Bitcoin Core: 블록 인덱스/UTXO 저장에 LevelDB 사용(RocksDB는 미사용. 다만 외부 BTC 인덱서들은 RocksDB 채택)
  • Apache Cassandra: Instagram이 RocksDB 백엔드(Rocksandra) 프로젝트로 실험
  • Ceph: BlueStore 메타데이터 저장에 RocksDB

 

왜 다들 RocksDB를 채택하는가

 

이유는 크게 네 가지로 압축된다. 첫째, 검증된 임베디드 KV가 별로 없다. 대안이 LevelDB(낡음), LMDB(read-heavy 위주), BadgerDB(Go 전용) 정도여서 선택지가 좁다. 둘째, 페이스북이 운영하면서 단련된 코드라는 점이며, 버그가 생길 만한 부분은 거의 잡혔다고 보아도 무방하다. 셋째, C++ 성능에 풍부한 튜닝 옵션이 더해져 워크로드에 맞춰 최적화가 가능하다. 마지막으로 커뮤니티와 업데이트가 활발해 GitHub 이슈/PR이 빠르게 회전한다는 점도 크다.

 

RocksDB의 단점도 솔직하게

 

광고처럼 보이지 않으려면 단점도 함께 봐야 한다. 다른 글들이 잘 다루지 않는 부분이다.

 

Range query가 약하다는 점이 가장 자주 지적된다. SELECT * FROM table WHERE id BETWEEN 100 AND 200 같은 범위 쿼리는 여러 SSTable을 머지하면서 읽어야 하므로 B-Tree 대비 느리다. Bloom Filter도 point lookup에는 도움이 되지만 range scan에는 별 효과가 없다.

 

Compaction 비용도 만만치 않다. 위에서 언급한 Write Amplification 외에도, Compaction이 IO와 CPU를 백그라운드에서 잡아먹기 때문에 트래픽 피크 시간에 Compaction이 겹치면 latency spike가 발생할 수 있다. 이를 통제하는 것이 운영의 핵심이다.

 

튜닝이 복잡하다는 점도 입문 장벽이다. RocksDB의 옵션은 100개에 가깝다. write_buffer_size, max_write_buffer_number, level0_file_num_compaction_trigger, target_file_size_base 등이 끝없이 등장한다. 잘못 설정하면 성능이 급락한다. RocksDB Wiki에 튜닝 가이드가 있긴 하지만 입문자에게는 부담스럽다.

 

메모리 사용량도 무시할 수 없다. MemTable, Block Cache, Bloom Filter, Index/Filter Block 등이 모두 메모리를 잡아먹어, 임베디드라 해서 메모리를 적게 쓰는 것이 아니다. 오히려 제대로 동작시키려면 충분한 RAM이 필요하다.

 

마지막으로 트랜잭션 지원도 제한적이다. Optimistic/Pessimistic 트랜잭션은 있지만 MySQL InnoDB 같은 풀스펙 ACID는 아니다. 분산 트랜잭션은 당연히 지원하지 않는다(그것은 위 레이어에서 처리해야 한다).

 

그렇다면 RocksDB를 직접 사용해야 하는가

 

 

출처: themythicalengineer.com

 

대부분의 개발자는 RocksDB를 사용하는 시스템(Kafka, TiKV, MyRocks 등)을 사용하는 입장이지, 직접 RocksDB API를 호출할 일은 드물다. 직접 손댈 일이 생기는 케이스는 보통 다음과 같다.

 

  • 로컬 캐시: Redis보다 가볍게, 디스크 기반 KV 캐시가 필요할 때
  • 임베디드 시스템: 모바일/IoT에서 작은 KV가 필요할 때
  • 로그/메트릭 인덱스: write-heavy인 시계열 데이터 저장
  • 새로운 DB/시스템 제작: 스토리지 엔진으로 박아 넣기

 

대안도 존재한다. Read-heavy 워크로드라면 메모리 매핑 기반의 LMDB가 더 빠를 수 있고, Go 생태계라면 CockroachDB가 만든 RocksDB 호환 엔진 Pebble이 합리적이다. 같은 Go에서 키/값 분리 저장 모델이 필요하다면 BadgerDB가 있고, SQL이 반드시 필요하다면 SQLite가 답이다.

 

핵심 정리

 

여기까지 읽었다면 RocksDB가 무엇인지 대략 감이 잡혔을 것이다. 한 줄씩 박아 정리하면 다음과 같다.

 

  • RocksDB는 페이스북이 2012년에 LevelDB를 포크해 만든 임베디드 키-밸류 스토어이다
  • C++로 작성되었고 SSD 최적화, 멀티스레드, 풍부한 튜닝 옵션이 강점이다
  • LSM-Tree 구조라 write가 빠르고 압축률이 좋다. 다만 read와 range query는 상대적으로 약하다
  • Kafka, TiKV, MyRocks, YugabyteDB 등 수많은 시스템이 부품으로 채택한다
  • 단점은 Compaction 비용, Write Amplification, 튜닝 복잡성, 메모리 사용량이다

 

핵심 메시지를 한 줄로 다시 박으면, RocksDB는 데이터베이스라기보다 데이터베이스의 부품이다. 그래서 직접 사용할 일은 적지만, 백엔드 시스템 내부 구조를 이해하려면 반드시 알아야 하는 컴포넌트이다.

 

내부 동작을 더 깊이 파보고 싶다면 LSM-Tree 구조 완전 정복 글이나 B-Tree vs LSM-Tree 어느 것이 더 빠른가 글을 따라 읽어 보길 권한다. 실전 사례가 궁금하다면 Kafka Streams가 RocksDB를 사용하는 이유 글도 추천한다. 공식 자료는 rocksdb.orgGitHub facebook/rocksdb에 모두 정리되어 있다.

 

운영하다 보면 결국 마주치는 것은 Compaction 튜닝과 Write Amplification 모니터링이다. 거기서부터 RocksDB는 진짜로 시작된다.

728x90
반응형
Share Link
reply
«   2026/05   »
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