Boas Práticas de Desenvolvimento com AWS Glue

Felipe RodriguesFelipe Rodrigues
13 min read

O AWS Glue é a solução serverless da AWS para integração, transformação (ETL) e catalogação de dados em escala. Suportando frameworks como Apache Spark, Python, Scala e Ray, o Glue evoluiu para atender desde cargas legadas até os ambientes de data lakes modernos.

Para maximizar a eficiência e o custo-benefício, é essencial adotar práticas que otimizem performance, evitem desperdícios e escolham a ferramenta certa para cada caso. Este documento detalha recomendações práticas, exemplos de uso e comparações com AWS Lambda, com foco em custo e eficiência.

graph TB
    A[📊 AWS Glue] --> B[🔄 ETL Jobs]
    A --> C[🗃️ Data Catalog]
    A --> D[🔍 Crawlers]

    B --> E[Apache Spark]
    B --> F[Python Shell]
    B --> G[Ray Framework]

    E --> H[G.1X Workers]
    E --> I[G.2X Workers] 
    E --> J[G.4X Workers]

    style A fill:#ff9900,stroke:#232f3e,stroke-width:3px,color:#fff
    style B fill:#146eb4,stroke:#232f3e,stroke-width:2px,color:#fff
    style C fill:#146eb4,stroke:#232f3e,stroke-width:2px,color:#fff
    style D fill:#146eb4,stroke:#232f3e,stroke-width:2px,color:#fff

Versões do AWS Glue: 3.0, 4.0 e 5.0

A escolha da versão do Glue impacta diretamente as funcionalidades disponíveis. Abaixo está um comparativo detalhado:

graph LR
    subgraph "🔄 Evolução das Versões AWS Glue"
        A[📦 Glue 3.0<br/>🐍 Python 3.7<br/>⚡ Spark 3.1.1] --> B[📦 Glue 4.0<br/>🐍 Python 3.10<br/>⚡ Spark 3.3.0]
        B --> C[📦 Glue 5.0<br/>🐍 Python 3.11<br/>⚡ Spark 3.5.4]
    end

    A --> A1[✅ Estável para legado<br/>❌ Recursos limitados]
    B --> B1[✅ Data Lakes<br/>✅ Hudi, Iceberg, Delta<br/>❌ Sem ML/PII transforms]
    C --> C1[✅ 32% mais rápido<br/>✅ FGAC nativo<br/>✅ SageMaker integrado<br/>✅ requirements.txt]

    style A fill:#52c41a,stroke:#389e0d,stroke-width:2px,color:#fff
    style B fill:#1890ff,stroke:#096dd9,stroke-width:2px,color:#fff
    style C fill:#722ed1,stroke:#531dab,stroke-width:2px,color:#fff
    style A1 fill:#f6ffed,stroke:#52c41a,stroke-width:1px
    style B1 fill:#e6f7ff,stroke:#1890ff,stroke-width:1px
    style C1 fill:#f9f0ff,stroke:#722ed1,stroke-width:1px
VersãoSparkPythonDestaquesLimitações
3.03.1.13.7Estável, ideal para workloads legadosMenos recursos e integrações modernas
4.03.3.03.10Suporte a frameworks de data lake (Hudi, Iceberg, Delta Lake), conectores otimizadosML/PII transforms não disponíveis
5.03.5.43.11FGAC nativo, requirements.txt, DataZone, S3 Table Bucket, Java 17, SageMakerTable-level access control via GlueContext não suportado

Destaques do Glue 5.0

  • Integração com Amazon SageMaker para ML

  • Suporte atualizado para Hudi 0.15.0, Iceberg 1.7.1, Delta Lake 3.3.0

  • Controle de acesso refinado (FGAC) com AWS Lake Formation

  • Suporte a requirements.txt para dependências Python

  • Integração com Amazon DataZone para governança

  • Suporte a S3 Table Bucket e visualizações multi-dialeto no Data Catalog

