Abraçando a mudança em uma startup acelerada
Pelo menos uma vez por ano, velejo com a minha família. Nada muito sofisticado: um veleiro que a gente mesmo consegue tocar, para curtir a natureza e um bom tempo em família. Curiosamente, um dos elementos-chave dessas viagens é o vento — direção e intensidade — e o detalhe é que ele muda o tempo todo!
Assim como o vento, a vida está em constante mudança. E isso vale ainda mais em uma startup acelerada. O que funciona bem hoje pode não ser o ideal amanhã. Saber reconhecer a hora de mudar de rumo, otimizar ou até refazer um sistema por completo é fundamental. Como engenheiros, temos a tendência de nos apaixonar pelas decisões que tomamos e pelos sistemas que construímos. Mas se apegar a escolhas do passado pode virar um problema.
Na Attribute™, a gente se apaixona por pessoas, e não pelo que constrói. Então, quando chegou a hora de revisitar nossa stack de processamento de dados, não foi surpresa. Lá no começo, tomamos as melhores decisões de infraestrutura dentro das nossas restrições. Mas, conforme escalamos, essas mesmas decisões viraram limitações e nos forçaram a repensar e nos adaptar.
A decisão inicial: Serverless Dataproc para o Spark
Quando começamos a montar nossa infraestrutura de processamento de dados, escolhemos o Serverless Dataproc para rodar nossos jobs Spark. Na época, essa decisão fazia todo o sentido. Como um time enxuto, com pouca banda de engenharia, não tínhamos o luxo de construir e manter um cluster Spark autogerenciado. O Serverless Dataproc nos permitiu focar em entregar valor sem nos preocupar com o overhead operacional. A gente escrevia os jobs Spark, fazia o deploy tranquilamente e deixava o Google Cloud cuidar do resto.
As dores do crescimento: custo e falta de controle
À medida que o negócio crescia, cresciam também as necessidades de processamento de dados. Mais dados significavam mais jobs, maior frequência de execução e, com o tempo, custos disparando.
Também começamos a esbarrar em gargalos operacionais. Por ser uma caixa-preta, o Dataproc nos dava pouquíssima visibilidade sobre os detalhes de execução dos jobs, o que dificultava otimizar performance e depurar falhas com eficiência.
A essa altura, as desvantagens já superavam os benefícios. Ficou claro que precisávamos retomar o controle.
O "porquê" por trás da migração
Tenho uma regra simples ao encarar qualquer projeto de engenharia: ele precisa começar com um "porquê" forte. Se não existe um motivo convincente para fazer algo, não vale gastar nosso recurso mais valioso, o tempo, com isso. (Dica: testar uma tecnologia nova só porque é "legal" nunca é motivo suficiente.)
Na nossa migração do Dataproc, o "porquê" estava claro:
- Eficiência de custo: o Serverless Dataproc tinha ficado caro demais.
- Transparência operacional: precisávamos de mais controle e visibilidade sobre nossos jobs Spark.
- Escalabilidade e flexibilidade: queríamos poder ajustar finamente nossa infraestrutura conforme as necessidades evoluíssem.
Com esses motivos como combustível, embarcamos em um projeto focado em migrar nossos workloads Spark do Dataproc para uma solução autogerenciada baseada em Kubernetes.
A migração: levando o Spark para o Kubernetes
Decidimos implantar nossos jobs Spark usando Spark-on-Kubernetes, que permite rodar aplicações Spark como workloads nativos do Kubernetes. Segue um resumo em alto nível da abordagem:
Configuração da infraestrutura:
- Provisionamos um cluster Kubernetes no Google Kubernetes Engine (GKE) com autoscaling habilitado para dar conta de workloads variáveis.
- Configuramos um namespace dedicado para os jobs Spark, garantindo uma separação clara em relação aos demais serviços.
- Usamos instâncias Spot para reduzir ainda mais os custos.
Execução de jobs com o SparkApplication CRD:
Usamos o Spark Operator para gerenciar workloads Spark como recursos nativos do Kubernetes.
Isso nos permitiu definir os jobs Spark de forma declarativa, com Custom Resources (CRs) do Kubernetes, deixando-os mais fáceis de gerenciar e escalar.
Observabilidade e monitoramento:
Integramos o Victoria Metrics e o Grafana para monitorar a execução dos jobs em tempo real.
O resultado: mais controle, custos menores e melhor monitoramento
A migração trouxe melhorias significativas:
- Redução de custos: ao eliminar o overhead do Dataproc gerenciado e otimizar o uso de recursos, cortamos os custos de processamento Spark em mais de 70%.
- Mais transparência: ganhamos uma visibilidade muito maior sobre a execução dos jobs, o que se traduziu em melhor debug e otimização. Isso também elevou o senso de ownership do time de engenharia — sem a caixa-preta, somos obrigados a fazer um trabalho de engenharia melhor.
- Escalabilidade: rodar em Kubernetes nos permite escalar workloads dinamicamente, sem limitações impostas por um fornecedor. A melhoria na performance do Spark, com tempos de execução menores, também aumentou nossa eficiência no desenvolvimento de features, gerando mais valor no produto.
Considerações finais
Engenharia é resolver problemas da forma mais eficiente possível. Nossa decisão de usar o Serverless Dataproc foi acertada no começo, e a decisão de migrar para o Kubernetes foi acertada quando escalamos.
A grande lição? Mantenha-se adaptável. Não se apaixone pelas suas decisões — abrace a mudança, porque ela vai chegar, gostando você ou não.
Fico imaginando quando vamos começar a sentir o atrito com a nossa atual infraestrutura de aplicações Spark…