쓰기 증폭 최적화와 LSM-Tree 기반 RocksDB 스토리지 아키텍처
RocksDB의 WAL·MemTable·SST와 compaction은 쓰기 내구성·읽기·공간 사이의 비용을 조정합니다. 증폭률과 stall은 옵션·버전·workload에 따라 달라집니다.
발행·오류 제보: infostoa · 편집 기준
이 글의 개별 작성자와 전문 검토자 정보는 제공되지 않습니다.
RocksDB LSM 트리의 쓰기 경로와 compaction 조건
RocksDB는 embedded key-value 저장 엔진으로, LSM 구조에서 쓰기 경로에 WAL과 메모리 MemTable을 사용하고 flush된 정렬 데이터를 SST 파일로 저장합니다. WAL 사용 여부와 동기화는 WriteOptions 및 DB 설정에 영향을 받으므로 모든 쓰기가 응답 전에 안정 저장소에 도달한다고 가정할 수 없습니다. flush는 memtable 데이터를 새 SST 파일로 만들고, compaction은 여러 SST를 병합해 오래된 버전과 삭제 tombstone을 제거할 수 있습니다. 이는 매번 모든 데이터를 순차 쓰기만 한다는 뜻이 아니며, 읽기와 compaction에서 반복적인 읽기·재기록이 발생합니다.
전문가 관점: RocksDB 엔지니어 Jay Zhuang의 compaction 분석
RocksDB 엔지니어 Jay Zhuang은 다음 레벨의 SST 경계에 맞춰 compaction 출력 파일을 자르면 특정 level-compaction에서 재작업을 줄일 수 있다고 분석했습니다. 해당 변경은 RocksDB 7.8 이상에서 기본 활성화된다고 글은 설명하지만, 제시한 10% 이상 쓰기 증폭 개선은 특정 설계와 db_bench 조건의 결과입니다. 글의 simulator는 동일한 key-value 크기를 가정하고 삭제, 압축, compaction 중 write stall을 모델링하지 않는 한계가 있습니다. 이 수치를 임의의 프로덕션 환경 성능 보장으로 일반화할 수 없습니다.
compaction 방식과 읽기 경로
Leveled compaction에서는 L0 파일의 key range가 겹칠 수 있고, 하위 레벨은 보통 해당 레벨 안에서 범위가 겹치지 않도록 유지합니다. 하지만 universal/tiered compaction 등 다른 스타일은 파일 중첩과 읽기 비용 특성이 다릅니다. 따라서 모든 LSM 트리가 레벨마다 10배 용량 또는 동일한 compaction 규칙을 갖는다는 설명은 부정확합니다. 읽기에서는 memtable, 여러 SST, block cache, index와 filter가 관여합니다. Bloom filter는 없는 key의 탐색을 건너뛰게 도울 수 있지만 false positive가 가능하고, 저장·메모리·CPU 비용과 설정이 따릅니다. “99% I/O 제거” 같은 고정 효과는 데이터와 filter 구성에 따라 달라집니다.
튜닝 시 관찰할 지표와 테스트
LSM 엔진은 write amplification, read amplification, space amplification 사이의 trade-off를 가집니다. 입력률이 background compaction 처리율을 오래 앞서면 pending compaction이 늘고 write stall이 생길 수 있습니다. write_buffer_size, background job 수, level 크기 배율, compaction style, compression, block cache, Bloom filter bits 등을 함께 봐야 합니다. RocksDB option의 이름·기본값·효과는 버전에 따라 바뀔 수 있으므로 실제 라이브러리 release와 옵션 문서를 확인합니다. 대표 key 분포, update·delete 비율, 값 크기, 동시 읽기·쓰기 조건으로 db_bench 또는 서비스 부하를 재현하고, p95/p99 지연, pending compaction bytes, stall 시간, 디스크 쓰기량과 공간을 비교하세요.
가상 workload에서 증거를 해석하고 다음 실험 고르기
아래 workload와 수치는 설명을 위한 가상 사례이며 RocksDB의 측정 결과나 권장 기본값이 아닙니다. 예를 들어 key 16B, value 1KiB, point read 70%·overwrite 25%·delete 5%, 고정된 동시성으로 30분간 부하를 준다고 정의합니다. 먼저 dataset이 block cache보다 큰지, warm-up 구간을 제외했는지, 입력 바이트와 장치 쓰기를 같은 시간 창에서 집계했는지 기록합니다. 다른 조건이 달라지면 비교가 흐려집니다.
| 가상 관측 증거 | 우선 해석할 가설 | 다음 단일 변수 검증 |
|---|---|---|
| 같은 측정 창에서 DB 입력 10 MB/s, 장치 쓰기 30 MB/s | 이 가정 아래 총 쓰기량/입력량은 약 3입니다. compaction 외 WAL·다른 프로세스 쓰기가 섞였는지 먼저 분리해야 합니다. | DB 통계와 장치 지표의 시간 창을 맞추고 다른 프로세스 쓰기를 분리해 기준선을 다시 잽니다. 아직 옵션을 바꾸지 않습니다. |
L0 파일 수와 pending compaction bytes가 함께 증가하고 STALL_MICROS도 상승 | compaction이 입력을 따라가지 못해 stall이 생기는지 의심할 수 있습니다. 이것만으로 background job 수 부족을 확정하진 않습니다. | 기준 설정과 workload를 고정하고 background compaction job 수만 한 단계 바꿔 반복합니다. stall 시간·p99 쓰기 지연·장치 사용률을 함께 비교합니다. |
| point-read p99가 나빠지지만 write stall은 거의 없고 block-cache hit가 낮아짐 | 이 workload에서는 read 경로/cache 압박이 후보입니다. compaction만이 원인이라고 결론내릴 수 없습니다. | 나머지를 고정하고 block cache 용량 하나만 바꿔 hit율·물리 읽기·p99를 비교합니다. |
각 실험은 같은 seed와 데이터셋에서 반복하고, 설정·RocksDB 버전·하드웨어·warm-up·측정 구간을 남기세요. 결과가 한 지표만 좋아지고 다른 지표가 나빠질 수 있으므로 목표 지표와 허용 가능한 비용을 먼저 정합니다. RocksDB 튜닝 가이드도 먼저 통계와 시스템 병목을 확인한 뒤 workload에 맞춰 조정하도록 안내합니다(RocksDB Tuning Guide, Compaction Stats and DB Status).