Recomendações

  • Use Glue 5.0 para novos projetos devido à performance (32% mais rápido que 4.0) e novos recursos.

  • Mantenha Glue 3.0 para sistemas legados que dependem de Python 3.7.

  • Verifique periodicamente as release notes para manter-se atualizado com as mudanças e novas funcionalidades.

Tipos de Worker

A seleção do worker correto depende do tamanho e complexidade do seu trabalho. Veja abaixo uma tabela comparativa que pode servir como referência:

graph LR
    subgraph "Worker Types"
        A[G.1X<br/>💰 Custo Eficiente] --> A1[4 vCPU<br/>16GB RAM<br/>94GB Disco]
        B[G.2X<br/>⚖️ Balanceado] --> B1[8 vCPU<br/>32GB RAM<br/>138GB Disco]
        C[G.4X<br/>🚀 Alto Desempenho] --> C1[16 vCPU<br/>64GB RAM<br/>256GB Disco]
    end

    subgraph "Use Cases"
        D[📄 Datasets Pequenos<br/>≤10GB]
        E[📊 Datasets Médios<br/>20-100GB]
        F[🗄️ Datasets Grandes<br/>>100GB]
    end

    A --> D
    B --> E
    C --> F

    style A fill:#52c41a,stroke:#389e0d,stroke-width:2px,color:#fff
    style B fill:#1890ff,stroke:#096dd9,stroke-width:2px,color:#fff
    style C fill:#722ed1,stroke:#531dab,stroke-width:2px,color:#fff
WorkerDPUvCPURAMDiscoIndicação
G.1X1416GB94GBWorkloads comuns, joins, transforms, custo eficiente
G.2X2832GB138GBDados maiores, jobs mais pesados
G.4X41664GB256GBWorkloads exigentes, grandes joins, transformações complexas

Como escolher

  • G.1X: Para datasets pequenos a médios (até 10GB) ou transformações simples.

  • G.2X: Para datasets maiores (20-100GB) ou jobs com muitos joins e agregações.

  • G.4X: Para datasets muito grandes (>100GB) ou tarefas intensivas, como ML.

Um caso de uso real

Como exemplo prático, um job de produção foi configurado para processar 2,3 milhões de registros em menos de 6 minutos. Para isso, ele utiliza instâncias G.1X com auto-scale ativado, demonstrando alta eficiência e economia. A tarefa busca dados em uma base PostgreSQL, realiza o processamento via API’s do Spark, serializa os registros em Avro e, por fim, publica-os em um tópico do Kafka.

graph LR
    A[🐘 PostgreSQL<br/>2.3M registros] --> B[⚡ AWS Glue<br/>G.1X Auto-Scale]
    B --> C[🔄 Spark Processing<br/>API Transforms]
    C --> D[📦 Avro Serialization]
    D --> E[📡 Kafka]

    B -.-> F[⏱️ <6 minutos<br/>💰 Custo otimizado]

    style A fill:#336791,stroke:#fff,stroke-width:2px,color:#fff
    style B fill:#ff9900,stroke:#232f3e,stroke-width:2px,color:#fff
    style E fill:#231f20,stroke:#fff,stroke-width:2px,color:#fff
    style F fill:#52c41a,stroke:#389e0d,stroke-width:1px,color:#fff

Dica: Monitore o Spark UI para ajustar workers com base em gargalos de CPU, memória ou I/O.

Classe de Execução Flex

Disponível para Glue 3.0+ com workers G.1X ou G.2X, essa configuração oferece uma redução de custos de aproximadamente 34% (com tarifas de $0,29/DPU-hora versus $0,44/DPU-hora) ao custo de uma maior latência na inicialização. Essa opção é ideal para jobs que não exigem respostas imediatas, como relatórios semanais, testes ou tarefas programadas fora do horário de pico, onde a flexibilidade em relação ao tempo de resposta compensa a economia operacional.

