[Daily morning study] Time-series 데이터베이스 개념과 활용

#daily morning study

Image


Time-series 데이터베이스란

Time-series 데이터베이스(TSDB)는 시간 순서로 기록된 데이터를 저장하고 조회하는 데 최적화된 데이터베이스다. 일반 RDB와 달리 타임스탬프를 기본 인덱스로 사용하고, 시간 범위 쿼리와 집계 연산에 특화된 저장 구조를 가진다.

시계열 데이터의 특성

  • 추가 위주(append-only): 새로운 데이터가 계속 들어오지만 과거 데이터를 수정하는 경우는 드물다.
  • 높은 쓰기 처리량: 수천 개의 센서나 서버 메트릭이 1초 단위로 데이터를 발생시킨다.
  • 시간 기반 범위 조회: “최근 1시간”, “어제 오후 3시~5시” 같은 시간 범위 쿼리가 대부분이다.
  • 자동 만료(retention): 오래된 데이터는 용량 절약을 위해 자동으로 삭제하거나 압축한다.

대표적인 활용 사례

  • 서버 메트릭(CPU, 메모리, 네트워크) 모니터링
  • IoT 센서 데이터 수집
  • 주식·코인 가격 이력
  • 사용자 행동 이벤트 로그

RDB와의 비교

일반 RDB에 시계열 데이터를 저장하면 아래 문제가 생긴다.

-- 서버 메트릭 테이블 예시 (RDB)
CREATE TABLE metrics (
    id         BIGINT PRIMARY KEY AUTO_INCREMENT,
    server_id  VARCHAR(50),
    metric     VARCHAR(50),
    value      DOUBLE,
    ts         DATETIME
);
  • 행(row) 하나에 메타데이터(server_id, metric 이름)가 중복 저장되어 공간 낭비가 심하다.
  • 시간 범위 조회를 위한 인덱스를 별도로 관리해야 한다.
  • 초당 수십만 건의 INSERT를 처리하기 어렵다.

TSDB는 이 문제를 다음과 같이 해결한다.

항목RDBTSDB
기본 인덱스PK (id)타임스탬프
쓰기 최적화트랜잭션 우선배치 압축 쓰기
과거 데이터 처리수동 파티셔닝자동 downsampling/retention
공간 효율낮음 (메타데이터 중복)높음 (델타 인코딩, 압축)

주요 TSDB 제품

InfluxDB

가장 널리 쓰이는 오픈소스 TSDB. 자체 쿼리 언어인 Flux(또는 InfluxQL)를 사용한다.

# InfluxDB 3.x 기준 (line protocol로 데이터 쓰기)
# measurement,tag_key=tag_value field_key=field_value timestamp
cpu,host=server01,region=us-east usage_idle=87.3,usage_user=12.7 1728432000000000000
  • Measurement: 관계형 DB의 테이블에 해당
  • Tag: 인덱싱되는 메타데이터 (서버명, 지역 등)
  • Field: 실제 측정값 (CPU 사용률, 온도 등)
  • Timestamp: 나노초 단위까지 저장 가능
from influxdb_client import InfluxDBClient, Point
from datetime import datetime

client = InfluxDBClient(url="http://localhost:8086", token="my-token", org="my-org")
write_api = client.write_api()

point = (
    Point("cpu_usage")
    .tag("host", "server01")
    .field("usage_idle", 87.3)
    .field("usage_user", 12.7)
    .time(datetime.utcnow())
)
write_api.write(bucket="monitoring", record=point)

Prometheus

쿠버네티스 환경에서 표준처럼 쓰이는 풀(pull) 기반 모니터링 TSDB. 자체 쿼리 언어 PromQL을 사용한다.

# 지난 5분간 평균 CPU 사용률
100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)

# 메모리 사용량이 80% 초과인 인스턴스
(1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) > 0.8

Prometheus는 데이터를 직접 저장하기보다 단기 보관용으로 쓰고, 장기 보관은 Thanos나 VictoriaMetrics 같은 외부 저장소에 위임하는 경우가 많다.

TimescaleDB

PostgreSQL의 확장 기능으로 동작하는 TSDB. 기존 SQL 문법을 그대로 쓸 수 있어 RDB 경험이 있는 팀이 도입하기 쉽다.

-- TimescaleDB 하이퍼테이블 생성
CREATE TABLE metrics (
    ts       TIMESTAMPTZ NOT NULL,
    host     TEXT,
    cpu_idle DOUBLE PRECISION,
    cpu_user DOUBLE PRECISION
);

SELECT create_hypertable('metrics', 'ts');

-- 일반 SQL로 시간 범위 조회
SELECT time_bucket('1 minute', ts) AS bucket,
       host,
       AVG(cpu_idle) AS avg_idle
