Spark

Junior

Por que meu job do Spark ficou mais lento do nada, sem mudanças no código?

Nove em cada dez vezes não é o código. É o dado, o cluster ou uma configuração que silenciosamente parou de bater com um dos dois.

Ler em:
Os dados cresceram Join desequilibrado Cluster diferente do testado
Ordenado aproximadamente por quão comum é cada causa real — não medido em um dataset real.

Você não mexeu no job. O DAG é idêntico. O último deploy foi há três semanas. Mesmo assim, a execução de ontem à noite levou 40 minutos em vez de 12. Este é um dos tickets mais comuns em data engineering, e quase sempre se resume a uma de três causas.

1. Os dados cresceram, mas a configuração não

O número de shuffle partitions, a memória do executor e o limite de broadcast join geralmente são definidos uma única vez, durante o desenvolvimento inicial, com base no volume de dados daquele momento. Seis meses depois, a mesma tabela tem 4x mais linhas e o mesmo spark.sql.shuffle.partitions=200, que agora produz partições grandes demais para caber confortavelmente na memória, forçando spill em disco em cada etapa de shuffle. Nada mudou no código; o que mudou foi a suposição que a configuração carregava.

Como verificar: compare a contagem de linhas de entrada e os bytes de leitura/escrita de shuffle entre uma execução lenta recente e uma antiga rápida, na aba Stages da Spark UI. Um salto grande aí, com uma desaceleração proporcional, aponta direto para essa causa.

2. Um join que antes era equilibrado deixou de ser

Data skew não se anuncia — simplesmente significa que um punhado de partições acaba fazendo 10-100x mais trabalho que as demais, então o tempo total é ditado pela task mais lenta, não pela média. Uma distribuição de chaves que era razoavelmente uniforme no lançamento pode derivar conforme os padrões de uso mudam (um cliente, uma região, um tipo de evento passa a dominar o volume).

Como verificar: na visão detalhada do stage na Spark UI, ordene as tasks por duração. Um stage em que a mediana é 4 segundos e o máximo é 6 minutos está enviesado, sem sombra de dúvida.

3. O cluster não é mais o cluster em que você testou

Clusters com autoscaling, pools de instâncias spot e clusters compartilhados multi-tenant podem silenciosamente entregar ao seu job menos executors, ou mais lentos, especialmente sob disputa com outros jobs. Isso aparece como tempo total mais lento com tempo de CPU por task idêntico — o job faz a mesma quantidade de trabalho, só espera mais pelos recursos para fazê-lo.

Como verificar: compare o número de executors realmente alocados (não solicitados) entre execuções, e olhe o atraso do scheduler de tasks, não só a duração das tasks.

A forma mais rápida de distinguir essas causas: você precisa de duas coisas lado a lado — sua configuração atual e métricas reais da execução que realmente aconteceu. Essa é a premissa inteira do motor de regras do opti-pipe: ele lê o tempo real das tasks, o volume de shuffle e o uso de memória do seu event log e compara com suas shuffle partitions, memória do executor e número de instâncias configurados — em vez de você olhar a Spark UI e tentar adivinhar qual das três causas é a sua.

Veja como isso fica no seu próprio pipeline.

Envie um event log real do Spark, um run_results.json do dbt, ou uma exportação de métricas do Flink, e receba recomendações concretas para aprovar — não mais uma regra de bolso.