graph TB
    subgraph "Execução Standard"
        A[💸 $0.44/DPU-hora] --> A1[🚀 Inicialização Rápida]
        A1 --> A2[⚡ Baixa Latência]
    end

    subgraph "Execução Flex"
        B[💰 $0.29/DPU-hora] --> B1[⏳ Inicialização Lenta]
        B1 --> B2[🕐 Maior Latência]
    end

    subgraph "Economia"
        C[📊 34% de Redução<br/>de Custos]
    end

    B --> C

    style A fill:#ff4d4f,stroke:#cf1322,stroke-width:2px,color:#fff
    style B fill:#52c41a,stroke:#389e0d,stroke-width:2px,color:#fff
    style C fill:#1890ff,stroke:#096dd9,stroke-width:2px,color:#fff

Por exemplo, um job noturno para limpeza e consolidação de dados pode utilizar a opção Flex para reduzir despesas, uma vez que eventuais atrasos na inicialização não impactam significativamente a execução do processo.

Dimensionamento de Workers

Gerenciar os workers de forma adequada é fundamental para otimizar custos e garantir a performance desejada dos jobs. O dimensionamento incorreto pode levar a custos excessivos e ineficiências, sendo crucial alinhar a alocação de recursos à demanda real do workload para evitar desperdícios e manter a eficiência operacional.

flowchart TD
    A[🤔 Qual tipo de workload?] --> B{Volume de dados<br/>é previsível?}

    B -->|Sim| C[📊 Número Fixo de Workers]
    B -->|Não| D[🔄 Auto Scaling]

    C --> C1[✅ Previsibilidade de custos<br/>✅ Performance constante<br/>❌ Risco de superdimensionamento]

    D --> D1[✅ Otimização automática<br/>✅ Flexibilidade<br/>❌ Latência variável]

    D --> E[Configuração]
    E --> E1[--enable-auto-scaling true]
    E --> E2[--min-workers X]
    E --> E3[--max-workers Y]

    style A fill:#722ed1,stroke:#531dab,stroke-width:2px,color:#fff
    style C fill:#1890ff,stroke:#096dd9,stroke-width:2px,color:#fff
    style D fill:#52c41a,stroke:#389e0d,stroke-width:2px,color:#fff

1. Auto Scaling

Ideal para workloads com variação ou imprevisibilidade de carga, como:

  • Jobs de streaming

  • Processos batch mensais com picos de processamento

  • Processamento de logs ou dados com volume flutuante

Como Configurar

  • Ativar: --enable-auto-scaling true

  • Definir limites: --min-workers e --max-workers

  • (Opcional) Monitoramento contínuo: --enable-continuous-cloudwatch-log true

Benefícios

  • Otimização de custos: Ajusta os recursos automaticamente conforme a demanda.

  • Flexibilidade: Escala horizontalmente de acordo com o volume de dados e complexidade.

  • Eficiência: Reduz ociosidade em períodos de baixa carga.

Considerações

  • Pode haver variação na latência, já que a escalabilidade não é instantânea (tempo de provisionamento dos workers).

  • Usar workers fixos em jobs com carga variável pode resultar em ociosidade e custo extra.

Exemplos

  • Job mensal com picos de volume: configurar entre 2 e 20 workers garante economia e desempenho.

  • Job de logs com carga entre 50GB e 1TB: Auto Scaling pode reduzir em até 40% os custos mensais.

  • Jobs near real-time: monitoramento via CloudWatch permite ajuste em tempo real.

2. Número Fixo

Mais indicado para workloads estáveis e previsíveis, como:

  • Jobs diários com volume constante

  • Pipelines críticos onde a performance precisa ser constante

Como Configurar

Definir manualmente a quantidade de workers com base na análise do job e volume de dados.

Benefícios

  • Previsibilidade: Permite estimar com exatidão o custo e tempo de execução.

  • Estabilidade: Elimina variações causadas por escalabilidade dinâmica.

Considerações

Risco de superdimensionamento, com desperdício de recursos em cenários de baixa carga.

Apache Spark

Ao trabalhar com o Glue, entender como o Spark funciona é essencial para extrair o máximo da plataforma, pois ele é utilizado como mecanismo de execução distribuída. Essa combinação oferece uma plataforma robusta para processamento de dados em larga escala, com alta disponibilidade, tolerância a falhas e integração nativa com o ecossistema AWS.

