Armazenamento de filas de tempo
1) Por que uma arquitetura separada para filas de tempo
As filas de tempo (time series) são sequências de pares (timestamp, value) com marcas (labels) que são caracterizadas como:- Alta taxa de gravação (ingest) e frequência.
- Leituras de intervalo de tempo (scan + unidades/janelas).
- Uma radicalidade explosiva por causa das combinações de marcas.
- A necessidade de retencagem (limitação de tempo de armazenamento) e downsampling (compressão de tempo).
- A partir daí, um modelo especial de armazenamento, formatos de compressão e protocolos de solicitação.
2) Modelo de dados e contrato de métricas
2. 1 Denominação e marcas de formatação
metric _ name: verbo/substantivo no único número ('http _ requests _ total', 'cpu _ usage _ secunds _ total').
labels: atributos de chave ('job', 'instance', 'dc', 'pod', 'status', 'method').
Invariantes: não alterar a semântica do nome, adicionar versões ('metric _ v2') em caso de alterações incompatíveis.
2. 2 Tipos de fila
Gauge (foto), Counter (resultado crescente), Historogram/Summary (distribuição/Quantili), Event/Span (ponto de trade).
Para finanças/densidades: fixe as unidades e a agregabilidade (somada/média).
2. 3 Política de Retensismo e Rollaps
Detalhe quente (segundos/1-10 min) → unidades quentes (5m/1h) → frias (1d/1w).
Para counter - armazenar rate/deiv unidades.
3) Caminho de gravação: recepção, tampão, CD
3. 1 Ingest-Pipeline
Scrape (pull, Prometheus) ou push (OTLP/StatsD/Graphite), muitas vezes via gateway/agente.
Tampão em WAL (write-ahead jobs), depois compactuação em segmentos/blocos (LSM-Semelhante Arquitetura).
Batching e ordenação por tempo aumentam a compressão e a velocidade.
3. 2 Processamento de out-of-order e dublagens
Janela de tolerância (lateness window, por exemplo, 5-15 min) + política: 'drop | upsert | keep-last'.
Deduplicação por '(série _ id, timestamp)' com versão ou 'última entrada vencendo'.
3. 3 Compressão
Delta-of-delta para marcas de tempo, Gorilla/XOR para float, RLE e varint para inteiras, dictionary para marcas de formatação.
Tamanho ideal de bloco («chanca») 1-8K de pontos - comprometimento entre IOPS e CPU.
4) Esquemas de armazenamento: TSDB vs SQL/colinvertebrados
4. 1 TSDB especializado
Prometheus (retensório local, curto, PromQL, remote _ write).
VictoriaMetrics/M3/InfluxDB - zoom horizontal, retencagem longa, remote read.
Os formatos de blocos são otimizados sob range scan + agregações de ofertas.
4. 2 Motores relacionais/invertebrados
TimescaleDB (PostgreSQL): hipertablinos, chanchas de tempo/espaço, contínuos agregates.
ClickHouse: MergeTree/TTL/Visualização Materializada, ótima compressão e agregação de tempo.
Escolha por ecossistema de consulta (SQL vs PromQL), requisitos de join/BI e habilidades operacionais da equipe.
5) Esquema e exemplos
5. 1 TimescaleDB: hipertablitz + 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: armazenamento agregado
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) Cardinalidade: como não «explodir» o cofre
6. 1 Regras
Limite o label cardinality (número de valores exclusivos). Não inclua 'user _ id', 'request _ id', 'trace _ id'.
Normalize as marcas de formatação (categorias → códigos).
Use LowCardinality tipos (CH), dicionários/árvores de marca (TSDB).
6. 2 Controle e alertas
As métricas são: 'series _ count', 'label _ values\label a.', top-N de filas' caras '.
Políticas de rejeição quando o limite de radicalidade for tenant/job for ultrapassado.
6. 3 Histórias/histogramas
Para high-cardinality, é melhor armazenar unidades (historograma buckets) e pré-rollup; Quantili calcular online nas unidades.
7) Retenshn, downsampling e tiered-armazenamento
7. 1 Políticas
Hot: 3 a 30 dias de detalhe de segundo/minuto.
Warm: 90-365 dias 5m/1h unidades.
Cold: anos de unidades diurnas, arquivo em armazenamento de objetos (S3/Glacier) com Parquet.
7. 2 Técnicos
Contínuo agregates (Timescale), visualizações materializadas (CH), retenção + rollup tasks (Victoria/M3/Influx).
Armazenamento Tiered: «blocos quentes» localmente, «frios» no armazenamento local.
8) Consultas e idiomas
8. 1 PromQL (exemplo)
promql rate(http_requests_total{job="api",status=~"5.."}[5m])
Procurando o ritmo de erro de API 5xx.
8. 2 unidades SQL por janelas
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 Anomalias (esboço)
Z-score/ESD em estatísticas de janela, descomposição STL de sazonalidade; armazenar os resultados em uma fila separada de 'anataly = 1/0'.
9) Integração e protocolos
OTLP (OpenTelemetry): métricas/trailers/logs, exportadores em agentes (otel-captor) → TSDB/clickouse/objeto.
StatsD/Graphite: contadores simples/temporizadores; proxy em edge, e a conversão em formato único.
Kafka/NATS: tampão para picos de ingest, replayer para backphill; Os conceituadores escrevem batches.
text kafka(topic=metrics) -> stream processor (normalize/tags) -> CH INSERT INTO metrics_cpu FORMAT RowBinary
10) Disponibilidade, HA e federação
Replica/HA casais TSDB ou Prometheus (Nível Regional → Global).
Remote read/write para armazenamento de longo prazo e dashboards centralizados.
Shard-by-label/time: distribuição uniforme de ingest, locality por 'dc/tenant'.
11) Observabilidade do próprio armazenamento
11. 1 Métricas
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`.
«série _ count», top-labels.
11. 2 SLO
«p99 latency para 1h ≤ 200 ms de QPS≤500».
«Ingest-drop ≤ 0. 01% para burst até X sample/sec".
«Compaction backlog < 10 min».
11. 3 Alertas
Altura de 'series _ count'> Com %/hora.
Fila de compacção/flush> limiar.
Доля out-of-order > N%, dedup/late-drops.
12) Segurança e multi-tenência
Isolamento por 'tenant' (editora em chaves, tabelas/bases individuais, quotas).
Saneamento de marcas (proibição do PII), controle de tamanho/valor.
Criptografia em paz e transporte, auditoria do acesso a métricas sensíveis.
13) Práticas operacionais
Aquecimento e início frio: pin blocos «quentes» no cachê, prefetch das últimas horas N.
Backfill: Pipas individuais de baixa prioridade, não misturadas com online.
Versionagem de padrão: migração com registro paralelo (dual-write) e suavidade subsequente.
Orçamento de armazenamento: Controle de 'questão _ para _ TB _ month' + forecast do crescimento da radicalidade.
14) Anti-pattern
Marcas de formatação (user _ id, uuid) → explosão de filas.
Filas «eternas» sem retino → crescimento descontrolado.
Gravação sem batching/triagem → má compressão e tempestade IOPS.
Mistura OLTP e telas longas em uma única bala de discos.
Nenhuma política out-of-order → duplicação e inchaço.
Histogramas com centenas de baquetes → custo x 10 sem utilidade.
15) Folha de cheque de implementação
- Defina as métricas, seus tipos e unidades; estabeleça o contrato de nomes/editoras.
- Selecione o motor (TSDB vs SQL/colinvertebrado) e o idioma de consulta (PromQL/SQL).
- Projete o retensno/roll (hot/warm/cold) e as tascas ILM.
- Configure o ingest: WAL/batchi/triagem, janelas out-of-order.
- Ative a compressão (delta-of-delta/XOR/RLE), os pontos perfeitos.
- Controle a radicalidade: quotas, alertas, políticas de rejeição.
- Configure EM/federação e remote-write/read.
- Dashboard SLO e métricas de armazenamento (ingest/query/armazenamento).
- Políticas de segurança/isolamento tenante e ausência de PII nas editoras.
- Regularmente «game day»: backphill, perda de nó, pica ingest.
16) FAQ
Q: O que escolher para monitorar a infraestrutura: Prometheus ou ClickHouse/Timescale?
A: Para monitoramento nativo e PromQL - Prometheus + armazenamento longo (Victoria/M3). Para cenários BI/armazenamento e SQL - Timescale/ClickHouse.
Q: Como armazenar quantili sem summary pesado?
A: Use um historograma com baquetas cuidadosas e calcule o quântli quando for solicitado; ou t-digest/CKMS em unidades.
Q: Como fazer com o out-of-order?
A: Digite uma janela de tolerância (5-15 min) e uma política de dedup definida; para telemetria móvel/edge - janela mais larga.
Quando precisas de rollup?
A: Sempre a retencer> 30-90 dias: as unidades reduzem o tamanho do x 10-100 e aceleram a análise.
Pode misturar logs e métricas?
A: Guarde separadamente (formatos/solicitações diferentes). Use Exemplar/TraceID e frascos para correlacionar, mas não coloque tudo na mesma tabela.
17) Resultados
O armazenamento efetivo de linhas de tempo é um contrato de métricas + disciplina de marcas de formatação, englest (WAL/compactação), compressão e políticas de retensão/roll. Adicione o controle de cardealidade, a P/federação e a observabilidade do próprio estor - e você terá p95 previsíveis, um custo razoável para meses-anos e resistência a picos.