Início/Blog

Voltar ao blog

Blog

Aqui é onde vou publicar meus artigos, minhas anotações e minhas ideias sobre o que eu estiver construindo e aprendendo.

/
Portuguese
Diário de engenharia•25 de junho de 2026•18 min de leitura

Construindo um Modern Banking Data Lakehouse End-to-End: Da Ingestão com PySpark e Apache Iceberg à Orquestração com Airflow e dbt

Um guia prático e aprofundado sobre como desenhar, implementar e orquestrar uma plataforma de dados bancária resiliente em produção, aplicando Arquitetura Medalhão, streaming com PyArrow, quarentena com PySpark, tabelas ACID com Apache Iceberg e modelagem semântica com dbt.

Engenharia de DadosPySparkApache IcebergAirflowdbtLakehouse

No setor financeiro e bancário moderno, a infraestrutura de dados vai muito além de relatórios operacionais: ela é o alicerce crítico para detecção de fraudes em tempo real, modelos de concessão de crédito e score de risco, auditoria regulatória estrita (BACEN/LGPD) e hiperpersonalização de serviços financeiros.

Contudo, construir uma plataforma de dados bancária impõe desafios de engenharia que quebram abordagens tradicionais de data warehouse:

  • Volume massivo e granularidade temporal: Milhões de transações diárias distribuídas em múltiplos canais assíncronos (PIX, TED, cartões de débito/crédito, depósitos e saques).
  • Integridade referencial rígida: Transações e pagamentos jamais podem referenciar contas fantasmas, cartões inexistentes ou comércios não cadastrados.
  • Garantia de Data Quality não bloqueante: Dados malformados ou inconsistentes não devem derrubar os pipelines de produção nem poluir a camada analítica final.
  • Auditoria regulatória, ACID e Time Travel: A obrigação legal de auditar e reproduzir o estado histórico de saldos e transações em qualquer data passada com isolamento transacional completo.

Para endereçar e solucionar esses desafios sob condições reais de produção, desenhei e implementei o Banking Data Lakehouse (Banking Pipeline) — uma plataforma de dados moderna, conteinerizada e 100% reproduzível.

1. Visão Geral da Arquitetura End-to-End

O projeto foi concebido sob o consagrado padrão da Arquitetura Medalhão (Bronze -> Silver -> Gold), combinada aos recursos avançados de um Modern Lakehouse baseado em Apache Iceberg e MinIO (storage compatível com S3):

                         FONTES DE DADOS
                Motor Sintético de Domínio Bancário
                               │
                               ▼
                      INGESTÃO EM STREAMING
                  PyArrow Chunked Batch Writer
                               │
                               ▼
                         🥉 BRONZE
                 Raw Parquet (year=YYYY/month=MM)
                               │
                               ▼
                     APACHE SPARK ENGINE
             Limpeza Distribuída & Validações
                               │
                     ┌─────────┴─────────┐
                     │                   │
                     ▼                   ▼
                  SILVER            QUARENTENA
             Dados Validados     Registros Inválidos / DLQ
                     │
                     ▼
                  🥇 GOLD
             Marts Analíticos & Agregações 360°
                     │
         ┌───────────┴───────────┐
         ▼                       ▼
   APACHE ICEBERG            DBT CORE
  Lakehouse ACID (MinIO)   DuckDB Camada Semântica
         │                       │
         └───────────┬───────────┘
                     ▼
             APACHE AIRFLOW
       Orquestração CeleryExecutor & Circuit Breakers

Stack Tecnológica e Papel de Cada Ferramenta

  • Gerador de Domínio Sintético: Python, Faker, NumPy, Pandas (geração relacional determinística respeitando distribuições assimétricas reais).
  • Ingestão em Streaming: PyArrow (processamento em lotes chunked de baixo uso de memória com gravação direta em Parquet comprimido com Snappy).
  • Processamento Distribuído: Apache Spark 3.5 / PySpark (joins distribuídos, quarentena com anti-joins e deduplicação idempotente por janelas).
  • Armazenamento & Formato de Tabela: Apache Iceberg + MinIO (tabelas ACID com isolamento de snapshots, particionamento oculto e evolução de schema segura).
  • Modelagem Semântica & Contratos: dbt Core + DuckDB (camadas modulares Staging/Intermediate/Marts com testes automatizados de integridade).
  • Orquestração de Workflows: Apache Airflow 2.10 (CeleryExecutor, políticas de retry automático, execução em containers e circuit breakers de qualidade).
  • Infraestrutura: Docker & Docker Compose orquestrando 7 microsserviços isolados.