graph LR
    subgraph "📱 Execução Local Python"
        A1[📄 Script Python] --> A2[💾 Dados em Memória<br/>Uma Máquina]
        A2 --> A3[⚡ Processamento Sequencial]
    end

    subgraph "🌐 Execução Distribuída PySpark"
        B1[🎯 Driver Program] --> B2[📊 RDD/DataFrame]
        B2 --> B3[🔄 Distribuição de Tasks]
        B3 --> B4[⚡ Executor 1]
        B3 --> B5[⚡ Executor 2]
        B3 --> B6[⚡ Executor N]
        B4 --> B7[💾 Dados Distribuídos<br/>Múltiplas Máquinas]
        B5 --> B7
        B6 --> B7
    end

    style A1 fill:#1890ff,stroke:#096dd9,stroke-width:2px,color:#fff
    style B1 fill:#ff9900,stroke:#232f3e,stroke-width:2px,color:#fff
    style B4 fill:#52c41a,stroke:#389e0d,stroke-width:2px,color:#fff
    style B5 fill:#52c41a,stroke:#389e0d,stroke-width:2px,color:#fff
    style B6 fill:#52c41a,stroke:#389e0d,stroke-width:2px,color:#fff

O Spark executa transformações de dados em paralelo por meio de executores, que são processos responsáveis por realizar as tasks atribuídas pelo driver, utilizando a memória distribuída para acelerar o processamento. Cada executor possui múltiplos slots, normalmente atrelados a núcleos de CPU virtuais (vCPUs), o que permite o processamento simultâneo de diversas tasks.

Esse paralelismo é possível graças ao conceito de RDD (Resilient Distributed Dataset), uma abstração fundamental do Spark que representa uma coleção de dados distribuída, imutável e tolerante a falhas. Os RDDs geralmente são manipulados de forma indireta via DataFrames e DynamicFrames, que adicionam estrutura e semântica aos dados, facilitando operações como schema inference, joins, filtros e agregações.

graph TB
    A[🤔 Escolher Ferramenta ETL] --> B{Tamanho dos dados<br/>e complexidade?}

    B -->|Pequeno e Simples<br/><1GB| C[⚡ AWS Lambda]
    B -->|Médio/Grande<br/>ETL Distribuído| D[🔧 AWS Glue Spark]
    B -->|Médio - Script Python<br/>Sem distribuição| E[🐍 Glue Python Shell]

    C --> C1[✅ Inicialização rápida<br/>✅ Custo baixo<br/>✅ Event-driven<br/>❌ Limitado a 1GB]

    D --> D1[✅ Processamento distribuído<br/>✅ Grande escala<br/>✅ Tolerância a falhas<br/>❌ Cold start alto]

    E --> E1[✅ Python puro<br/>✅ Data Catalog integrado<br/>✅ Sem overhead Spark<br/>❌ Não distribuído]

    style C fill:#52c41a,stroke:#389e0d,stroke-width:2px,color:#fff
    style D fill:#ff9900,stroke:#232f3e,stroke-width:2px,color:#fff
    style E fill:#1890ff,stroke:#096dd9,stroke-width:2px,color:#fff

Contudo, é importante lembrar que o poder do Spark vem com custo: Apesar de sua potência, o Spark carrega um tempo de inicialização elevado (cold start) e custos proporcionalmente altos para workloads pequenos. Para tarefas simples, como a manipulação de arquivos JSON, CSV ou transformações básicas, o uso do AWS Glue pode ser excessivo. Por exemplo, quando você executa um job Glue apenas com um script Python sequencial (sem usar Spark, DataFrames ou DynamicFrames), você está pagando o custo do motor distribuído (inclusive o tempo de provisionamento dos recursos Spark) mas sem usar o poder dele! Nesses casos, o uso do AWS Lambda surge como uma alternativa mais econômica e com tempo de inicialização significativamente menor. O Lambda é ideal para cargas pequenas (até 1 GB), tarefas event-driven e a execução rápida de scripts Python, especialmente quando a complexidade do processamento é baixa.

