Pular para o conteúdo principal
Todos os artigosPlataformas de Dados

De RDS para ClickHouse: 100M de mensagens/dia com p99 abaixo de 10ms

Benchmark de fundo sobre como eliminar contenção de locks em bancos relacionais e migrar para armazenamento colunar em consultas de telemetria de sub-segundo.

Publicado em

leitura de 12 min


O sintoma era sempre o mesmo: o dashboard de telemetria levava 30 segundos para responder, e o time de infraestrutura respondia que o banco estava são. Estava. Ele só nunca foi desenhado para a pergunta que estávamos fazendo.

A causa raiz é o modelo de acesso, não o volume

Telemetria é um caso de leitura analítica puro: agregações de baixo cardinalidade sobre janelas de tempo, quase nunca de volta a uma linha individual. Um banco relacional transacional resolve esse padrão da forma mais cara possível: B-tree, page split, contenção de buffer pool e um plano de execução que precisa tocar milhões de linhas para responder o que é uma soma.

Bancos colunares invertem todas essas decisões. Colunas são independentes, então uma agregação lê apenas as colunas necessárias. Partições por tempo tornam a poda quase gratuita. E a compressão por coluna reduz a varredura em uma ordem de grandeza.

O caminho, na ordem em que funciona

  1. Não migre o banco. Migre a responsabilidade: extraia o fluxo de telemetria para um caminho de escrita dedicado e deixe o relacional cuidar do que ele faz bem.
  2. ETL com Databricks para normalizar, deduplicar e agregar antes da carga. O mais rápido insert em ClickHouse é o que nunca aconteceu.
  3. Escolha a chave de ordenação pela consulta mais frequente, não pela entidade. Em telemetria, quase sempre é (timestamp, device_id).
  4. Materialize visões para as consultas que rodam a cada cinco minutos e mantenha o resto em consultas ad-hoc.

sql

CREATE TABLE telemetry_events (
  occurred_at   DateTime64(3, 'UTC') CODEC(Delta(8), ZSTD(1)),
  device_id    UInt64          CODEC(ZSTD(1)),
  event_type   LowCardinality(String) CODEC(ZSTD(1)),
  payload      String          CODEC(ZSTD(3)),
  ingested_at  DateTime64(3, 'UTC') DEFAULT now()
) ENGINE = MergeTree
PARTITION BY toYYYYMM(occurred_at)
ORDER BY (event_type, occurred_at, device_id)
TTL toDateTime(occurred_at) + INTERVAL 25 MONTH;

Resultados medidos

  • Tempo da consulta do dashboard: 30s → 190ms.
  • Carga no banco relacional: −72%, porque ele deixou de ser o caminho analítico.
  • Throughput de ingestão: 100M de mensagens/dia com p99 de ingestão abaixo de 10ms.
  • Armazenamento: −88% frente ao relacional equivalente, por compressão colunar e TTL nativo.

Quando não migrar

Se a consulta é por chave primária, se o volume cabe folgadamente na memória e se ninguém precisa agregar milhões de linhas, o relacional continua sendo a escolha certa. Arquitetura séria inclui saber quando não usar a ferramenta que você acabou de dominar.

Tags

  • ClickHouse
  • MySQL
  • latência
  • OLAP
  • ETL
  • Databricks