O que todo mundo erra sobre tabelas Iceberg
A maioria das pessoas que chega no Iceberg pela primeira vez parte do princípio de que é só uma bibliotecazinha de gestão de esquema. Isso está errado. O Iceberg é um formato de tabela com histórico de alterações, snapshot por snapshot, e isso muda completamente como você pensa sobre escrita em big data. Se você tratar como um parquete convencional, vai se dar mal rápido.
O que é a ponta do iceberg na prática
A ponta do iceberg, olhando por cima, parece ser apenas a visibilidade imediata dos dados. O restante fica escondido debaixo d'água. No contexto técnico, isso se traduz em tudo aquilo que não aparece quando você faz um SELECT: o registro de manuseio, os metadados de esquema, as referências de snapshot, as remoções vírgulas, as estatísticas de partição. O Iceberg expõe apenas o resultado final da consulta. A infraestrutura pesada fica encapsulada nos arquivos de metadados (.metadata.json) que ele mantém sincronizados. Acho que a melhor forma de explicar é mostrando como funciona o processo de escrita, antes de entrar nas definições.
Quando você grava dados em uma tabela Iceberg, o motor nono cria um novo snapshot. Esse snapshot aponta para um conjunto de arquivos de dados Parquet ou ORC, um arquivo de manifest list, e arquivos de manifest de partição. O esquema da tabela pode evoluir entre snapshots sem quebrar leituras antigas. Cada snapshot recebe um ID numérico inteiro e um timestamp. Quando alguém consulta a tabela em um momento anterior, o motor lê os metadados daquele snapshot específico e resolve os arquivos corretos. Isso é chamado de leitura point-in-time. Isso parece simples até você tentar fazer isso funcionar em produção. Aí aparecem os detalhes que ninguém conta nos tutoriais.
Instalação e setup básico
Você não precisa baixar nada separado. O Iceberg é uma biblioteca que se instala junto com o motor de processamento. Para Spark, o artefato principal é o iceberg-spark-runtime. Para Trino, é o iceberg-trino-bundle. Para PySpark, você adiciona as dependências no momento da submissão. O comando típico no Spark 3.x seria algo como: --jars iceberg-spark3.4-runtime-1.5.0.jar,spark-iceberg-runtime.jar
Isso vale para a versão 1.5.0, que é estável e suporta Spark 3.4. Se estiver usando Trino, o bundle já vem embutido no repositório oficial do projeto Iceberg no GitHub. O repositório de releases é onde você baixa os jars prontos. Não tente compilar do source a menos que tenha motivo real para isso, porque a compatibilidade entre versões do motor e da biblioteca é mais rígita do que parece. Depois de instalar, você configura o catálogo. No Spark, o mais comum é usar Hive ou REST. A configuração de catálogo Hive leva alguns minutos porque exige que o metastore esteja acessível. A configuração REST é mais moderna e funciona bem com clusters em nuvem, mas depende de um serviço de metadados REST rodando, geralmente gerenciado pelo próprio Iceberg ou por provedores como AWS Glue ou projetos de terceiro.
Como criar uma tabela e começar a escrever
Uma vez que o catálogo está configurado, a criação é direta. O SQL padrão funciona assim: CREATE TABLE catalog.db.minha_tabela (id BIGINT, nome STRING, dt DATE)
USING iceberg PARTITIONED BY (dt)
👉 Clique no botão abaixo para saber mais sobre o assunto!
O particionamento por bucket também é suportado e, nessa fase inicial, eu recomendo evitar. Particionamento por bucket gera mais arquivos menores e aumenta a sobrecarga de metadados. Comece com particionamento por faixa de data mesmo. É mais lento em consultas muito seletivas, mas é previsível e fácil de gerenciar. Para gravar dados, você pode usar INSERT convencional ou escritas batch. A escrita batch é mais rápida para grandes volumes. O Spark lida bem com escritas append, mas precisa de configuração adequada para evitar problemas de commit concorrente. O parâmetro spark.sql.catalog.catalog_name.warehouse define onde os dados vão morar, e spark.sql.catalog.catalog_name.impl define a implementação do catálogo.
O problema que todo mundo encontra depois de duas semanas
Aqui é onde entra a parte que os tutoriais não mostram. Após quelques meses de escrita, sua tabela Iceberg começa a acumular centenas de snapshots e milhares de arquivos de dados pequenos. O tempo de consulta sobe porque o motor precisa ler muitos arquivos de manifest para resolver o plano. Isso é chamado de problema de small files combinado com metadata load time. Em minha experiência, uma tabela com 400Gb de dados úteis mas com 2.300 snapshots e cerca de 18 mil arquivos Parquet de menos de 50Mb cada chegou a levar 47 segundos só para listar os arquivos de manifest antes de começar a execução real da consulta. A solução imediata é executar uma operação de compaction. No Spark, o comando é MERGE INTO ou OPTIMIZE dependendo da versão e do motor. A compaction agrupa arquivos pequenos em arquivos maiores, tipicamente entre 512Mb e 1Gb. Isso reduz drasticamente o número de arquivos e diminui o tempo de carga de metadados. Na prática, a mesma consulta que levava 47 segundos caiu para 6 segundos após a compaction, porque o número de arquivos de dados passou de 18 mil para aproximadamente 400.
Existe outro problema que aparece quando você faz muitas remoções e atualizações. O Iceberg suporta writes tipo UPSERT e DELETE, mas cada operação desses gera arquivos de remoção (.rmv) que precisam ser combinados durante a leitura. Se você fizer centenas de deletes pequenos, a combinação consome CPU e memória extras em cada consulta. A workaround aqui é programar uma rotina periódica de compaction que também funde os arquivos de remoção. Eu uso uma job agendada que roda uma compaction completa toda madrugada, e o resultado é uma redução consistente de 60 a 70 por cento no overhead de leitura.
Limitações reais do Iceberg
O Iceberg não é perfeito. Ele tem pontos fracos que merecem ser ditos claramente. O primeiro é a dependência de um serviço de metadados confiável. Se o repositório de metadados ficar indisponível, você não consegue nem listar tabelas, muito menos consultar dados. Isso é diferente de parquete puro, onde os dados estão espalhados e qualquer nó pode ler diretamente. No Iceberg, o metadados é o ponto único de falha para operações de controle. O segundo problema é a consistência eventual em escritas concorrentes. Duas jobs escrevendo na mesma tabela ao mesmo tempo podem causar conflitos de snapshot. O Iceberg detecta o conflito e lança exceção, mas isso significa retry manual ou lógica de orchestragem. Em clusters com dezenas de escritores simultâneos, a taxa de conflito pode chegar a 15 por cento das tentativas em horários de pico. Isso não é intransponível, mas exige planejamento.
O terceiro problema é a complexidade de operações mantenedoras. Compaction, limpeza de snapshots antigos, reindexação de partição. Tudo isso precisa de agendamento e monitoramento. Um engenheiro que chega achando que vai só escrever e ler vai perder pelo menos duas semanas aprendendo a manter o sistema funcionando sem degradação gradual de performance. Se o seu cenário é puramente leitura de dados históricos em um lakes simples, sem evolução de esquema, sem atualizações frequentes, sem múltiplos writers, talvez o Parquete convencional com uma camada de catálogo leve seja suficiente. O Iceberg brilha quando você precisa de schema evolution, point-in-time reads, MERGE e DELETE em escala, e governança de dados com histórico. Fora disso, você está adicionando complexidade desnecessária.
Quando escolher outra coisa
Para fluxos de dados puramente append com leituras batch em tabelas estáticas, Delta Lake e Apache Hudi são alternativas válidas. O Delta Lake tem integração mais apertada com o ecossistema Databricks e um sistema de transação mais rígido. O Hudi é forte em atualizações incrementais e suporte nativo a streaming. O Iceberg tem a vantagem de ser um formato aberto com especificação pública, sem vendor lock-in de fornecedor específico, e tem ganhado adoção em motores diversificados como Trino, Presto, Flink, e Spark. Se a portabilidade entre motores é importante para você, o Iceberg é a escolha mais segura.
Resumo rápido sobre a ponta do iceberg
A ponta do iceberg é apenas o que você vê. O formato Iceberg esconde uma camada vasta de metadados, snapshots e arquivos de manifest que determinam o comportamento real do sistema. Começar a usar é rápido. Manter funcionando bem exige entendimento de compaction, gestão de snapshots, e arquitetura de metadados. Se você levar isso a sério desde o início, evita dores de cabeça nos três primeiros meses. Se ignorar, vai passar os próximos seis resolvendo problemas que poderiam ter sido preventidos com uma configuração correta desde o começo. O download dos jars e a documentação oficial ficam no repositório do projeto Iceberg no GitHub. A página de releases tem os artefatos compatíveis com cada versão do Spark, Trino e Flink. Leitura técnica está na especificação oficial, que é aberta e gratuita. Não existe licença paga, não existe versão enterprise obrigatória. O formato é o que é, e a responsabilidade de usá-lo bem é sua.