Já para situações em que a execução precisa permanecer no ambiente do AWS Glue, por exemplo, devido à integração com o AWS Data Catalog, uso de triggers ou necessidade de orquestração centralizada, o Glue Python Shell representa uma opção mais leve e eficiente, permitindo rodar scripts em Python puro sem o overhead do motor Spark.

Para extrair o máximo desempenho do Spark, considere as seguintes boas práticas:

  • Evite ações que trazem todos os dados ao driver, como collect() ou toPandas(), especialmente com grandes volumes. Essas operações podem gerar estouro de memória e travar o job.

  • Use transformações distribuídas, como map, filter, reduce, select, withColumn, que são executadas em paralelo nos executores Spark.

  • Otimize o particionamento de dados com repartition ou coalesce para evitar data skew e melhorar o desempenho de leitura e escrita.

  • Utilize formatos colunares, como Parquet, que são mais eficientes em termos de I/O e armazenamento.

  • Ajuste o número de executores e núcleos conforme a carga de trabalho esperada, lembrando que cada executor Spark pode executar uma tarefa por núcleo (vCPU).

  • Habilite ferramentas de monitoramento, como Spark UI e CloudWatch Logs, para diagnosticar problemas de paralelismo, memória e shuffle.

  • Use checkpoints em S3 para salvar o estado intermediário em jobs longos, garantindo maior resiliência em caso de falhas.

  • Implemente políticas de retry com backoff exponencial para jobs críticos, evitando reprocessamentos constantes e falhas em cascata.

  • Defina um timeout ligeiramente acima do tempo esperado, para evitar custos com jobs travados.

  • Valide jobs com dados amostrais em ambientes de desenvolvimento antes de escalar para produção.

Para aprofundar ainda mais no ajuste fino de performance, a AWS disponibiliza um guia completo com práticas recomendadas. O documento aborda desde os fundamentos da arquitetura distribuída e avaliação preguiçosa, até estratégias avançadas de particionamento, otimização de embaralhamentos (shuffles), paralelismo, tuning de cluster e análise de métricas. Esse material é altamente recomendado para quem busca elevar a eficiência de pipelines Glue em ambientes de produção.

Acesse o documento completo aqui: Práticas recomendadas para ajuste de desempenho AWS Glue para tarefas do Apache Spark (AWS Docs)

Monitoramento Proativo e Alertas com New Relic

Para garantir a estabilidade e o desempenho dos jobs, é essencial contar com um monitoramento eficaz. Com a integração do New Relic e o AWS CloudWatch Metric Streams, você consegue acompanhar métricas críticas dos jobs e configurar alertas que permitem uma resposta imediata a qualquer comportamento incomum. Essa integração facilita a personalização de dashboards e a automação dos alertas, garantindo que sua equipe seja notificada via OpsGenie ou Slack sempre que os parâmetros monitorados ultrapassarem os limites predefinidos.

graph TB
    subgraph "AWS Environment"
        A[⚡ AWS Glue Jobs] --> B[📊 CloudWatch Metrics]
        B --> C[🌊 CloudWatch Metric Streams]
    end

    subgraph "New Relic Platform"
        C --> D[📈 New Relic Dashboard]
        D --> E[🚨 Alert Policies]
        E --> F[📧 Notification Channels]
    end

    subgraph "Team Communication"
        F --> G[📱 OpsGenie]
        F --> H[💬 Slack]
    end

    subgraph "Key Metrics"
        I[📥 bytesRead<br/>Volume de dados]
        J[❌ numFailedTasks<br/>Tarefas falhadas]
        K[🔄 shuffleBytesWritten<br/>Operações shuffle]
        L[⏱️ elapsedTime<br/>Tempo execução]
    end

    D --> I
    D --> J
    D --> K
    D --> L

    style A fill:#ff9900,stroke:#232f3e,stroke-width:2px,color:#fff
    style D fill:#1ce783,stroke:#008c99,stroke-width:2px,color:#fff
    style G fill:#172b4d,stroke:#fff,stroke-width:2px,color:#fff
    style H fill:#4a154b,stroke:#fff,stroke-width:2px,color:#fff

