Stocarea seriilor de timp
1) De ce o arhitectură separată pentru serii de timp
Seriile de timp sunt secvențe de perechi (timestamp, valoare) cu etichete (etichete), care se caracterizează prin:- Viteză mare de înregistrare (ingerare) și frecvență.
- Citește după intervale de timp (scanare + agregate/funcții de fereastră).
- Cardinalitate explozivă datorită combinaţiilor de etichete.
- Nevoia de retenție (restricții de valabilitate) și sub-eșantionare (compresie de timp).
- Prin urmare - un model special de stocare, formate de compresie și protocoale de cerere.
2) Modelul de date și măsurătorile contractuale
2. 1 Denumire și etichete
metric_name: singular verb/substantiv ('http _ requests _ total', 'cpu _ usage _ seconds _ total').
etichete: atribute keys ('job', 'instance', 'dc', 'pod',' status ',' method ').
Invarianți: nu schimbați semantica numelui, adăugați versiuni ('metric _ v2') cu modificări incompatibile.
2. 2 Tipuri de rânduri
Ecartament, Contor, Histogramă/Rezumat, Eveniment/Span.
Pentru financiare/densități - Fixați unitățile și agregabilitatea (însumate/medii).
2. 3 Politica de retenție și Rollup
Detalii fierbinți (secunde/1-10 min) → unități calde (5m/1h) → reci (1d/1w).
Pentru counter - store rate/deriv agregate.
3) Cale de înregistrare: recepție, tamponare, compact
3. 1 Ingera-conducte
Răzuiți (trageți, Prometheus) sau împingeți (OTLP/StatsD/Graphite), adesea prin gateway/agent.
Tamponarea în WAL (jurnal write-ahead), apoi comprimarea în segmente/blocuri (arhitectură LSM-like).
Batching și timp de sortare crește compresia și viteza.
3. 2 Manipularea out-of-order și ia
Fereastra de toleranță (fereastra de întârziere, de exemplu 5-15 min) + politică: 'drop | upsert | keep-last'.
Deduplicarea prin „(series_id, timestamp)” cu versioning sau „ultimul record câștigă”.
3. 3 Compresie
Delta-of-delta pentru marcaje temporale, Gorilla/XOR pentru float, RLE și varint pentru numere întregi, dicționar pentru etichete.
Dimensiunea optimă a blocului („bucată”) a 1-8K puncte este un compromis între IOPS și CPU.
4) Scheme de stocare: TSDB vs SQL/coloane
4. 1 TSDB dedicat
Prometheus (local, retenție scurtă, PromQL, remote_write).
VictoriaMetrics/M3/InfluxDB - scalare orizontală, retenție lungă, citire la distanță.
Formatele de bloc sunt optimizate pentru scanarea intervalului + agregări de licitație.
4. 2 Motoare relaționale/coloane
TimescaleDB (PostgreSQL): hypertables, bucăți de timp/spațiu, agregate continue.
ClickHouse: MergeTree/TTL/vizualizări materializate, compresie excelentă și agregarea timpului.
Selecție - prin interogare ecosistem (SQL vs PromQL), se alăture/cerințele BI și abilitățile operaționale ale echipei.
5) Schema și exemple
5. 1 TimescaleDB: hipertensibil + agregat continuu
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: Agregarea de stocare
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) Cardinalitate: cum să nu „arunce în aer” depozitarea
6. 1 Reguli
Limitați cardinalitatea etichetei (numărul de valori unice). Nu includeți 'user _ id',' request _ id', 'trace _ id'.
Normalizați etichetele „multi-valued” (categorii → coduri).
Utilizați tipuri LowCardinality (în CH), dicționare/arbori de etichetă (în TSDB).
6. 2 Controale și alerte
Metrics: 'series _ count',' label _ values {label} ', top-N „scump” rânduri.
Scrieți politici de eșec atunci când limita de cardinalitate este depășită pe chiriaș/loc de muncă.
6. 3 Istorii/Histograme
Pentru cardinalitate ridicată, este mai bine să stocați agregate (găleți histogramă) și pre-rollup; cantități pentru a calcula online pe agregate.
7) Retenție, sub-eșantionare și stocare pe niveluri
7. 1 Politici
Fierbinte: 3-30 de zile de detaliu al doilea/minut.
Cald: 90-365 zile de agregate 5m/1h.
Rece: ani de agregate de zi, arhiva în depozitarea obiectelor (S3/Glacier) cu parchet.
7. 2 Tehnicieni
Agregate continue (Timescale), vizualizări materializate (CH), sarcini de retenție + rollup (Victoria/M3/Influence).
Depozitare pe niveluri: „blocuri fierbinți” local, „rece” în obiect cu memorie cache locală.
8) Interogări și limbi
8. 1 PromQL (exemplu)
promql rate(http_requests_total{job="api",status=~"5.."}[5m])
Căutați o rată de eroare API 5xx.
8. 2 SQL agregate de ferestre
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 Anomalii (schiță)
Z-score/ESD după statisticile ferestrelor, descompunerea STL a sezonalității; stocați rezultatele într-un rând separat 'anomalie = 1/0'.
9) Integrări și protocoale
OTLP (OpenTelemetry): metrici/trasee/busteni, exportatori pe agenți (otel-colector) → TSDB/clickhouse/obiect.
StatsD/Graphite: contoare simple/cronometre; proxy la margine, apoi conversia într-un singur format.
Kafka/NATS: tampon pentru explozii ingerate, reluare pentru rambursare; consumatorii scriu batchami.
text kafka(topic=metrics) -> stream processor (normalize/tags) -> CH INSERT INTO metrics_cpu FORMAT RowBinary
10) Accesibilitate, HA și Federație
Replica/TSDB HA perechi sau Prometheus federație (regiune → nivel global).
Citire/scriere la distanță pentru stocare pe termen lung și tablouri de bord centralizate.
Cioburi cu etichetă/timp: distribuție uniformă a ingerării, localitate cu 'dc/chiriaș'.
11) Observabilitatea depozitării în sine
11. 1 Măsurători
Ingera: 'mostre/sec', 'append _ latency', 'wal _ fsync _ ms'.
Хранение: 'blocks _ count',' compaction _ queue _ len ',' chunk _ compression _ ratio '.
Запросы: 'query _ qps', 'scan _ bytes', 'p95/p99 _ latency', 'alloce _ bytes'.
Cardinalitate: 'series _ count', top-labels.
11. 2 SLO
„p99 latență pentru gama 1h ≤ 200ms la QPS≤500”.
"Ingera-drop ≤ 0. 01% la explozie înainte de probele X/sec"
Accesat în 3 martie 2013. ^ „Compaction restlog <10 min”.
11. 3 Alerte
Growth 'series _ count'> Y %/oră.
Coadă de comprimare/culoare> prag.
Доля out-of-order> N%, dedup/late-drops.
12) Siguranță și multi-chirie
Izolarea prin „chiriaș” (etichetă în chei, tabele individuale/baze de date, cote).
Igienizarea etichetelor (interzicerea PII), controlul dimensiunii/valorii.
Criptarea „în repaus” și pe transport, auditarea accesului la valori „sensibile”.
13) Practici de operare
Încălzire și pornire la rece: pini de blocuri „fierbinți” în memoria cache, prefetch din ultimele ore N.
Backfill: conducte individuale cu prioritate redusă, nu se amestecă cu on-line.
Versionarea schemei: migrații cu scriere paralelă (dual-write) și comutare ulterioară.
Bugetul de stocare: controlul 'cost _ per _ TB _ month' + prognoza creșterii cardinalității.
14) Anti-modele
Etichete cu cardinalitate ridicată (user_id, uuid) → explozia rândurilor.
Rânduri „eterne” fără reținere → creștere necontrolată.
Înregistrare non-butching/sortare → compresie slabă și furtună IOPS.
Se amestecă OLTP și scanări lungi pe același bazin de discuri.
Lipsa politicii out-of-order → duplicate și balonări.
Histogramele cu sute de găleți → costa × 10 fără beneficii.
15) Lista de verificare a implementării
- Definiți valorile, tipurile și unitățile acestora; fixați contractul de denumire/etichetă.
- Selectați motorul (TSDB vs SQL/Coloana) și limba de interogare (PromQL/SQL).
- Proiectați o retenție/rollup (cald/cald/rece) și ILM.
- Configurați ingerarea: WAL/loturi/sortare, ferestre out-of-order.
- Porniți compresia (delta-of-delta/XOR/RLE), bucăți optime.
- Controlul cardinalității: cote, alerte, politici de renunțare.
- Configurați HA/federație și de la distanță-scrie/citi.
- Tablouri de bord SLO și valori de stocare (ingerare/interogare/stocare).
- Politici de securitate/izolare a chiriașilor și lipsa PII în etichete.
- Regulat „zi joc”: rambursare, pierderea nodului, ingera val.
16) ÎNTREBĂRI FRECVENTE
Î: Ce să alegeți pentru monitorizarea infrastructurii: Prometheus sau ClickHouse/Timescale?
R: Pentru monitorizarea nativă și PromQL - Prometheus + stocare pe termen lung (Victoria/M3). Pentru scenarii BI/depozit și SQL - Timescale/ClickHouse.
Î: Cum se stochează cantitățile fără rezumate grele?
R: Utilizați histograma cu găleți îngrijite și calculați cantitățile atunci când este solicitat; sau t-digest/CKMS în agregate.
Î: Cum să se ocupe de out-of-order?
R: Introduceți fereastra de toleranță (5-15 min) și politica de deducere deterministă; pentru telemetrie de pe mobil/margine - fereastra este mai largă.
Î: Când este nevoie de un rollup?
R: Întotdeauna> 30-90 de zile: agregatele reduc dimensiunea × 10-100 și accelerează analiza.
Î: Este posibilă amestecarea jurnalelor și a măsurătorilor?
R: Stocați separat (formatele/interogările sunt diferite). Pentru corelare, utilizați Exemplar/TraceID și tablouri de bord, dar nu adăugați totul la un singur tabel.
17) Totaluri
Stocarea efectivă a seriei de timp este măsurarea contractului + disciplina etichetelor, ingerarea competentă (WAL/compactare), compresia și politicile de retenție/rollup. Adăugați controlul cardinalității, NA/federația și observabilitatea magazinului în sine - și veți obține p95 previzibil, cost rezonabil pentru luni până la ani și rezistență la supratensiune.