FROM metrics
WHERE ts > NOW() - INTERVAL '1 hour'
GROUP BY bucket, host
ORDER BY bucket DESC;

저장 구조 — 왜 빠른가

시간 기반 청크(Chunk) 분할

TSDB는 데이터를 시간 범위별로 청크(파티션)로 나눠 저장한다.

[2026-10-09 00:00 ~ 01:00] → chunk_001
[2026-10-09 01:00 ~ 02:00] → chunk_002
...
[2026-10-09 23:00 ~ 00:00] → chunk_024

최근 1시간을 조회할 때 전체 테이블을 스캔하지 않고 해당 청크만 읽는다.

델타 인코딩과 압축

시계열 데이터는 연속적인 값의 변화량(delta)이 작은 경우가 많다. Gorilla 압축 알고리즘(InfluxDB, Prometheus 채택)은 다음 원리를 사용한다.

원래 값:   87.3, 87.5, 87.4, 88.0, 87.9
첫 번째:   87.3 (전체 저장)
이후:      +0.2, -0.1, +0.6, -0.1 (차이만 저장, 비트 압축)

이 방식으로 일반 부동소수점 저장 대비 1/10 수준의 공간으로 줄이는 경우도 있다.


Retention Policy와 Downsampling

Retention Policy

오래된 데이터를 자동 삭제하는 규칙이다.

-- InfluxDB: 30일 지난 데이터 자동 삭제
CREATE RETENTION POLICY "30days" ON "monitoring" 
DURATION 30d REPLICATION 1 DEFAULT;

Downsampling (연속 쿼리)

원시 데이터는 단기 보관하고, 집계된 데이터는 장기 보관하는 전략이다.

원시 데이터 (1초 단위)  → 7일 보관
1분 평균 집계            → 30일 보관
1시간 평균 집계          → 1년 보관
# InfluxDB Flux로 downsampling 예시
from(bucket: "raw_metrics")
  |> range(start: -1h)
  |> filter(fn: (r) => r._measurement == "cpu_usage")
  |> aggregateWindow(every: 1m, fn: mean, createEmpty: false)
  |> to(bucket: "downsampled_metrics")

실제 스택 구성 예시

서버 모니터링 (Prometheus + Grafana)

서버/컨테이너
    ↓ (메트릭 노출, /metrics 엔드포인트)
Node Exporter / cAdvisor
    ↓ (scrape, 15초마다 pull)
Prometheus
    ↓ (PromQL 쿼리)
Grafana (대시보드 시각화)

IoT 데이터 수집 (InfluxDB)

IoT 디바이스
    ↓ (MQTT 프로토콜)
Telegraf (데이터 수집 에이전트)
    ↓ (Line Protocol)
InfluxDB
    ↓ (Flux/InfluxQL)
Grafana

Telegraf는 InfluxDB에서 만든 오픈소스 에이전트로, 200개 이상의 플러그인으로 다양한 소스(MySQL, Redis, Kafka 등)에서 메트릭을 수집해 TSDB에 쓸 수 있다.


카디널리티(Cardinality) 문제

TSDB에서 흔히 발생하는 성능 이슈다. InfluxDB와 Prometheus는 태그(레이블) 조합 수를 기준으로 인덱스를 관리한다.

host=server01, region=us-east, env=prod → 1개 시리즈
host=server02, region=us-east, env=prod → 1개 시리즈
...

태그 값의 종류가 많아지면(예: user_id를 태그로 사용) 시리즈 수가 폭발적으로 증가해 메모리 사용량과 인덱스 크기가 급증한다. 이를 high cardinality 문제라고 부른다.

해결 방법

  • user_id처럼 고유값이 많은 항목은 태그 대신 field로 저장한다.
  • 불필요하게 세분화된 태그는 제거한다.
  • Prometheus의 경우 레이블 수를 최소화하고, 레코딩 룰(recording rules)로 사전 집계한다.

정리

구분InfluxDBPrometheusTimescaleDB
주요 용도IoT, 일반 메트릭쿠버네티스 모니터링PostgreSQL 기반 확장
쿼리 언어Flux / InfluxQLPromQLSQL
수집 방식PushPullPush
장기 보관자체 지원외부 저장소 필요자체 지원
학습 곡선중간중간낮음 (SQL 재사용)

시계열 데이터는 발생 빈도와 양이 많고 시간 범위 조회가 핵심이라, RDB 대신 TSDB를 사용하면 저장 공간과 쿼리 성능 모두에서 큰 이점을 얻을 수 있다. 모니터링 스택을 구성할 때 Prometheus+Grafana 조합을 기본으로 익혀두면 실무에 바로 활용할 수 있다.