Alguns exemplos de métricas que podem ser utilizadas para monitorar os jobs do AWS Glue incluem:

  • glue.driver.aggregate.bytesRead: Total de bytes lidos de todas as fontes de dados durante a execução dos jobs, refletindo o volume de dados processados.

  • glue.driver.aggregate.numFailedTasks: Quantidade de tarefas que falharam durante a execução, permitindo identificar rapidamente pontos de falha.

  • glue.driver.aggregate.shuffleBytesWritten: Número de bytes escritos durante operações de shuffle, o que pode indicar problemas relacionados a particionamento dos dados.

  • glue.driver.aggregate.elapsedTime: Tempo total de execução do job (em milissegundos, excluindo o tempo de inicialização), importante para acionar alertas quando o tempo de processamento ultrapassar os limites estabelecidos.

flowchart LR
    subgraph "🔄 Ciclo de Monitoramento"
        A[⚡ Job AWS Glue<br/>Executando] --> B[📊 Métricas<br/>CloudWatch]
        B --> C[🌊 Metric Streams<br/>Tempo Real]
        C --> D[📈 New Relic<br/>Dashboard]

        D --> E{🚨 Threshold<br/>Ultrapassado?}
        E -->|Não| F[✅ Monitoramento<br/>Contínuo]
        E -->|Sim| G[📢 Alerta<br/>Disparado]

        G --> H[📱 Notificação]
        H --> I[👥 Equipe<br/>Acionada]
        I --> J[🔧 Ação<br/>Corretiva]

        F --> A
        J --> K[📝 Análise<br/>Pós-Incidente]
        K --> L[⚙️ Ajuste<br/>Thresholds]
        L --> A
    end

    style A fill:#ff9900,stroke:#232f3e,stroke-width:2px,color:#fff
    style D fill:#1ce783,stroke:#008c99,stroke-width:2px,color:#fff
    style E fill:#722ed1,stroke:#531dab,stroke-width:2px,color:#fff
    style G fill:#ff4d4f,stroke:#cf1322,stroke-width:2px,color:#fff
    style H fill:#52c41a,stroke:#389e0d,stroke-width:2px,color:#fff

Esses são alguns dos benefícios e funcionalidades da integração:

  • Análise de Tendências: Monitore o histórico de execução dos jobs para ajustar proativamente os thresholds. A análise dos dados históricos possibilita a identificação antecipada de problemas e a otimização contínua dos processos, melhorando a performance geral antes que os problemas se agravem.

  • Dashboards Personalizados: Crie dashboards dedicados para visualizar, em tempo real, as métricas dos seus jobs. Isso facilita a identificação de padrões, tendências e eventuais desvios que possam impactar a performance dos processos.

  • Alertas Compostos: Combine múltiplas métricas, como erros, volume de dados e tempo de execução, em um único alerta. Essa abordagem reduz o ruído e direciona a atenção da equipe para eventos críticos, garantindo uma resposta mais rápida e eficaz.

  • Integração com OpsGenie e Slack: Configure a entrega de alertas por meio do OpsGenie ou diretamente em canais do Slack. Essa integração agiliza a comunicação entre as equipes, permitindo coordenação imediata e organizada diante de incidentes.

TL;DR

  • Escolha a versão correta do Glue: Glue 5.0 oferece os recursos mais recentes, mas versões anteriores podem ser adequadas para workloads legados.

  • Selecione o worker apropriado: Use G.1X para jobs leves e G.4X para tarefas pesadas, ajustando conforme o tamanho e complexidade dos dados.

  • Considere a classe Flex: Para jobs não críticos, a execução Flex reduz custos em cerca de 34%.

  • Use auto scaling para workloads variáveis: Ajusta recursos dinamicamente, economizando em picos e vales de processamento.

  • Monitore e otimize: Ative Spark UI e CloudWatch para identificar gargalos e reduzir custos.

  • Glue vs. Lambda: Prefira Glue para ETL distribuído e Lambda para tarefas simples e rápidas.

0
Subscribe to my newsletter

Read articles from Felipe Rodrigues directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Felipe Rodrigues
Felipe Rodrigues