Zeitreihen speichern
1) Warum eine separate Architektur für Zeitreihen
Zeitreihen (Zeitreihen) sind Sequenzen von Paaren (Zeitstempel, Wert) mit Tags (Etiketten), die gekennzeichnet sind durch:- Hohe Aufnahmegeschwindigkeit (ingest) und Periodizität.
- Lesungen nach Zeitbereichen (Scan + Aggregate/Fensterfunktionen).
- Explosive Kardinalität aufgrund von Tag-Kombinationen.
- Notwendigkeit von Retenschna (Begrenzung der Haltbarkeit) und Downsampling (Zeitkompression).
- Daher ein spezielles Speichermodell, Kompressionsformate und Anforderungsprotokolle.
2) Datenmodell und Kontraktmetriken
2. 1 Benennung und Tags
metric_name: Verb/Substantiv im Singular ('http _ requests _ total', 'cpu _ usage _ seconds _ total').
labels: Schlüsselattribute ('job', 'instance', 'dc', 'pod', 'status', 'method').
Invarianten: Ändern Sie nicht die Semantik des Namens, fügen Sie Versionen ('metric _ v2') bei inkompatiblen Änderungen hinzu.
2. 2 Arten von Reihen
Gauge (Momentaufnahme), Counter (steigende Summe), Histogram/Summary (Verteilungen/Quantile), Event/Span (Treis-Punkte).
Für Finanzen/Dichten - Einheiten und Aggregierbarkeit erfassen (summiert/gemittelt).
2. 3 Rethenchen- und Rollap-Politik
Heißes Detail (Sekunden/1-10 min) → warme Einheiten (5m/1h) → kalte Einheiten (1d/1w).
Für counter - speichern rate/deriv Aggregate.
3) Aufnahmeweg: Empfang, Pufferung, kompakt
3. 1 Ingest-Pipeline
Scrape (Pull, Prometheus) oder Push (OTLP/StatsD/Graphite), oft über Gateway/Agent.
Pufferung in WAL (write-ahead log), dann Kompression in Segmente/Blöcke (LSM-ähnliche Architektur).
Batching und Timesortierung erhöhen die Komprimierung und Geschwindigkeit.
3. 2 Verarbeitung von Out-of-Order und Takes
Toleranzfenster (Latenzfenster, z.B. 5-15 min) + Richtlinie: 'drop | upsert | keep-last'.
Deduplizierung nach „(series_id, timestamp)“ mit Versionsnummer oder „letzter Eintrag gewinnt“.
3. 3 Kompression
Delta-of-Delta für Zeitstempel, Gorilla/XOR für Float, RLE und Varint für ganze, Dictionary für Tags.
Die optimale Blockgröße („Chank“) 1-8K Punkte ist ein Kompromiss zwischen IOPS und CPU.
4) Speicherschemata: TSDB vs SQL/Säulenhalter
4. 1 Spezialisierte TSDBs
Prometheus (lokal, kurze Retention, PromQL, remote_write).
VictoriaMetrics/M3/InfluxDB - horizontale Skalierung, lange Retention, Remote Read.
Die Blockformate sind optimiert für range scan + tendering Aggregationen.
4. 2 Relationale/Säulenmotoren
TimescaleDB (PostgreSQL): Hypertabellen, Chunks nach Zeit/Raum, kontinuierliche Aggregate.
ClickHouse: MergeTree/TTL/materialisierte Ansichten, ausgezeichnete Kompression und Aggregation nach Zeit.
Die Auswahl erfolgt nach Abfrageökosystem (SQL vs PromQL), Join/BI-Anforderungen und den operativen Fähigkeiten des Teams.
5) Schema und Beispiele
5. 1 TimescaleDB: hypertable + continuous aggregate
sql
CREATE TABLE metrics_cpu(
ts timestamptz NOT NULL,
host text NOT NULL,
dc text NOT NULL,
usage double precision NOT NULL,
PRIMARY KEY (ts, host, dc)
);
SELECT create_hypertable('metrics_cpu', by_range('ts'), chunk_time_interval => interval '1 day');
-- Continuous unit (5 minutes)
CREATE MATERIALIZED VIEW cpu_5m
WITH (timescaledb. continuous) AS
SELECT time_bucket('5 minutes', ts) AS ts5m, host, dc, avg(usage) AS avg_usage
FROM metrics_cpu GROUP BY 1,2,3;
-- Politicians
SELECT add_retention_policy('metrics_cpu', INTERVAL '14 days');
SELECT add_retention_policy('cpu_5m', INTERVAL '180 days');
5. 2 ClickHouse: aggregierende Speicherung
sql
CREATE TABLE metrics_cpu (
ts DateTime,
host LowCardinality(String),
dc LowCardinality(String),
usage Float32
) ENGINE = MergeTree()
PARTITION BY toYYYYMM(ts)
ORDER BY (host, dc, ts)
TTL ts + INTERVAL 14 DAY
SETTINGS index_granularity = 8192;
-- Rollup in hourly detail
CREATE MATERIALIZED VIEW cpu_1h
ENGINE = SummingMergeTree()
PARTITION BY toYYYYMM(ts)
ORDER BY (host, dc, ts)
POPULATE AS
SELECT toStartOfHour(ts) AS ts, host, dc, avg(usage) AS usage
FROM metrics_cpu GROUP BY ts, host, dc;
5. 3 Prometheus/VictoriaMetrics: remote_write
yaml global:
scrape_interval: 15s remote_write:
- url: http://vminsert:8480/insert/0/prometheus/api/v1/write
6) Kardinalität: wie man den Speicher nicht „sprengt“
6. 1 Regeln
Beschränken Sie label cardinality (die Anzahl der eindeutigen Werte). Nicht einschließen 'user _ id', 'request _ id', 'trace _ id'.
Normalisieren Sie „mehrwertige“ Tags (Kategorien → Codes).
Verwenden Sie LowCardinality-Typen (in CH), Wörterbücher/Labelbäume (in TSDB).
6. 2 Kontrolle und Warnungen
Metriken: 'series _ count', 'label _ values {label}', top-N 'teure' Reihen.
Schreibfehlerrichtlinien, wenn das Kardinalitätslimit per tenant/job überschritten wird.
6. 3 Geschichten/Histogramme
Für High-Cardinality ist es besser, Aggregate (Histogrammschnecken) und Pre-Rollup zu speichern; quantisiert, um online auf Aggregaten zu berechnen.
7) Retention, Downsampling und Tiered-Storage
7. 1 Politik
Heiß: 3-30 Tage Sekunde/Minute Detail.
Warm: 90-365 Tage 5m/1h Aggregate.
Cold: Jahre der Tagesaggregate, Archiv im Objektspeicher (S3/Glacier) mit Parket.
7. 2 Techniken
Kontinuierliche Aggregate (Timescale), materialisierte Darstellungen (CH), retention + rollup Aufgaben (Victoria/M3/Influx).
Tiered Storage: „heiße Blöcke“ lokal, „kalt“ im Objekt mit lokalem Cache.
8) Anfragen und Sprachen
8. 1 PromQL (Beispiel)
promql rate(http_requests_total{job="api",status=~"5.."}[5m])
Wir suchen nach einer Fehlerrate von 5xx über die API.
8. 2 SQL-Aggregate nach Fenster
sql
SELECT time_bucket('1h', ts) AS hour,
dc, avg(usage) AS avg, max(usage) AS pmax
FROM metrics_cpu
WHERE ts >= now() - interval '24 hours'
GROUP BY 1,2 ORDER BY 1;
8. 3 Anomalien (Skizze)
Z-Score/ESD nach Fensterstatistik, STL-Zerlegung der Saisonalität; Speichern Sie die Ergebnisse in einer separaten Zeile' anomaly = 1/0'.
9) Integrationen und Protokolle
OTLP (OpenTelemetry): Metriken/Traces/Logs, Exporteure auf Agenten (Otel-Collector) → TSDB/Clickhouse/Object.
StatsD/Graphite: einfache Zähler/Timer; Proxy auf der Kante, dann - Konvertierung in ein einziges Format.
Kafka/NATS: Puffer für ingest Bursts, Replayer für Backfill; Consumer schreiben Schlachten.
text kafka(topic=metrics) -> stream processor (normalize/tags) -> CH INSERT INTO metrics_cpu FORMAT RowBinary
10) Verfügbarkeit, HA und Föderation
Replica/HA-Paare TSDB oder Prometheus Federation (Ebene Region → Global).
Remote Read/Write für Langzeitspeicherung und zentrale Dashboards.
Shard-by-label/time: gleichmäßige Verteilung von ingest, locality durch 'dc/tenant'.
11) Beobachtbarkeit der Lagerung selbst
11. 1 Metriken
Ingest: `samples/sec`, `append_latency`, `wal_fsync_ms`.
Хранение: `blocks_count`, `compaction_queue_len`, `chunk_compression_ratio`.
Запросы: `query_qps`, `scan_bytes`, `p95/p99_latency`, `alloc_bytes`.
Kardinalität: 'series _ count', Top-Labels.
11. 2 SLO
„p99 Latenz für den Bereich 1h ≤ 200 ms bei QPS≤500“.
«Ingest-drop ≤ 0. 01% bei Burst bis X Proben/Sek."
«Compaction backlog < 10 min».
11. 3 Alerts
Wachstum 'series _ count'> U %/Stunde.
Kompositionswarteschlange/flush> Schwelle.
Доля out-of-order > N%, dedup/late-drops.
12) Sicherheit und Multi-Tenant
Isolierung durch 'tenant' (Label in Schlüsseln, separate Tabellen/Basen, Quoten).
Labelsanierung (PII-Verbot), Größen-/Wertkontrolle.
Verschlüsselung „in Ruhe“ und im Verkehr, Prüfung des Zugangs zu „sensiblen“ Metriken.
13) Betriebspraktiken
Aufwärmen und Kaltstart: Pin der „heißen“ Blöcke im Cache, Prefetch der letzten N Stunden.
Backfill: Einzelne Pipelines mit niedriger Priorität, nicht mit Online mischen.
Schema-Versionierung: Migrationen mit paralleler Schreibweise (Dual-Write) und nachfolgendem Sweep.
Speicherbudget: Kontrolle' cost _ per _ TB _ month'+ Prognose des Kardinalitätswachstums.
14) Anti-Muster
Tags mit hoher Kardinalität (user_id, uuid) → eine Explosion von Reihen.
„Ewige“ Reihen ohne Retention → unkontrolliertes Wachstum.
Aufzeichnung ohne Batching/Sortierung → schlechte Kompression und IOPS-Sturm.
Mischen Sie OLTP und lange Scans auf einem einzigen Laufwerk-Pool.
Keine Out-of-Order-Richtlinie → Duplikate und Aufblasen.
Histogramme mit Hunderten von Baketten → die Kosten × 10 ohne Nutzen.
15) Checkliste Umsetzung
- Definieren Sie die Metriken, ihre Typen und Einheiten; Fixieren Sie den Vertrag der Namen/Labels.
- Wählen Sie die Engine (TSDB vs SQL/Collar) und die Abfragesprache (PromQL/SQL).
- Entwerfen Sie retention/rollup (hot/warm/cold) und ILM-taski.
- Konfigurieren Sie ingest: WAL/Batchi/Sortierung, Out-of-Order-Fenster.
- Kompression einschalten (Delta-of-Delta/XOR/RLE), optimale Chunks.
- Kontrolle der Kardinalität: Quoten, Warnungen, Opt-out-Richtlinien.
- Konfigurieren Sie NA/federation und remote-write/read.
- SLO Dashboards und Speichermetriken (ingest/query/storage).
- Sicherheitsrichtlinien/Tenant-Isolation und keine PII in Labels.
- Regulärer „Game Day“: Backfill, Knotenverlust, Ingest-Burst.
16) FAQ
Q: Was soll ich wählen, um die Infrastruktur zu überwachen: Prometheus oder ClickHouse/Timescale?
A: Für die native Überwachung und PromQL - Prometheus + Langzeitlagerung (Victoria/M3). Für BI/Warehouse-Szenarien und SQL - Timescale/ClickHouse.
Q: Wie man Quantile ohne schwere Zusammenfassung speichert?
A: Verwenden Sie histogram mit ordentlichen bakets und berechnen Sie quantils, wenn Sie angefordert werden; oder t-digest/CKMS in Aggregaten.
F: Wie gehe ich mit Out-of-Order um?
A: Geben Sie das Toleranzfenster (5-15 min) und die deterministische Dedup-Richtlinie ein; für Telemetrie von mobile/edge - das Fenster ist breiter.
F: Wann wird Rollup benötigt?
A: Immer bei Retention> 30-90 Tage: Die Aggregate reduzieren die Größe × 10-100 und beschleunigen die Analyse.
F: Können Protokolle und Metriken gemischt werden?
A: Separat speichern (Formate/Anfragen sind unterschiedlich). Verwenden Sie für die Korrelation Exemplar/TraceID und Dashboards, aber addieren Sie nicht alles in eine Tabelle.
17) Ergebnisse
Ein effektiver Zeitreihenspeicher ist ein Vertrag von Metriken + Tag-Disziplin, kompetenter Ingest (WAL/Kompression), Kompression und Retenschna/Rollap-Richtlinien. Fügen Sie Kardinalitätskontrolle, NA/Föderation und die Beobachtbarkeit des Stors selbst hinzu - und Sie erhalten vorhersehbare p95, angemessene Kosten für Monate bis Jahre und Widerstandsfähigkeit gegen Spitzen.