2. Modelagem Relacional do Domínio & Síntese de Dados

Para espelhar a dinâmica de um banco digital moderno, modelamos um ecossistema com 7 entidades inter-relacionadas com cardinalidade estrita:

                       ┌──────────────┐
                       │   CUSTOMER   │ (100.000 clientes)
                       └──────┬───────┘
                              │
                    ┌─────────┴─────────┐
                    ▼                   ▼
             ┌─────────────┐     ┌─────────────┐
             │   ACCOUNT   │     │    LOAN     │ (30.000 contratos)
             └──────┬──────┘     └──────┬──────┘
                    │                   │
          ┌─────────┴─────────┐         ▼
          ▼                   ▼   ┌──────────────┐
   ┌─────────────┐     ┌──────────┴──┐│ LOAN_PAYMENT │ (~740k parcelas)
   │    CARD     │     │ TRANSACTION │└──────────────┘
   └─────────────┘     └──────┬──────┘ (5.000.000 eventos)
  (120k cartões)              │
                              ▼
                       ┌──────────────┐
                       │   MERCHANT   │ (10.000 estabelecimentos)
                       └──────────────┘

Volumetria e Distribuições Realistas

  • Clientes (100k): Segmentados em perfis socioeconômicos (BASIC, STANDARD, PREMIUM) que ditam limites de crédito e volume transacional.
  • Contas (~150k): Contas correntes (CHECKING) e poupança (SAVINGS) com controle de status ativo/bloqueado.
  • Transações (5.000.000 de registros): Eventos multi-canal (PIX, TED, DOC, compras no débito/crédito, depósitos e saques) distribuídos ao longo de múltiplos períodos fiscais.
  • Realismo da Síntese: Em vez de dados puramente randômicos, as transações seguem uma distribuição log-normal / Pareto, simulando o comportamento real do consumidor: alta frequência de transações de baixo valor (alimentação, transporte) contrapondo baixa frequência de transações de alto valor (eletrônicos, aluguel, investimentos).

3. Camada Bronze: Ingestão em Streaming Sem Estouro de Memória

Um erro frequente em engenharia de dados é carregar datasets de milhões de linhas diretamente na memória com pd.read_csv() ou pd.to_parquet(), resultando em crashes fatais por Out-Of-Memory (OOM) em máquinas com recursos limitados.

Para garantir alta vazão com consumo estritamente controlado de RAM (menos de 300MB), a ingestão foi projetada utilizando PyArrow Chunked Streaming RecordBatches:

python
# Padrão de ingestão em streaming com PyArrow
import pyarrow as pa
import pyarrow.parquet as pq

def stream_records_to_bronze(generator, batch_size=100_000, output_path='data/bronze/transactions'):
    schema = get_transaction_pyarrow_schema()
    writer = None
    
    for batch in generator.iter_batches(batch_size):
        arrow_table = pa.Table.from_batches([batch], schema=schema)
        if writer is None:
            writer = pq.ParquetWriter(f'{output_path}/data.parquet', schema, compression='SNAPPY')
        writer.write_table(arrow_table)
        
    if writer:
        writer.close()

Otimizações Estratégicas de Armazenamento:

  • Armazenamento Colunar Parquet: Compressão Snappy resulta em uma redução de ~4.5x no tamanho do arquivo em disco em relação a CSV/JSON brutos.
  • Particionamento Temporal (year=YYYY/month=MM): Consultas analíticas que filtram períodos específicos utilizam o mecanismo de partition pruning para pular mais de 90% dos arquivos irrelevantes durante o scan do Spark.

4. Camada Silver: Limpeza Distribuída e Arquitetura de Quarentena

A camada Silver é onde o Spark transforma dados brutos e não confiáveis em datasets estruturados, validados e normalizados.

O Conceito de Quarentena (Dead Letter Queue de Dados)

Em pipelines tradicionais corporativos, registros com chaves estrangeiras inválidas ou campos inconsistentes costumam gerar dois comportamentos prejudiciais:

  1. Descartar silenciosamente (Drop): Elimina rastreabilidade, mascara falhas de sistemas de origem e quebra auditorias regulatórias.
  2. Falhar todo o pipeline (Fail): Uma única transação com payload corrompido paralisa as operações analíticas de toda a empresa.

No Banking Pipeline, criamos o padrão de Dual-Sink Quarantine Routing no Spark:

python
# Roteamento dual-sink de quarentena com PySpark
from pyspark.sql import functions as F

# 1. Validação de Integridade Referencial via Left Anti Join
df_valid_tx = df_raw_tx.join(df_accounts, 'account_id', 'inner')
df_invalid_tx = df_raw_tx.join(df_accounts, 'account_id', 'left_anti') \
                        .withColumn('rejection_reason', F.lit('FOREIGN_KEY_NOT_FOUND_ACCOUNT'))

# 2. Validação de Regras de Negócio do Domínio
df_business_valid = df_valid_tx.filter(
    (F.col('amount') > 0) &
    (F.col('currency') == 'BRL') &
    (F.col('status').isin('COMPLETED', 'PENDING', 'REVERSED'))
)

# 3. Gravação simultânea dos válidos na Silver e inconsistentes na Quarentena
df_business_valid.write.mode('overwrite').parquet('data/silver/transactions')
df_invalid_tx.write.mode('append').parquet('data/quarantine/transactions')

Principais Invariantes Validadas:

  • Integridade Relacional: Existência de conta validada para cada transação; existência de estabelecimento comercial validada para compras em cartão.
  • Regras do Domínio Bancário: Contas poupança (SAVINGS) não podem emitir cartões de crédito; cartões de crédito devem possuir limite positivo (credit_limit > 0); valores de transação devem ser estritamente positivos (amount > 0).
  • Deduplicação Idempotente: Deduplicação baseada em funções de janela ROW_NUMBER() OVER (PARTITION BY transaction_id ORDER BY ingested_at DESC) garantindo execuções idempotentes.

5. Camada Gold: Modelagem Dimensional e Visão 360°

Com dados saneados na camada Silver, o Spark calcula as visões analíticas agregadas e tabelas de fatos/dimensões prontas para consumo:

  1. customer_360: Perfil consolidado do cliente unindo saldo total de contas, quantidade de cartões ativos, volume financeiro movimentado na vida, exposição em empréstimos e score RFM (Recência, Frequência, Valor Monetário).
  2. daily_transaction_summary: Agregações diárias por canal de pagamento (PIX vs. TED vs. Cartão), volumetria financeira total, ticket médio e taxa de autorização de transações.
  3. customer_transaction_metrics: Métricas de comportamento de gastos (horários de pico de consumo, maior transação individual e categorias de comércios preferidas).
  4. merchant_performance: Análise de parceiros comerciais com faturamento bruto, taxa de estorno (chargeback) e volumetria de vendas.
  5. loan_portfolio: Saúde da carteira de crédito com índices de inadimplência (Default Rate a 30/60/90+ dias), total de capital concedido e índice de recuperação.

6. Modern Lakehouse com Apache Iceberg e MinIO Object Storage

Arquivos Parquet tradicionais gravados em pastas possuem limitações severas: não oferecem garantias transacionais ACID, sofrem com concorrência de leitura/escrita e exigem listagens lentas de diretórios para descobrir arquivos de partição.

Evoluímos a plataforma para um verdadeiro Lakehouse de Tabelas Abertas utilizando Apache Iceberg com MinIO (S3):

python
# Criação de tabela ACID no Apache Iceberg com particionamento oculto
df_gold_summary.writeTo('iceberg.banking.daily_transaction_summary') \
    .tableProperty('write.format.default', 'parquet') \
    .tableProperty('write.parquet.compression-codec', 'snappy') \
    .partitionedBy(F.days('transaction_date')) \
    .createOrReplace()
