Estratégias de hot e cold data: tiering de armazenamento para dados históricos
1. Conceitos Fundamentais de Tiering de Armazenamento
O tiering de armazenamento é uma estratégia que classifica dados com base em sua frequência de acesso, latência necessária e criticidade operacional. Os três tiers principais são:
- Hot data: Dados acessados frequentemente (milissegundos de latência), alta criticidade. Exemplo: transações do dia corrente.
- Warm data: Dados acessados ocasionalmente (segundos de latência), criticidade moderada. Exemplo: transações do último trimestre.
- Cold data: Dados raramente acessados (minutos a horas de latência), baixa criticidade. Exemplo: transações com mais de 5 anos.
A separação entre tiers reduz custos de armazenamento em até 80% e melhora a performance operacional, pois índices e buffers ficam dedicados aos dados quentes.
Exemplo prático: Um sistema financeiro mantém dados de transações:
- Hot: mês corrente em SSD (acesso <1ms)
- Warm: últimos 12 meses em HDD (acesso <10ms)
- Cold: 5+ anos em object storage (acesso <30s)
-- Estrutura de tiering baseada em data
CREATE TABLE transacoes (
id SERIAL PRIMARY KEY,
valor DECIMAL(15,2),
data_transacao TIMESTAMP,
tipo VARCHAR(20)
) PARTITION BY RANGE (data_transacao);
-- Partição hot (mês corrente)
CREATE TABLE transacoes_2025_03
PARTITION OF transacoes
FOR VALUES FROM ('2025-03-01') TO ('2025-04-01')
TABLESPACE ssd_fast;
-- Partição warm (últimos 12 meses)
CREATE TABLE transacoes_2024_03
PARTITION OF transacoes
FOR VALUES FROM ('2024-03-01') TO ('2024-04-01')
TABLESPACE hdd_standard;
2. Arquiteturas Comuns de Tiering em Bancos Relacionais
O particionamento por data (range partitioning) é a base para movimentação entre tiers. No PostgreSQL, o uso de herança de tabelas permite isolar dados históricos sem impacto no schema principal.
Migração manual vs. automatizada:
- Manual: Scripts SQL executados em janelas de manutenção
- Automatizada: Jobs com pg_cron ou triggers que movem partições ao final de cada mês
-- Exemplo de herança para dados cold
CREATE TABLE transacoes_cold (LIKE transacoes INCLUDING ALL);
ALTER TABLE transacoes_cold ADD CONSTRAINT ano_check
CHECK (data_transacao < '2024-01-01');
-- Migração automatizada via pg_cron
SELECT cron.schedule('migrate-cold', '0 3 1 * *', $$
INSERT INTO transacoes_cold
SELECT * FROM transacoes
WHERE data_transacao < NOW() - INTERVAL '3 years';
DELETE FROM transacoes
WHERE data_transacao < NOW() - INTERVAL '3 years';
$$);
3. Estratégias de Movimentação de Dados (Hot → Cold)
ETL reverso: Exportar dados cold para arquivos parquet compressados e removê-los do banco principal. Isso libera espaço e reduz custos de backup.
Foreign Data Wrappers (FDW): Acessar dados cold sem movê-los fisicamente, mantendo a capacidade de consulta.
Políticas de retenção: Definir janelas temporais para cada tier usando tabelas temporárias.
-- ETL reverso para parquet (via psql + Python)
-- 1. Exportar dados cold
COPY (
SELECT * FROM transacoes
WHERE data_transacao < '2023-01-01'
) TO '/tmp/cold_transacoes.csv' WITH CSV;
-- 2. Converter para parquet compressado (comando externo)
-- duckdb -c "COPY (SELECT * FROM read_csv('/tmp/cold_transacoes.csv'))
-- TO '/cold_storage/transacoes_2022.parquet' (FORMAT PARQUET, COMPRESSION ZSTD);"
-- 3. Remover do banco principal
DELETE FROM transacoes WHERE data_transacao < '2023-01-01';
-- FDW para acessar dados cold
CREATE FOREIGN DATA WRAPPER parquet_fdw HANDLER parquet_fdw_handler;
CREATE SERVER cold_storage FOREIGN DATA WRAPPER parquet_fdw
OPTIONS (location '/cold_storage/');
CREATE FOREIGN TABLE transacoes_cold_fdw (
id INTEGER,
valor DECIMAL(15,2),
data_transacao TIMESTAMP,
tipo VARCHAR(20)
) SERVER cold_storage OPTIONS (filename 'transacoes_2022.parquet');
4. Armazenamento Frio: Opções e Trade-offs
| Opção | Custo/GB/mês | Latência | Compressão | Recuperação |
|---|---|---|---|---|
| S3 Standard | $0.023 | 5-10ms | Automática | Imediata |
| S3 Glacier | $0.004 | 1-5min | Automática | 1-12h |
| MinIO (on-prem) | $0.010 | 10-20ms | Configurável | Imediata |
| Fita magnética | $0.001 | 1-24h | Manual | Dias |
Bancos analíticos dedicados: ClickHouse e DuckDB oferecem compressão colunar (10-20x) e consultas otimizadas para dados frios.
-- Configuração de cold storage no ClickHouse
CREATE TABLE transacoes_cold_clickhouse (
id Int32,
valor Decimal(15,2),
data_transacao DateTime,
tipo String
) ENGINE = MergeTree()
PARTITION BY toYYYYMM(data_transacao)
ORDER BY (data_transacao, id)
SETTINGS storage_policy = 'cold_policy';
-- Política de tiering no MinIO/S3
-- minio-client cp /cold_storage/transacoes_2022.parquet s3://cold-bucket/
-- aws s3api put-object-tagging --bucket cold-bucket --key transacoes_2022.parquet \
-- --tagging '{"TagSet": [{"Key": "tier", "Value": "cold"}]}'
5. Indexação e Performance em Dados Frios
Índices em dados cold são desnecessários e consomem espaço. Use índices parciais para dados quentes e BRIN para dados históricos.
BRIN (Block Range Index): Ideal para dados ordenados temporalmente, ocupa 1% do espaço de um B-tree.
-- Índice parcial apenas para dados quentes
CREATE INDEX idx_transacoes_hot ON transacoes (data_transacao)
WHERE data_transacao >= NOW() - INTERVAL '30 days';
-- Índice BRIN para dados históricos (cold)
CREATE INDEX idx_transacoes_cold_brin ON transacoes_cold
USING BRIN (data_transacao)
WITH (pages_per_range = 32);
-- Compressão de páginas em dados frios
-- pg_repack para reorganizar sem lock
-- pg_repack -t transacoes_cold -o 'fillfactor=50, autovacuum_enabled=off'
6. Monitoramento e Automação do Ciclo de Vida
Use métricas do pg_stat_user_tables para identificar dados que se tornaram frios e ferramentas como pg_partman para automação.
-- Identificar tabelas candidatas a tiering
SELECT schemaname, tablename,
n_tup_ins + n_tup_upd + n_tup_del as total_writes,
seq_scan + idx_scan as total_reads,
n_live_tup as row_count
FROM pg_stat_user_tables
WHERE (seq_scan + idx_scan) < 100
AND (n_tup_ins + n_tup_upd + n_tup_del) > 10000
ORDER BY total_reads ASC;
-- Configuração pg_partman para retenção automática
SELECT partman.create_parent(
p_parent_table := 'public.transacoes',
p_control := 'data_transacao',
p_type := 'native',
p_interval := '1 month',
p_premake := 3
);
-- Política de retenção: manter 36 partições (3 anos)
UPDATE partman.part_config
SET retention = '36 months',
retention_keep_table = false
WHERE parent_table = 'public.transacoes';
7. Casos de Uso e Exemplos Práticos
Sistema de logs de aplicação:
-- Hot: últimas 24h em memória (Redis)
-- Warm: 30 dias em PostgreSQL particionado por dia
-- Cold: histórico em S3 compressado
CREATE TABLE logs (
id UUID DEFAULT gen_random_uuid(),
timestamp TIMESTAMPTZ DEFAULT NOW(),
level TEXT,
message TEXT,
service TEXT
) PARTITION BY RANGE (timestamp);
-- Partição diária para warm
CREATE TABLE logs_20250328
PARTITION OF logs
FOR VALUES FROM ('2025-03-28') TO ('2025-03-29')
TABLESPACE ssd_fast;
-- Exportação diária para cold storage
SELECT cron.schedule('export-logs-cold', '0 4 * * *', $$
COPY (
SELECT * FROM logs
WHERE timestamp < NOW() - INTERVAL '30 days'
) TO PROGRAM 'gzip > /cold_backup/logs_$(date -d "30 days ago" +%Y%m%d).csv.gz';
DELETE FROM logs WHERE timestamp < NOW() - INTERVAL '30 days';
$$);
Dados de sensores IoT:
-- Tiering por dispositivo e timestamp
CREATE TABLE sensor_data (
device_id INT,
timestamp TIMESTAMPTZ,
temperatura DECIMAL(5,2),
umidade DECIMAL(5,2)
) PARTITION BY RANGE (timestamp);
-- Hot: dados das últimas 24h em tabela não particionada
CREATE TABLE sensor_data_hot (
device_id INT,
timestamp TIMESTAMPTZ,
temperatura DECIMAL(5,2),
umidade DECIMAL(5,2)
) TABLESPACE ram_disk;
-- Migração para warm a cada hora
CREATE OR REPLACE FUNCTION migrate_sensor_data()
RETURNS void AS $$
BEGIN
INSERT INTO sensor_data
SELECT * FROM sensor_data_hot
WHERE timestamp < NOW() - INTERVAL '1 hour';
DELETE FROM sensor_data_hot
WHERE timestamp < NOW() - INTERVAL '1 hour';
END;
$$ LANGUAGE plpgsql;
Referências
- PostgreSQL Documentation: Table Partitioning — Documentação oficial sobre particionamento por range para tiering de dados quentes e frios.
- pg_partman: Partition Management Extension — Ferramenta de automação para gerenciamento de partições, retenção e movimentação entre tiers.
- AWS Storage Tiering Best Practices — Guia oficial sobre classes de armazenamento S3 (Standard, Glacier, Deep Archive) para cold data.
- ClickHouse Documentation: Storage Policies — Como configurar políticas de armazenamento em múltiplos tiers no ClickHouse para dados frios.
- PostgreSQL BRIN Indexes — Documentação oficial sobre índices BRIN, ideais para dados históricos com ordenação temporal.