Executando verificação de segurança...
18

✅ Finalizando a migração para o ClickHouse - Valeu a pena?

Saga da Migração: PostgreSQL → ClickHouse

Bom galera, finalizando aqui nesse post a pequena saga de migração do PostgreSQL para o ClickHouse.
Coloquei o novo DB em produção agora a pouco e não tive problemas! 🎉


Nosso caminho até aqui...

  1. Reduzi um DB de 52gb para 4.5gb! PostgreSQL -> Clickhouse
  2. Reduzi um DB de 8TB para 218 GB! como? ClickHouse!
  3. Os "perrengues" depois de transformar um DB de 8TB em 218GB
  4. Depois de migrar 8TB, o Clickhouse "sequestrou" meus dados kkkk

Durante essa jornada tive imprevistos, dificuldades, mas também ótimos resultados que fizeram todo o processo valer a pena.


Antes (PostgreSQL)

  • Banco de 8TB
  • Consultas variando entre 100ms e 10s (dependendo da carga e do tamanho da consulta)
  • Servidor: 8 vCPU / 16 threads, 90GB RAM, 10TB de disco (crescimento constante)
  • Picos de 100% de CPU constantes, e RAM em 70-80% a todo momento.
  • Migração recente para aplicar particionamento mais definido — mas mesmo assim já dava sinais de “cansaço”.

Depois (ClickHouse)

  • Banco caiu para 270GB (tabela principal + tabelas de agregações)
  • Consultas em média de 70ms–1s
  • Servidor: 6 vCPU / 12 threads (90% do tempo mal usa 1 CPU)
  • 32GB RAM (apenas 3GB usados na maior parte do tempo)
  • Expurgo automático de dados após o período de validade (coisa que era problemática no PostgreSQL)
  • Remoção de duplicações nos dados automaticamente!. essa era uma dor constante no PostgreSQL, ter que consultar os dados e remover as duplicações no código, no ClickHouse essas duplicações são removidas automaticamente sem dor de cabeça!

Ingestão de dados

  • Antes: 6 instâncias consumindo Kafka em paralelo para dar conta do PostgreSQL
  • Agora: apenas 1 instância consome 600Mi de linhas/dia sem atraso

Benefícios

  • Consultas rápidas e flexíveis, permitindo filtros mais definidos e personalizados
  • Economia de mais de 90% em disco 🎉
  • Possibilidade de expansão horizontal para acompanhar crescimento futuro

Observação Importante

Não estou dizendo que o PostgreSQL é ruim — muito pelo contrário!
Ele continua sendo um dos melhores DBs para a maioria dos casos e ainda usamos em partes do sistema que exigem inserções e atualizações frequentes.

O problema está no cenário analítico:

  • Hoje temos 38Bi de linhas
  • Nesse volume, o PostgreSQL não entrega a mesma performance e economia de recursos que o ClickHouse.

O Problema da MV (Materialized View)

No post anterior (aqui) comentei sobre dificuldades na migração de dados entre tabelas.

Descobri que a causa era uma View Materializada na tabela de agregação que removia duplicações.

  • Durante migrações pesadas, ela não conseguia acompanhar o ritmo dos inserts
  • Chegava a 30% do processo e explodia em erro por falta de recursos

Em produção isso não acontece, já que o volume de inserts é gradual.

Solução: remover a MV durante a migração. Resultado: 36Bi de linhas migradas em 44 minutos. 🚀

📌 Dica: usem o clickhouse-client via terminal — mostra progresso em tempo real e erros claros, diferente do DBeaver que só mostra mensagens genéricas.


Lições e Dicas

  1. Planeje bem o ORDER BY da tabela

    • Ele pode acelerar absurdamente as consultas ou torná-las inutilizáveis.
    • Testei 4x diferentes combinações até chegar no modelo atual.
  2. Schema quase fixo

    • O ClickHouse não permite tantas alterações no schema.
    • Ideal começar no PostgreSQL, validar a modelagem e só depois migrar pro ClickHouse.
  3. Sobre batches

    • Usar createdAt (dica dada em um comentário) como critério de migração não ajudaria, pois não faz parte da chave de ordenação.
    • Consultas por essa coluna seriam extremamente lentas.
    • Usar outras colunas para "percorrer" os dados não entrega uma exatidão de não repetir alguns dados entre batches.

Deploy e Infraestrutura

  • Uso ClickHouse em Docker, com bind da pasta de dados para o host.
  • Sim, já li várias vezes que “não se deve rodar DB em container”. Também acreditei nisso.

Mas depois de alguns perrengues, mudei de ideia!

Resultado fora do container: logs espalhados e dificuldade de gerenciar. Dificuldade de identificar motivo de instabilidades e quedas.
Resultado com Docker + Portainer:

  • Fácil visualizar logs
  • Reiniciar/recriar container em poucos cliques
  • Monitoramento simples (CPU, memória, disco, rede)
  • Nenhuma perda de desempenho observada

👉 Meu veredito: usem Docker. Testem, ajustem e vejam se atende.


Conclusão

Estou muito feliz com o resultado:

  • Economia absurda de disco (90%+)
  • Consultas rápidas e consistentes
  • Ingestão simplificada
  • Escalabilidade futura garantida