┌────────────────────────────────────────────────────────┐
│             ESTRUTURA DE METADADOS ICEBERG             │
├────────────────────────────────────────────────────────┤
│ 1. Catalog Pointer (Aponta para metadata JSON atual)   │
│    └── v3.metadata.json                                │
│        ├── Schema & Especificação de Partição          │
│        └── Manifest List (Snapshot #104928)            │
│            ├── snap-manifest-1.avro                    │
│            │   ├── data_file_a.parquet (min/max stats) │
│            │   └── data_file_b.parquet (min/max stats) │
│            └── snap-manifest-2.avro                    │
│                └── data_file_c.parquet                 │
└────────────────────────────────────────────────────────┘

Por que o Apache Iceberg é Superior aos Formatos Legados:

  • Transações ACID via Controle de Concorrência Otimista (OCC): Commits atômicos eliminam leituras parciais ou inconsistentes enquanto novos lotes estão sendo gravados.
  • Isolamento de Snapshots & Time Travel: Capacidade de auditar e reproduzir relatórios em qualquer ponto histórico (SELECT * FROM table FOR SYSTEM_TIME AS OF '2026-06-01').
  • Particionamento Oculto (Hidden Partitioning): A otimização de queries via poda de partições ocorre de forma transparente sem que analistas precisem criar colunas sintéticas nas consultas SQL.
  • Estatísticas Min/Max nos Manifestos: Os manifestos do Iceberg guardam os limites de cada coluna, permitindo pular arquivos inteiros no plano de execução sem ler o cabeçalho físico do Parquet.

7. Camada Semântica & Contratos de Dados com dbt + DuckDB

Para separar a manipulação pesada de dados brutos das regras analíticas de negócio, integramos o dbt (data build tool) com o DuckDB como motor analítico SQL in-process ultrarrápido:

Estrutura do Projeto dbt:
├── models/
│   ├── staging/        # Conversão de tipos, renomeação canônica e limpeza
│   │   ├── stg_accounts.sql
│   │   └── stg_transactions.sql
│   ├── intermediate/   # Joins de regras de negócio e enriquecimento
│   │   └── int_customer_transaction_summary.sql
│   └── marts/          # Tabelas Fato e Dimensões para BI
│       ├── fct_daily_transactions.sql
│       └── dim_customers_360.sql

Contratos de Dados & Testes Automatizados

Todos os modelos do dbt possuem testes declarados em arquivos schema.yml:

  • Unicidade e Não-Nulos: Garantia de integridade em Primary Keys de contas e transações.
  • Relacionamentos e Chaves Estrangeiras: Validação de que fct_daily_transactions.account_id existe compulsoriamente em dim_accounts.
  • Accepted Values: Validação de enums de status transacional (['COMPLETED', 'PENDING', 'REVERSED']).

8. Orquestração em Produção com Apache Airflow & Circuit Breakers

A automação do fluxo completo com observabilidade e tolerância a falhas é gerenciada por uma DAG no Apache Airflow:

[generate_data] ──> [build_bronze] ──> [build_silver] ──> [silver_qa]
                                                              │
                                                              ▼
[build_iceberg] <── [gold_qa] <── [build_gold] <──────────────┘

Destaques da Orquestração:

  • Disparo Isolado em Containers: O Celery Worker do Airflow dispara as tarefas dentro do container dedicado do Spark via Docker Socket integration (spark_exec).
  • Quality Gates como Circuit Breakers (silver_qa, gold_qa): Tarefas de validação analisam volumetrias, desvios de schema e taxas de nulos. Se anomalias forem detectadas, o pipeline é interrompido imediatamente antes de persistir dados no Iceberg.
  • Políticas de Retry Resilientes: Configurações de exponential backoff garantem recuperação automática contra instabilidades transitórias de rede e I/O.

9. Desafios de Engenharia & Lições Práticas

  1. Ajuste de Partições de Shuffle no Spark (spark.sql.shuffle.partitions): Em testes locais com 4GB de heap, as 200 partições padrão do Spark geravam overhead massivo de escalonamento em tabelas menores de dimensão. Reduzir dinamicamente para 8–16 partições reduziu o tempo total da pipeline em 64%.
  2. Configuração S3A do MinIO: A integração do Spark 3.5 com o MinIO exigiu a configuração explícita de fs.s3a.path.style.access = true, desativação de fs.s3a.fast.upload.buffer=bytebuffer e o uso de catálogos em memória para eliminar a dependência pesada de um metastore Hive dedicado.
  3. Engenharia Defensiva com Quarentena: O isolamento de registros defeituosos extinguiu quedas acidentais no pipeline e forneceu um repositório auditável de DLQ para análise forense de inconsistências.

10. Conclusão & Próximos Passos

O Banking Data Lakehouse demonstra na prática que a engenharia de dados moderna reside em desenhar arquiteturas de software resilientes, auditáveis e automatizadas.

Próximas Evoluções da Plataforma:

  • [ ] Ingestão de eventos de transações em tempo real com Apache Kafka e Spark Structured Streaming.
  • [ ] Criação de dashboards de negócio conectados via Metabase / Superset.
  • [ ] Feature Store para modelos de detecção de fraude em tempo real com XGBoost / Feast.

Confira o código-fonte completo, configurações Docker Compose, DAGs do Airflow e modelos dbt no GitHub!

Construindo um Modern Banking Data Lakehouse End-to-End: Da Ingestão com PySpark e Apache Iceberg à Orquestração com Airflow e dbt | Renan Costa