Nota histórica: esta série revisita minha trajetória em Engenharia de Dados iniciada em 2012. Apache Iceberg, Delta Lake e Apache Hudi surgiram posteriormente. Neste capítulo, conectamos os fundamentos daquela jornada às arquiteturas Lakehouse modernas.
Nos capítulos anteriores, aprendemos como o Apache Spark executa processamento distribuído, organiza Tasks, utiliza memória, movimenta dados por shuffle e otimiza consultas.
Na Parte 12, exploramos os formatos CSV, JSON, Parquet e ORC.
Entendemos por que formatos colunares são importantes para workloads analíticos e como recursos como Column Pruning, Predicate Pushdown e Partition Pruning podem reduzir o custo de leitura.
Mas existe uma limitação que merece atenção.
Um conjunto de arquivos Parquet não é, automaticamente, uma tabela transacional.
Imagine um Data Lake contendo milhares de arquivos Parquet.
Precisamos atualizar pedidos, corrigir registros, receber novos eventos, consultar versões anteriores e permitir que diferentes aplicações leiam os dados enquanto outras escrevem.
Como garantir consistência?
Como controlar quais arquivos pertencem à versão atual da tabela?
Como recuperar uma versão anterior?
E como impedir que duas operações concorrentes deixem os dados em um estado inconsistente?
Essas perguntas nos levam aos formatos de tabela e à arquitetura Data Lakehouse.
1. Data Lake, Data Warehouse e Lakehouse
Antes de comparar tecnologias, precisamos entender o problema arquitetural.
Data Warehouse
Um Data Warehouse tradicional oferece recursos como modelagem analítica, SQL, gerenciamento de tabelas, otimização de consultas e mecanismos de consistência.
É projetado para facilitar o consumo estruturado de dados.
Data Lake
Um Data Lake permite armazenar dados em diferentes formatos e estruturas, frequentemente utilizando armazenamento distribuído ou de objetos.
Pode receber:
- Dados estruturados.
- Dados semiestruturados.
- Arquivos brutos.
- Eventos.
- Logs.
- Dados históricos.
O Data Lake oferece flexibilidade, mas arquivos isolados não fornecem automaticamente todas as garantias de um sistema de tabelas.
Data Lakehouse
A arquitetura Lakehouse procura combinar a flexibilidade do armazenamento de Data Lakes com capacidades de gerenciamento e consistência de tabelas analíticas.
Conceitualmente:
DATA SOURCES | v OBJECT STORAGE | v OPEN TABLE FORMAT | +----------+----------+ | | | v v v SQL BI ML / AI A proposta não é simplesmente substituir o Data Warehouse.
É disponibilizar capacidades adicionais sobre dados armazenados em formatos abertos e acessíveis a diferentes mecanismos de processamento.
2. O problema dos arquivos Parquet isolados
Imagine uma tabela de pedidos representada por três arquivos:
pedidos/ part-00001.parquet part-00002.parquet part-00003.parquet Agora precisamos atualizar o status de um pedido.
Em uma arquitetura baseada apenas em arquivos, uma abordagem seria:
- Ler os dados existentes.
- Aplicar a atualização.
- Reescrever os arquivos afetados.
- Substituir os arquivos anteriores.
Parece simples.
Mas imagine que outra aplicação esteja lendo a tabela enquanto os arquivos são substituídos.
Dependendo da estratégia utilizada, ela pode observar um conjunto incompleto ou inconsistente de arquivos.
Outro problema surge quando duas aplicações tentam modificar os mesmos dados simultaneamente.
Precisamos de um mecanismo que controle qual conjunto de arquivos representa uma versão válida da tabela.
Essa é uma das principais responsabilidades dos formatos de tabela modernos.
3. Formato de arquivo não é formato de tabela
Essa distinção é fundamental.
Parquet define como os dados são armazenados fisicamente em arquivos.
Iceberg, Delta Lake e Hudi adicionam mecanismos para gerenciar tabelas compostas por arquivos.
Uma visão conceitual:
TABLE | v TABLE METADATA | v TABLE SNAPSHOT | v DATA FILES | v PARQUET Os detalhes internos diferem entre as tecnologias.
Mas a ideia geral é semelhante: precisamos de uma camada de gerenciamento acima dos arquivos.
Essa camada pode oferecer:
- Transações.
- Controle de versões.
- Metadados.
- Evolução de schema.
- Atualizações e exclusões.
- Operações concorrentes.
- Gerenciamento do ciclo de vida dos arquivos.
Isso transforma a maneira como trabalhamos com dados analíticos.
4. ACID em tabelas analíticas
ACID representa quatro propriedades tradicionalmente associadas a transações.
Atomicidade: uma operação transacional deve ser aplicada integralmente ou não ser confirmada.
Consistência: a transação deve preservar as regras e invariantes garantidos pelo sistema.
Isolamento: operações concorrentes devem respeitar o modelo de isolamento oferecido.
Durabilidade: uma transação confirmada deve permanecer registrada conforme as garantias do sistema.
Em uma arquitetura Lakehouse, essas propriedades são implementadas por mecanismos específicos de metadados, logs, snapshots e controle de concorrência.
É importante não presumir que todos os formatos ofereçam exatamente os mesmos níveis de isolamento ou comportamento em qualquer engine.
As garantias precisam ser verificadas para cada combinação de formato, catálogo, armazenamento e mecanismo de processamento.
5. O conceito de snapshot
Imagine uma tabela com três arquivos.
SNAPSHOT 100 File A File B File C Depois, uma operação atualiza determinados registros.
A nova versão pode referenciar:
SNAPSHOT 101 File A File C File D O arquivo B deixou de fazer parte da versão atual e foi substituído por D.
Observe que não precisamos necessariamente modificar o conteúdo dos arquivos antigos.
Podemos representar a evolução da tabela por metadados que identificam os arquivos válidos em cada versão.
Isso permite implementar recursos como:
- Leitura consistente.
- Histórico de versões.
- Rollback, quando suportado.
- Time Travel.
- Controle de mudanças.
Os detalhes de retenção e limpeza de arquivos são importantes: uma versão antiga só poderá ser consultada enquanto seus metadados e arquivos necessários estiverem disponíveis.
6. Apache Iceberg
O Apache Iceberg é um formato aberto de tabela desenvolvido para datasets analíticos de grande escala.
Seu projeto enfatiza gerenciamento de metadados, evolução de tabelas e interoperabilidade entre mecanismos de processamento.
Uma arquitetura conceitual:
ICEBERG TABLE | v CATALOG ENTRY | v METADATA FILE | v SNAPSHOT | v MANIFEST LIST | v MANIFEST FILES | v DATA FILES Os arquivos de manifesto descrevem informações sobre arquivos de dados e seus metadados.
Essa organização permite que engines identifiquem os arquivos relevantes sem depender exclusivamente de uma listagem completa de diretórios.
Iceberg também suporta arquivos de exclusão em cenários e versões compatíveis.
7. Evolução de schema no Iceberg
Imagine uma tabela inicial:
customer_id customer_name state Agora precisamos adicionar:
customer_segment Em sistemas baseados apenas em arquivos, mudanças de schema podem exigir cuidados adicionais para manter a interpretação consistente dos dados históricos.
O Iceberg oferece mecanismos de evolução de schema, incluindo identificação de campos por IDs.
Isso ajuda a evitar determinadas ambiguidades associadas a mudanças de nomes e posições de colunas.
Exemplo conceitual em Spark SQL:
ALTER TABLE lakehouse.crm.clientes ADD COLUMN customer_segment STRING; A operação depende de um catálogo Iceberg corretamente configurado.
O recurso é especialmente importante em plataformas nas quais os contratos de dados evoluem continuamente.
8. Hidden Partitioning
Um recurso conhecido do Iceberg é o Hidden Partitioning.
Em datasets particionados por diretórios tradicionais, frequentemente precisamos lidar explicitamente com colunas derivadas como:
ano mes dia Iceberg permite definir transformações de particionamento nos metadados da tabela.
Por exemplo:
CREATE TABLE lakehouse.sales.pedidos ( pedido_id BIGINT, cliente_id BIGINT, data_pedido TIMESTAMP, valor DECIMAL(12,2) ) USING iceberg PARTITIONED BY (days(data_pedido)); Nesse exemplo, a tabela é particionada por dia com base no timestamp.
O consumidor pode consultar a coluna original:
SELECT * FROM lakehouse.sales.pedidos WHERE data_pedido >= TIMESTAMP '2026-11-01 00:00:00' AND data_pedido < TIMESTAMP '2026-11-02 00:00:00'; O mecanismo pode utilizar os metadados de particionamento para reduzir os arquivos examinados.
Isso diminui o acoplamento entre a lógica das consultas e a estrutura física do armazenamento.
9. Configurando Iceberg com Spark
Uma integração Spark–Iceberg pode utilizar um catálogo configurado na SparkSession.
Exemplo ilustrativo com catálogo Hadoop para desenvolvimento local:
from pyspark.sql import SparkSession spark = ( SparkSession.builder .appName("IcebergExample") .config( "spark.sql.extensions", "org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions" ) .config( "spark.sql.catalog.lakehouse", "org.apache.iceberg.spark.SparkCatalog" ) .config( "spark.sql.catalog.lakehouse.type", "hadoop" ) .config( "spark.sql.catalog.lakehouse.warehouse", "file:///tmp/iceberg-warehouse" ) .getOrCreate() ) Importante: esse exemplo pressupõe que os artefatos Iceberg compatíveis com a versão do Spark e do Scala estejam disponíveis no classpath. Apenas configurar a SparkSession não instala as dependências.
O catálogo Hadoop local é adequado para experimentação controlada, não uma recomendação genérica para produção distribuída.
Em produção, devemos avaliar catálogos e mecanismos de armazenamento compatíveis com os requisitos de concorrência e atomicidade.
10. Criando uma tabela Iceberg
Com o ambiente configurado:
spark.sql(""" CREATE NAMESPACE IF NOT EXISTS lakehouse.sales """) Depois:
spark.sql(""" CREATE TABLE IF NOT EXISTS lakehouse.sales.pedidos ( pedido_id BIGINT, cliente_id BIGINT, status STRING, valor DECIMAL(12,2) ) USING iceberg """) Inserimos dados:
spark.sql(""" INSERT INTO lakehouse.sales.pedidos VALUES (1, 101, 'CRIADO', 150.00), (2, 102, 'PAGO', 230.00), (3, 103, 'CRIADO', 99.90) """) Agora podemos consultar:
spark.sql(""" SELECT * FROM lakehouse.sales.pedidos """).show() A tabela possui metadados gerenciados pelo formato Iceberg, em vez de ser apenas um diretório de arquivos Parquet sem gerenciamento transacional.
11. MERGE INTO: atualizações incrementais
Em pipelines modernos, frequentemente recebemos alterações incrementais.
Imagine um fluxo de CDC — Change Data Capture.
O sistema de origem informa que o pedido 1 mudou de:
CRIADO para:
PAGO Com suporte adequado do formato e da engine, podemos utilizar MERGE INTO.
MERGE INTO lakehouse.sales.pedidos AS destino USING ( SELECT CAST(1 AS BIGINT) AS pedido_id, 'PAGO' AS status ) AS origem ON destino.pedido_id = origem.pedido_id WHEN MATCHED THEN UPDATE SET destino.status = origem.status; Esse padrão é importante para:
- Ingestão incremental.
- Sincronização de sistemas.
- Atualização de dimensões.
- Correção de registros.
- Processamento de eventos de alteração.
Mas um MERGE não resolve automaticamente duplicidades ou eventos fora de ordem.
Precisamos definir regras de negócio, chaves e ordenação das alterações.
12. Delta Lake
O Delta Lake é outra tecnologia de gerenciamento de tabelas para Data Lakes.
Sua arquitetura utiliza um log transacional, conhecido como Delta Log, para controlar as versões e alterações da tabela.
Conceitualmente:
DELTA TABLE | +----------+----------+ | | v v DATA FILES _delta_log/ | | v v PARQUET COMMITS | v CHECKPOINTS O log registra as ações que compõem o estado da tabela.
Checkpoints ajudam a tornar mais eficiente a reconstrução desse estado.
O Delta Lake é amplamente utilizado em arquiteturas Lakehouse e possui integração importante com o ecossistema Spark.
13. Escrevendo uma tabela Delta
Em um ambiente com Delta Lake instalado e configurado:
dados = spark.createDataFrame( [ (1, "CRIADO", 150.0), (2, "PAGO", 230.0), (3, "CRIADO", 99.9) ], ["pedido_id", "status", "valor"] ) Podemos escrever:
( dados.write .format("delta") .mode("overwrite") .save("/tmp/delta-pedidos") ) E ler:
df_delta = ( spark.read .format("delta") .load("/tmp/delta-pedidos") ) df_delta.show() Esse exemplo não funciona em uma instalação Spark pura sem os componentes Delta necessários.
As versões do Delta Lake, Spark e Scala precisam ser compatíveis.
14. Atualizações com Delta Lake
Uma abordagem programática utiliza a API DeltaTable:
from delta.tables import DeltaTable tabela = DeltaTable.forPath( spark, "/tmp/delta-pedidos" ) tabela.update( condition="pedido_id = 1", set={"status": "'PAGO'"} ) Também podemos realizar operações MERGE quando as condições e a versão utilizada oferecerem suporte.
Um aspecto importante é que essas operações não devem ser interpretadas como alterações diretas e arbitrárias de arquivos Parquet.
Elas são gerenciadas pelo mecanismo transacional da tabela.
15. Time Travel
Um recurso bastante útil em formatos de tabela modernos é consultar versões anteriores.
Imagine:
Version 0 → Pedidos originais Version 1 → Atualização de status Version 2 → Novos pedidos Em Delta Lake, podemos consultar uma versão anterior:
versao_anterior = ( spark.read .format("delta") .option("versionAsOf", 0) .load("/tmp/delta-pedidos") ) Isso pode ajudar em:
- Auditoria.
- Investigação de incidentes.
- Comparação de versões.
- Reprocessamento.
- Recuperação lógica.
Mas Time Travel não deve ser confundido com backup completo.
Se arquivos antigos forem removidos por políticas de retenção ou manutenção, determinadas versões podem deixar de estar disponíveis.
16. Apache Hudi
O Apache Hudi também oferece mecanismos de gerenciamento de tabelas sobre Data Lakes.
Uma de suas características é o foco em workloads com ingestão incremental, atualizações e gerenciamento eficiente de registros.
Hudi disponibiliza diferentes tipos de tabela, incluindo:
Copy-on-Write (CoW)
Atualizações podem resultar na reescrita de arquivos base.
Merge-on-Read (MoR)
Alterações podem ser registradas em estruturas adicionais e reconciliadas durante a leitura ou por operações de compactação, conforme a configuração.
Conceitualmente:
HUDI TABLE | TABLE TIMELINE | +--------+--------+ | | v v BASE FILES LOG FILES | | +--------+--------+ | v QUERY RESULT O comportamento exato depende do tipo de tabela, das operações e da versão utilizada.
17. Copy-on-Write vs. Merge-on-Read
Considere um dataset que recebe muitas atualizações.
Em uma abordagem Copy-on-Write:
Existing File | v Update Records | v Rewrite File | v New File Version Isso pode favorecer determinados padrões de leitura, mas produzir amplificação de escrita.
Em uma abordagem Merge-on-Read:
Base File | +-- Update Log | +-- Update Log | v Merged Read Podemos reduzir determinados custos imediatos de atualização, mas introduzir trabalho adicional de leitura ou manutenção.
O trade-off depende de:
- Frequência de atualização.
- Latência exigida.
- Padrões de consulta.
- Estratégia de compactação.
- Volume de dados.
- Recursos disponíveis.
Não existe uma estratégia universalmente superior.
18. Hudi e pipelines incrementais
Imagine um sistema transacional que produz eventos de alteração.
Operational Database | v CDC | v Kafka | v Spark Processing | v Hudi Table | v Analytical Queries Esse tipo de arquitetura permite construir datasets analíticos atualizados incrementalmente.
Mas precisamos resolver problemas como:
- Identificação única dos registros.
- Ordenação de eventos.
- Atualizações fora de ordem.
- Deduplicação.
- Exclusões.
- Reprocessamento.
- Consistência entre origem e destino.
O formato de tabela oferece mecanismos úteis, mas a correção do pipeline continua dependendo da engenharia da aplicação.
19. Comparando Iceberg, Delta Lake e Hudi
| Critério | Apache Iceberg | Delta Lake | Apache Hudi |
|---|---|---|---|
| Organização central | Snapshots e manifests | Log transacional | Timeline de operações |
| Arquivos de dados | Frequentemente Parquet | Principalmente Parquet | Frequentemente Parquet, com logs conforme o tipo |
| Evolução de schema | Sim | Sim | Sim |
| Operações incrementais | Sim, conforme engine | Sim, conforme engine | Sim |
| Time Travel | Sim | Sim | Sim, conforme recursos e retenção |
| Atualizações e exclusões | Sim, conforme engine | Sim | Sim |
| Integração com Spark | Sim | Sim | Sim |
| Característica de destaque | Metadados e interoperabilidade | Ecossistema Delta e integração Spark | Ingestão e atualização incremental |
Essa tabela é uma visão conceitual.
Recursos específicos, desempenho e interoperabilidade variam conforme versões, catálogos, engines e configurações.
Portanto, não devemos escolher um formato apenas por uma comparação superficial de funcionalidades.
20. Como escolher entre os três?
Minha avaliação começa pelos requisitos.
Quando avaliar Iceberg
Iceberg merece atenção quando buscamos:
- Interoperabilidade entre engines.
- Gerenciamento de metadados em grande escala.
- Evolução de schema e particionamento.
- Integração com catálogos.
- Arquiteturas analíticas abertas.
Quando avaliar Delta Lake
Delta Lake merece atenção quando buscamos:
- Integração com Spark.
- Operações transacionais sobre tabelas analíticas.
- Histórico e versionamento.
- Pipelines de transformação e atualização.
- Ecossistema de ferramentas compatíveis.
Quando avaliar Hudi
Hudi merece atenção quando buscamos:
- Ingestão incremental frequente.
- Upserts.
- Processamento de CDC.
- Estratégias de atualização.
- Workloads com diferentes requisitos de leitura e escrita.
Esses cenários não são exclusivos.
Iceberg e Delta também podem atender ingestão incremental, e Hudi também pode atender analytics.
A decisão correta depende dos requisitos e de benchmarks representativos.
21. O papel dos catálogos
Uma tabela Lakehouse precisa ser descoberta e identificada.
É aqui que entram os catálogos.
Um catálogo pode ajudar a gerenciar:
- Namespaces.
- Identificadores de tabelas.
- Localização de metadados.
- Integração com engines.
- Controles de acesso, conforme a implementação.
- Descoberta e organização.
Uma arquitetura conceitual:
DATA CONSUMERS / | \ v v v Spark Trino Analytics \ | / v v v CATALOG | v TABLE METADATA | v OBJECT STORAGE Em ambientes Iceberg, por exemplo, diferentes implementações de catálogo podem ser utilizadas.
A escolha do catálogo também influencia concorrência, operação, governança e integração.
Formato de tabela e catálogo são decisões relacionadas, mas distintas.
22. Multi-engine: uma promessa que exige validação
Uma vantagem importante das arquiteturas abertas é permitir que diferentes engines trabalhem com os mesmos datasets.
Por exemplo:
SHARED TABLE | +----------+----------+ | | | v v v Spark Trino Flink Mas precisamos distinguir:
Conseguir ler uma tabela não significa necessariamente conseguir executar todas as operações de escrita e manutenção com as mesmas garantias.
Compatibilidade pode variar para:
- MERGE.
- DELETE.
- UPDATE.
- Time Travel.
- Evolução de schema.
- Branches.
- Deletion vectors.
- Recursos específicos do formato.
Em arquiteturas multi-engine, a matriz de compatibilidade deve fazer parte da documentação técnica.
23. Schema Evolution vs. Schema Enforcement
Esses dois conceitos são frequentemente confundidos.
Schema Enforcement significa validar operações de escrita contra as regras de schema suportadas pela tabela.
Schema Evolution significa permitir alterações controladas na estrutura da tabela.
Imagine:
Schema V1 --------- customer_id customer_name Depois:
Schema V2 --------- customer_id customer_name customer_segment A evolução pode ser legítima.
Mas isso não significa que qualquer mudança de tipo ou remoção de coluna deva ser aceita automaticamente.
Em produção, precisamos de contratos de dados, compatibilidade e governança.
24. ACID não substitui Data Quality
Uma tabela pode ser transacionalmente consistente e ainda conter dados incorretos.
Imagine:
pedido_id = 100 valor = -999999 A operação pode ser tecnicamente válida para o mecanismo de armazenamento, mas inválida para o negócio.
Por isso, precisamos separar:
TRANSACTIONAL CONSISTENCY | v TABLE INTEGRITY de:
BUSINESS DATA QUALITY | v VALIDATION RULES Em pipelines corporativos, podemos utilizar ferramentas e estratégias de qualidade de dados para validar:
- Unicidade.
- Completude.
- Domínios válidos.
- Integridade referencial.
- Consistência temporal.
- Regras de negócio.
Lakehouse não elimina essa responsabilidade.
25. Compactação e manutenção
Na Parte 12, discutimos o Small Files Problem.
Formatos de tabela modernos oferecem mecanismos de manutenção, embora as operações e os comandos variem.
Podemos precisar de:
- Compactação de arquivos.
- Reorganização de dados.
- Expiração de snapshots.
- Limpeza de arquivos órfãos.
- Manutenção de metadados.
- Otimização de layout.
Uma arquitetura típica:
Incremental Writes | v Many Small Files | v Compaction | v Larger Optimized Files | v Improved Read Efficiency Mas manutenção também consome recursos.
Compactar dados frequentemente demais pode aumentar custos sem ganhos proporcionais.
A política deve considerar o padrão de escrita e leitura.
26. Retenção e Time Travel
Imagine uma tabela que recebe alterações diariamente.
Ao longo do tempo, podem existir múltiplos snapshots e arquivos antigos.
Manter todas as versões indefinidamente pode aumentar custos.
Por outro lado, remover versões cedo demais pode comprometer auditoria e recuperação.
Precisamos equilibrar:
Storage Cost | v Retention Policy | v Time Travel Requirements | v Audit & Recovery Uma política de retenção deve considerar:
- Requisitos regulatórios.
- Necessidades de auditoria.
- Janelas de reprocessamento.
- Frequência de atualização.
- Custo de armazenamento.
- Estratégia de backup.
Time Travel e backup são mecanismos complementares, não equivalentes.
27. Lakehouse e CDC
Um dos cenários mais relevantes é integrar dados operacionais a uma plataforma analítica.
Imagine:
POSTGRESQL | v CDC EVENTS | v KAFKA | v SPARK STRUCTURED STREAMING | v LAKEHOUSE | v ANALYTICAL TABLES | v BI / ML / AI Esse tipo de arquitetura pode reduzir a dependência de cargas completas.
Mas exige atenção a:
- Chaves primárias.
- Semântica de exclusão.
- Ordem de eventos.
- Reprocessamento.
- Idempotência.
- Checkpoints.
- Consistência entre microbatches.
- Evolução de schema.
A tecnologia de tabela é apenas uma parte da solução.
28. Um exemplo de arquitetura corporativa
Considere uma plataforma que recebe dados de CRM, ERP, APIs e eventos.
DATA SOURCES / | \ v v v ERP CRM APIs \ | / v v v INGESTION LAYER | v RAW STORAGE | v SPARK PROCESSING | v LAKEHOUSE TABLES | +----------+----------+ | | | v v v Analytics BI ML / AI Nessa arquitetura, podemos utilizar:
- Spark para processamento distribuído.
- Parquet para armazenamento colunar.
- Um formato de tabela para gerenciamento transacional.
- Um catálogo para descoberta e integração.
- Orquestração para execução.
- Observabilidade para operação.
- Data Quality para validação.
- Governança para controle de acesso e rastreabilidade.
O Lakehouse não é um produto isolado.
É uma arquitetura composta por diferentes responsabilidades.
29. O impacto em performance e custos
Formatos de tabela podem melhorar a eficiência operacional, mas também introduzem custos de gerenciamento.
Precisamos considerar:
Benefícios potenciais
- Leitura consistente.
- Melhor gerenciamento de arquivos.
- Pruning baseado em metadados.
- Atualizações incrementais.
- Redução de reprocessamentos completos.
- Histórico de versões.
Custos e desafios
- Metadados adicionais.
- Operações de manutenção.
- Compactação.
- Controle de concorrência.
- Compatibilidade entre engines.
- Evolução operacional.
- Retenção de versões.
Uma arquitetura Lakehouse bem projetada pode melhorar a relação entre performance, governança e custo.
Mas não devemos assumir que será automaticamente mais barata em todos os cenários.
30. O que eu avaliaria em uma prova de conceito
Antes de escolher Iceberg, Delta ou Hudi para uma plataforma corporativa, eu construiria uma PoC com workloads reais.
A avaliação incluiria:
| Dimensão | O que medir |
|---|---|
| Ingestão | Throughput e latência |
| Upsert | Tempo e custo de atualização |
| Consulta | Latência e volume lido |
| Concorrência | Comportamento de leituras e escritas simultâneas |
| Schema | Evolução e compatibilidade |
| Manutenção | Compactação e limpeza |
| Metadados | Tempo de planejamento |
| Recuperação | Reprocessamento e histórico |
| Interoperabilidade | Operações suportadas por engine |
| Custo | Computação, armazenamento e operação |
A escolha deve ser fundamentada em resultados.
Não apenas em popularidade ou preferência tecnológica.
31. Erros comuns em projetos Lakehouse
Alguns erros merecem atenção.
Tratar Parquet como uma tabela transacional.
Parquet é um formato físico de arquivo. Não oferece, sozinho, todo o gerenciamento de tabelas.
Acreditar que ACID garante qualidade de dados.
Consistência transacional e qualidade de negócio são responsabilidades diferentes.
Ignorar o catálogo.
A integração entre engines depende de decisões de metadados e catálogo.
Habilitar retenção curta sem avaliar auditoria.
Isso pode eliminar versões necessárias.
Não planejar compactação.
Pipelines incrementais podem acumular muitos arquivos pequenos.
Assumir compatibilidade total entre engines.
Recursos de leitura e escrita podem variar.
Escolher tecnologia sem benchmark.
O melhor formato depende dos workloads.
32. Um modelo mental para decisões arquiteturais
Quando preciso definir uma estratégia Lakehouse, começo com:
BUSINESS REQUIREMENTS | v DATA WORKLOAD | +-------------+-------------+ | | | v v v Batch Streaming CDC | | | +-------------+-------------+ | v TABLE REQUIREMENTS | +------------+------------+ | | | v v v ACID Time Travel Evolution | | | +------------+------------+ | v ENGINE SUPPORT | v CATALOG | v TABLE FORMAT | v STORAGE PLATFORM | v OBSERVABILITY | v COST & GOVERNANCE Essa abordagem evita começar pela ferramenta antes de compreender o problema.
33. A principal lição deste capítulo
Na Parte 12, aprendemos que formatos colunares como Parquet podem melhorar a eficiência de leitura.
Agora demos um passo além.
Uma plataforma analítica moderna precisa gerenciar não apenas os bytes armazenados, mas também o estado lógico das tabelas.
Isso envolve:
- Quais arquivos pertencem à tabela.
- Qual versão está ativa.
- Como alterações são confirmadas.
- Como operações concorrentes são tratadas.
- Como schemas evoluem.
- Como versões anteriores são consultadas.
- Como arquivos antigos são mantidos ou removidos.
Iceberg, Delta Lake e Hudi oferecem abordagens diferentes para resolver esses desafios.
O princípio mais importante é:
O formato de arquivo organiza os dados. O formato de tabela organiza a consistência, a evolução e o ciclo de vida desses dados.
34. Como penso hoje
Quando alguém diz:
Vamos construir um Data Lake com Spark e Parquet.
Minha próxima pergunta é:
Como essas tabelas serão gerenciadas?
Quero entender:
Como faremos UPDATE e DELETE? | v Como trataremos CDC? | v Como garantiremos consistência? | v Qual catálogo utilizaremos? | v Quais engines terão acesso? | v Como evoluiremos o schema? | v Como manteremos os arquivos? | v Qual será a política de retenção? | v Como mediremos custo e performance? Essas perguntas representam a diferença entre armazenar arquivos e construir uma plataforma de dados sustentável.
Próximo artigo
Agora entendemos os fundamentos das arquiteturas Lakehouse.
Mas uma plataforma de dados não está completa apenas porque armazena e processa informações corretamente.
Precisamos garantir que os dados sejam confiáveis, rastreáveis e governáveis.
Na próxima parte, vamos estudar:
Data Quality, Data Contracts e Governança de Dados com Apache Spark.
Vamos explorar:
- Qualidade de dados.
- Regras de validação.
- Schema Enforcement.
- Data Contracts.
- Data Lineage.
- Catálogos.
- Metadados.
- Observabilidade.
- Quarentena de registros.
- Testes automatizados.
- Monitoramento de pipelines.
- Integração com arquiteturas Lakehouse.
A pergunta central será:
Como transformar pipelines Spark em produtos de dados confiáveis e governáveis?
Série: Como aprendi Apache Spark
← Parte 12: CSV, JSON, Parquet e ORC — performance começa no armazenamento
Próximo: Parte 14 — Data Quality, Data Contracts e Governança de Dados com Apache Spark