O ClickHouse mostrou maturidade para ser a solução definitiva para nosso cenário atual e deve ganhar ainda mais espaço dentro do sistema.


Obrigado a todos que acompanharam a saga! 🙌

Só continuei compartilhando porque vi que havia interesse no tema.

Foi gratificante buscar no Google sobre ClickHouse e encontrar um dos meus próprios posts linkados 😅. Espero que esse relato ajude quem também está pesquisando sobre esse DB.

Qualquer dúvida, deixem nos comentários — pode ser que eu tenha esquecido de falar algo. 😉

Carregando publicação patrocinada...
2

Cara nunca usei ClickHouse, mas achei muito interessante sua saga, fiquei esperando os "próximos capítulos" a cada novo post... parabéns e obrigado por compartilhar!!

1
2
0
2
0
1

Muito legal ver a saga, e conhecer mais dessa ferramenta. Vou fazer meus estudos sobre ela tb.

Uma coisa me chamou atenção: "Antes: 6 instâncias consumindo Kafka em paralelo para dar conta do PostgreSQL".
Já vi isso ser causador de muito problema, esses workers usavam bulk upsert pra sincronizar os dados pro PG?

2

opa, obrigado pelo comentário.

sobre os workers, eles enviavam paralelamente sem sincronismo, eram independentes.
o PostgreSQL que lidava com os inserts pra organizar, inclusive isso foi um problema quando tentei implementar um indice de unicidade pra tentar evitar duplicações, as 6 instâncias entravam em conflito direto por conta de dead Lock no índice.

ai tive que remover o indice de unicidade, só mantive indices normais mesmo pra auxiliar nas buscas, mas não tive problemas com sincronismo de inserts.

edit: as duplicações não eram por conta dos inserts em paralelo, ja chegava na fila do Kafka alguns dados duplicados por conta da natureza do sistema mesmo, múltiplos agentes inserindo no Kafka e alguns estavam observando os mesmos dados (pra redundância)

1

Tenho cenário semelhante, mas em menor escala, porém mesmo assim uma grande volumetria - 400~600 tps em média no tópico Kafka. No passado, o workers inseriam do jeito tradicional, com insert into table(....) values (...) ou update table set.... Esse algoritmo ruim, não dava conta de sincronizar, estava sempre com lag, e ao escalar os workers, começava a catástrofe do ambiente. O alto número do workers fazia o DB ficar sempre com carga excessiva, acima de 80% de CPU.

Fiz um mudança pequena, no lugar de inserir/atualizar com comandos SQL cada mensagem recebida do tópico (q demanda mais cpu pra parser no db), passei a fazer bulk upsert da seguinte forma:

  1. Agrupar mensagens do tópico em pacotes antes de enviar pro DB. Fiz duas regras de corte do pacote: 5 mil mensagens, ou 10 segundos sem receber mensagens.
  2. Criar uma temporary table copiada da original (create temp table nome_temporario on commit drop as table nome_original with no data)
  3. Inserir o pacote de mensagens agrupadas com o com copy from stdin...
  4. Ao final copiar dados da tabela temporária para original com comando de upsert: insert into tabela(campos) values (valores) on conflict (campo pk) do update campos. (Com índice único, pois tb tenho situação parecida de duplicidades de msgs).
  5. Tudo isso é uma transaction.l

Com isso, reduzi o uso de CPU de 85% pra 13~15% em média, e sem lag.
Hj o db é um aurora postgresql r6g.large (2 cpu x 16 ram), e o worker é apenas uma instância de ecs com 0.5 cpu x 1 gb de ram (e até poderia ser menor, mas tem outras coisas internas q não vem ao caso aqui).

A otimização do worker, normalizou o resto do ambiente, apis q dependem desse db obviamente passaram a responder mais rápido, e de propósito não deixo mais o worker escalar pra não degradar o ambiente, embora com o novo algoritmo não deva ser problema processar umas 500 milhões de msg por dia no mesmo hardware.

Pro seu cenário de big data sobre telemetria de aplicações, tb julgo correta a mudança pra um DB colunar pra otimizar as consultas com agregações, só queria compartilhar essa solução de carga de alto volume de dados em postgresql após ler essa parte em específico da sua saga. Pretendo montar um post para explicar em maiores detalhes.
Pra quem se interessar, aqui tem alguns benchmarks e exemplos do que venho preparando.

Valeuuu, e novamente parabéns pela história e por compartilhar.

1

muito interessante seu comentário.
realmente é uma solução robusta.

vou estudar sobre essa ideia pra implementações futuras em outros DBs.

sobre o insert em bulk que vc mencionou, tive que fazer algo similar no PostgreSQL antes.

também deixava acumular em memória um lote de 5-10k linhas na aplicação (puxando em lotes tambem do kafka)

e depois mandava pro insert no PostgreSQL de uma vez.

cada uma das instâncias fazia isso de forma independente.

mas no meu cenário não existe update, é so inserir mesmo, então imagino que isso tenha evitado de eu ter esse problema que você descreveu no seu caso.

mas bom saber que tem uma solução pra esse tipo de situação também.

vou deixar aqui indexado no meu notion esse seu comentário pra aprendizado futuro.