시계열 DB에 대해 알아보자
발행일 February 7, 2026 • 6분 소요 • 1091 단어 • 다른 언어 선택: English, 日本語
Table of contents
대규모 아키텍처를 설계하거나, 분산형 시스템을 구축하려고 할 때 Time Series Database(TSDB) 도입을 고려해볼 수 있다. 오늘은 TSDB가 어떤 도구인지, 어떤 특징들을 가지고 있으며, 또 어떤 문제들을 해결하는 데 도움을 주는지를 알아보고자 한다.
1. 시계열 데이터란?
TSDB는 시계열 데이터를 저장하고 처리하는 데이터베이스이다. 그렇다면 시계열 데이터란 무엇인가? 시계열 데이터는 단순히 타임스탬프가 달려 있는 데이터가 아니다. 더 정확하게는 “시간에 따라 추적, 모니터링, 다운샘플링, 집계되는 측정값 또는 이벤트” 라고 정의할 수 있으며, 여기서 말하는 측정값 또는 이벤트에는 아래와 같은 것들이 포함될 수 있다.
- 서버 메트릭
- 애플리케이션 성능 모니터링
- 네트워크 데이터
- IoT 센서 데이터
- 클릭 이벤트
- 마켓 거래 데이터
이러한 데이터들을 다루는 시계열 데이터는 일반적인 DB와는 다르게 아래와 같은 차별점들을 가진다.
- Write heavy: 쓰기 95% 읽기 5%
- Immutable: 한번 기록되면 거의 변경될 일이 없으므로, append-only 방식으로 데이터를 추가
- Ordered by time: 시간 순서대로 정렬되어 있으며, 시간에 따라 인덱싱된 것으로 간주할 수 있음
- High cardinality: 일반적으로 카디널리티가 높음
- Time-based range queries: 시간 범위로 대량 레코드 조회
- Continuous data stream: 지속적으로 데이터 포인트를 수집하는 형태
이러한 특성들을 다루기 위해 TSDB가 어떤 전략들을 취하는지 알아보자.
2. 쓰기 최적화
일반적인 DB의 경우 데이터를 쓰려면 쓰기 위한 위치를 찾고 수정하거나 삽입하는 작업을 수행해야 할 것이다. 아래와 같은 형태로 작업이 진행될 것이다.
[Seek to block 4752] → [Read] → [Modify] → [Write] → [Seek to block 9201] → ...
반면에 TSDB는 기존 데이터를 수정할 필요가 없고, 시간순으로 데이터를 적재하면 되므로 Append-only 방식으로 데이터를 추가하기만 하면 된다. 아래와 같이 작업들이 훨씬 단순화될 것이다.
[Write to end] → [Write to end] → [Write to end] → ...
LSM(Log-Structured Merge) 트리
LSM 트리는 InfluxDB, Cassandra, LevelDB 등 고성능의 쓰기 처리량을 자랑하는 데이터베이스 시스템의 특제 비법 소스다. LSM 트리의 핵심 아이디어는 다음과 같다.
- 비용이 많이 드는 랜덤 쓰기 → 비용이 저렴한 순차 쓰기
- 백그라운드에서 주기적으로 데이터를 재구성함으로써 읽기 효율 향상
그리고 LSM 트리의 작동 방식은 아래와 같다.
- 최신 데이터는 Memtable 메모리 버퍼에 저장
데이터는 키 순서대로 정렬을 유지한다. 이 때 쓰기 작업은 RAM에 접근하므로 속도가 매우 빠르다.
- SSTable(Sorted String Table) 디스크에 플러시
Memtable이 가득 차면 변경 불가능하며 정렬된 SSTable 파일로 저장된다. Memtable은 이미 정렬되어 있으므로 이 플러시 작업은 순차적으로 간단하고 빠르게 완료될 수 있다. 또한 플러시 작업 이후에는 Memtable을 비워주고 초기화한다.
- 백그라운드 압축
백그라운드에서는 작은 SSTable을 더 큰 SSTable로 병합하는 작업을 수행한다. 또한 중복 항목들과 툼스톤(삭제 대상 마크)을 제거하기도 한다.
이러한 LSM 트리의 작동 방식으로 인해 쓰기 작업은 읽기 작업을 방해하지 않게 된다. Memtable은 항상 최신 데이터를 처리하고 백그라운드에서 기존 데이터들을 정리하게 함으로써, 지속적으로 높은 쓰기 처리량을 유지할 수 있다.
하지만 쿼리를 위해 여러 SSTable을 확인해야 하는 경우에는 읽기 성능 저하가 생길 수 있다. 또한 쓰기 증폭이 발생한 경우 압축 과정에서 데이터가 여러 번 재작성될 수 있다.
따라서 LSM 트리는 쓰기 작업량이 많고, 읽기 성능은 어느 정도 희생할 수 있을 때 활용하기 좋다.
3. 시간 기반 인덱싱 및 파티셔닝
시계열 데이터는 이미 타임스탬프 기반으로 정렬되어 삽입되므로 쓰기 작업에 인덱싱이 필요하지 않다. 그리고 시간 범위에 따라 파티셔닝을 하면 쓰기 작업 시 어느 파티션에 데이터를 저장할지 고민할 필요가 없어진다. 데이터 보존 작업 또한 오래된 파티션을 삭제하는 방식으로 간편하게 진행할 수 있다.
블록 레벨 메타데이터
TSDB에서 데이터 블록들 또한 타임스탬프 기반으로 정렬되어 있다. 따라서 시간 범위에 해당하지 않는 블록들은 체킹 없이 스킵할 수 있고, 이에 따라 쿼리 성능이 향상된다. 각 블록에는 시간에 대한 최소/최대 타임스탬프, 필요에 따라 최소/최대 값을 기록해둔다. 이러한 메타데이터는 시간 기반 파티셔닝과 함께 데이터 양이 많아지더라도 쿼리 성능을 유지할 수 있도록 돕는 필터 계층으로 작용한다.
4. 다운샘플링 및 압축
시계열 데이터는 특성상 덜 중요한 내용을 덜어내고 압축해서 표현하기에도 용이하다. 아니, 사실은 초당 수백만 개의 데이터 포인트가 지속적으로 인입된다는 TSDB의 특성상 다운샘플링 작업은 필수적이라고도 할 수 있다. TSDB에서 높은 정밀도를 가진 최신 데이터들은 집계 및 다운샘플링되어 장기 데이터로 변환된다. 일반적인 다운샘플링 및 리텐션 전략은 다음과 같다.
- 원본 데이터: 최근 1일 보관
- 1분 평균값: 최근 7일 보관
- 5분 평균값: 최근 30일 보관
- 1시간 평균값: 최근 1년 보관
- 일일 요약: 영구 보관
이와 같은 규칙들은 사용자가 직접 정의할 수 있으며, 이를 활용해서 저장 효율성 및 읽기 성능을 비약적으로 향상시킬 수 있다.
5. 압축 알고리즘
앞서 말했듯 TSDB의 핵심은 수많은 쓰기 연산을 메모리 버퍼에서 처리하는 것과, 백그라운드에서 압축하는 작업이라고 할 수 있다. 그렇다면 어떻게 압축하는 것일까? 그 부분에 대한 개념들을 알아보자.
델타 인코딩
Raw values: [45.2] [45.3] [45.1] [45.4]
Delta encoded: [45.2] [+0.1] [-0.2] [+0.3]
델타 인코딩은 원본 값에서 얼만큼 변했는지 변화량만 기록하도록 바꾸는 작업이다. 변화값은 원본 값보다는 작은 숫자이므로 값을 저장하는 데에 필요한 bit 수도 훨씬 적어진다.
델타 오브 델타 인코딩
Raw timestamps: 1000, 1010, 1020, 1030, 1040
Deltas: 10 , 10 , 10 , 10 , 10 , ...
Delta-of-deltas: 10 , 0 , 0 , 0 , 0 , ...
델타 오브 델타 인코딩은 더 나아가서 변화량에 대한 변화량을 기록하는 방식이다. 이는 타임스탬프 간격이 완전히 규칙적일 때 사용할 수 있는 방법이며, bit 수를 좀 더 줄여줄 수 있다.
XOR 압축
Value 1: 0 10000010 01101000101000111101011
Value 2: 0 10000010 01101000110000100000000
XOR: 0 00000000 00000000011000011101011
^^^^^^^^^^ lots of leading zeros
XOR 압축은 연속된 float 기반 값들이 종종 유사한 값들을 가진다는 점을 활용하는 압축 알고리즘이다. 위와 같이 동일한 bit 부분을 모두 0으로 치환해서 전체 bit 수를 크게 줄일 수 있는 방식이다. 메타에서 개발한 고릴라 압축 기법도 여기에 해당한다.
Run-length 인코딩
Run-length 인코딩은 모니터링 지표와 같이 측정값이 반복해서 나타나는 경우에 해당 값을 카운트와 함께 하나로만 저장하는 방식이다. 로그인 횟수, 요청 수 등을 기록할 때 용이하다.
6. TSDB 선택 가이드
마지막으로 어떤 상황에서 어떤 TSDB를 활용하는 것이 좋을지 정리해보자.
InfluxDB
- 쿼리 언어: InfluxQL, Flux
- 장점: 이벤트 수집 최적화
- 단점: 분산 시스템 확장이 복잡함
- 배포 방법: 자체 호스팅 / 관리형 클라우드
- 사용 사례: 워크로드가 메트릭 중심의 실시간 데이터 수집인 경우, 데이터 보존 기간이 짧은 경우
Prometheus
- 쿼리 언어: PromQL
- 장점: 쿠버네티스 환경 최적화, Pull 모델이기에 에이전트 설치 불필요
- 단점: 장기 저장을 위한 설계 미비
- 배포 방법: 쿠버네티스에서는 기본적으로 설치되어 있음
- 사용 사례: 쿠버네티스 위주의 아키텍처, 알림 시스템이 필요한 경우
TimescaleDB
- 쿼리 언어: SQL (특히 PostgreSQL에 최적화됨)
- 장점: 관계형 워크로드에 최적화, PostgreSQL 생태계
- 단점: PostgreSQL 관련 의존성 설치 필요
- 배포 방법: 자체 호스팅 / Tiger Data 클라우드
- 사용 사례: 비즈니스 인텔리전스(BI), IoT, 금융 시스템 등 관계형 분석이 필요한 경우
Kdb
- 쿼리 언어: q 언어
- 장점: 가격대가 있는 만큼 지원팀의 지원을 받을 수 있을 것
- 단점: 러닝 커브가 있으며 문서화도 부실함, 상업 용도 라이센스가 비쌈
- 배포 방법: 클라우드 환경 최적화 안 됨, VM에 설치해야 함
- 사용 사례: 극한의 성능이 필요한 경우
Graphite
- 쿼리 언어: 일반 텍스트, Pickle, AMQP 활용
- 장점: 어떤 하드웨어에서 실행하든 뛰어난 성능 발휘
- 단점: 문서화가 부실함, 커뮤니티도 활발하지 않음
- 배포 방법: 컨테이너 이미지 활용
- 사용 사례: 단순하고 가벼운 형태의 오픈 소스 TSDB가 필요한 경우
References
- 알렉스 쉬 - 가상 면접 사례로 배우는 대규모 시스템 설계 기초 2
- influxdata - Time series database explained
- System Design Academy - Why a Time Series Database?
- hello interview - Time Series Databases
- Last 9 - Comparing Popular Time Series Databases
- OctaByte - InfluxDB vs TimescaleDB