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:

  1. Ler os dados existentes.
  2. Aplicar a atualização.
  3. Reescrever os arquivos afetados.
  4. 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