A arquitetura sem servidor oferece desafios e oportunidades de otimização e eficiência.
Neste post, você aprenderá com minha experiência sobre os desafios de desenvolver um serviço serverless orientado a alto desempenho. Compartilharei meus insights sobre explorar estratégias multilíngues e verei como abraçar a diversidade em linguagens de programação pode levar a soluções mais robustas.
Índice
Linguagem única AWS Lambda de escolha
Eu sempre construí serverless com Python. Usei o código Python AWS CDK para criar recursos serverless e escrevi minhas funções Lambda com Python.
Python é um ajuste natural para desenvolvimento serverless. Ele ostenta uma vasta gama de bibliotecas, incluindo Powertools para AWS e bibliotecas robustas para engenheiros de dados. Sua versatilidade e excelente experiência de desenvolvedor o tornam uma escolha principal para projetos serverless, oferecendo uma experiência de desenvolvimento perfeita e agradável.
Mas ei, não acredite apenas na minha palavra. Vamos mergulhar em alguns dados que dão suporte à superioridade do Python no desenvolvimento serverless.
O relatório 'State of Serverless' da DataDog , um recurso confiável do setor, revelou que Python e NodeJS são os campeões indiscutíveis no reino do desenvolvimento sem servidor.
Nos últimos cinco anos, Python atendeu bem às minhas necessidades e é nisso que minha organização tem se concentrado principalmente. Para cada novo serviço que construímos, Python é a linguagem de escolha.
Novo serviço, novos requisitos
Ultimamente, tenho trabalhado em um novo serviço que tem dois tipos de APIs:
CRUD básico.
Tempo de execução curto (milissegundos de um dígito, se possível), cálculo algorítmico de desempenho máximo.
Usarei o API Gateway para acionar funções do Lambda.
Quanto à linguagem de programação de função Lambda, Python é uma combinação perfeita para o primeiro requisito CRUD. A API não tem requisitos especiais e não precisa terminar em um milissegundo de um único dígito.
Entretanto, quanto ao segundo, alguns testes são necessários, pois o Python ainda não é conhecido por atingir tal desempenho.
Meus experimentos iniciais mostraram que os números do Python não eram bons logo de cara, e as partidas a frio que eu estava experimentando eram uma dor. Há maneiras de mitigar partidas a frio até certo ponto — confira meu post sobre isso aqui — mas o desempenho do Lambda quente ainda não era bom o suficiente.
Eu não queria desistir ainda. Existem maneiras de extrair um pouco de desempenho do Python.
Aproveite cada grama de desempenho
Eu vi várias abordagens. Os desenvolvedores aumentariam drasticamente a memória de função do Lambda, obtendo assim uma CPU melhorada e reduzindo o tempo de execução total, mas a um custo adicional.
Outra abordagem que vi é utilizar simultaneidade na forma de funções Lambda multithread para casos que podem se beneficiar, como múltiplas chamadas simultâneas de API ou SDK. Embora funcione, traz complexidade extra. Além disso, requisitos futuros podem aumentar o tempo de execução e levar o design atual ao seu limite. Precisamos considerar requisitos futuros e ter a opção de estender o serviço.
Todas essas soluções são válidas, mas elas só podem levar você até certo ponto. O Python tem limites e limites de desempenho e, para ser honesto, as soluções parecem, aos meus olhos, ser um patch em vez de um método de solução de problemas. As soluções podem funcionar bem por enquanto, mas quebrarão com requisitos adicionados no futuro.
Quanto mais eu pensava sobre esse assunto, menos confiante eu ficava no meu projeto original.
Lembrei-me de uma frase que ouvi na palestra de Werner no AWS re:invent 2023:
Não sei quantas vezes ouvi essa frase de desenvolvedores na minha vida.
Só porque sempre fazemos algo da mesma maneira não significa que devemos continuar fazendo.
Percebi que estava fazendo a mesma coisa. Queria usar Python novamente porque é assim que sempre fizemos. No entanto, Python não se encaixa nessa API do ponto de vista de desempenho, e cada otimização é um patch que provavelmente falhará quando novos requisitos forem introduzidos.
Algo precisava mudar.
Diversidade multilíngue sem servidor
Se você se lembra do meu post sobre cold starts e otimizações, eu cito o tweet do AJ sobre cold starts e linguagens. Cold starts são previsões sobre desempenho.
Agora, não vou usar C++ novamente; deixei esse capítulo anos atrás, e isso não vai acontecer. C++ não é seguro para memória e fácil de usar e exigiria um tempo maior para os desenvolvedores se adaptarem. Rust é o novato no pedaço, mas ouvi opiniões mistas sobre sua experiência de desenvolvedor, e ainda não há muitas bibliotecas em torno dele. LLRT é muito novo para o meu gosto, mas Go chamou minha atenção.
Go tem um ótimo equilíbrio entre experiência do desenvolvedor e desempenho; todos os desenvolvedores que conheço me disseram coisas ótimas sobre ele. É mais simples que Rust, fornece bom desempenho, tem coleta de lixo e minha empresa tem alguma experiência com ele. Você pode ler mais sobre Go e como ele se compara a Rust e Python aqui e aqui .
Então é isso. Precisaremos verificar o desempenho nós mesmos, mas agora temos uma nova e promissora direção. No entanto, precisamos abordar duas questões de notícias:
API CRUD - Mudamos para Go ou escrevemos em Python?
API de tempo de execução curto - Escrevemos seu código CDK em GO ou Python?
Dilema da Linguagem da Função Lambda
A resposta para a primeira pergunta é simples. Usaremos Python. Não há necessidade de complicar demais as coisas. Também posso continuar usando Python CDK no projeto CRUD.
Dividiremos o serviço em dois repositórios de código, fornecendo dois microsserviços menores:
API CRUD - Python CDK e função Python Lambda.
API de tempo de execução curto - Função Go Lambda.
Ter as funções Python Lambda e Go no mesmo projeto é possível. No entanto, isso traz complexidade desnecessária. Por exemplo, sua pasta de testes conterá arquivos Python e Go, fazendo uma bagunça. Como essas funções implementam domínios diferentes e têm requisitos diferentes, isso fortalece o caso de dividir o serviço em dois microsserviços em dois repositórios: um com funções Lambda escritas em Python e o outro em GO.
Agora, precisamos abordar a segunda questão: qual linguagem CDK devemos escolher para o segundo microsserviço, aquele que contém funções Go.
Linguagem CDK IaC - Única ou múltipla?
Embora usar uma única linguagem para scripts IaC e manipuladores Lambda possa agilizar o desenvolvimento e a manutenção, adotar uma abordagem multilíngue pode gerar vantagens distintas.
Discuto as vantagens e a sinergia entre o código CDK e o código Lambda na minha sessão AWS re:invent de 2023 abaixo:
Sempre usei a mesma linguagem para a definição do CDK do IaC e o código da função Lambda. Gerenciar dependências é mais fácil, mas você pode considerá-las como dois projetos separados no mesmo repositório — um para o IaC e o outro para o código do domínio de negócios, a função Lambda.
Por isso, pode ser aceitável usar dois idiomas diferentes .
Para começar, por que eu deveria escrever CDK em Go? CDK pode ser escrito em Go, mas digamos que mudemos para Rust amanhã. Devemos mudar nosso código CDK para Rust - CDK não tem variante Rust, então isso significa que nunca poderemos usar Rust? Não, claro que não; não faz sentido algum. Além disso, não faz sentido reescrever a construção CDK de Python para Go só porque o domínio de negócios está em Go. Podemos importar construções Python existentes para o projeto e reutilizar o código para acelerar nosso desenvolvimento. Faz pouco sentido perder essas vantagens porque nossa função Lambda é escrita em Go.
Uma das principais vantagens do CDK Python é a familiaridade que nossos desenvolvedores têm com ele. Ao aderir ao Python, eles podem escrever rapidamente a parte do CDK, permitindo que se concentrem no domínio de negócios em Go e mitiguem o risco geral e a complexidade do serviço.
No final das contas, o domínio do negócio tem precedência sobre o código do CDK. Independentemente da linguagem que escolhermos, o CDK criará os recursos necessários. O desempenho das funções go impacta diretamente o negócio, então é crucial direcionar nossos esforços para onde eles mais importam.
Para resumir, o Python CDK é bom e pode ser usado para criar funções Go Lambda ou qualquer outra linguagem.
A documentação da AWS é surpreendentemente excelente, e criei um pipeline de CI/CD com CDK que compila um executável Go e implanta um API Gateway em uma hora, acionando uma função Go Lambda.
Diversidade em Serverless e Containers
Podemos ir ainda mais longe. Ouso dizer, como um herói sem servidor , que as funções Lambda podem não ser o melhor caso de uso para meu novo serviço. Assumindo grande escala e tráfego constante, as funções Lambda podem custar muito mais do que suas contrapartes de contêiner. No entanto, você precisa considerar o custo de manutenibilidade, aplicação de patches, segurança e tempo do desenvolvedor e combinar todos os fatores para decidir. Nesta postagem , discuto FinOps e a importância de considerar o custo no estágio de design.
Meu serviço usará inicialmente funções Lambda para começar e fornecer valor aos nossos clientes de API o mais rápido possível. No entanto, daqui para frente, seria sensato considerar contêineres com escala e custo futuros em mente.
Minha opinião final
Não tenha medo de tentar algo novo.
Como arquiteto, você deve adequar a solução aos requisitos e considerar mudanças futuras. Não escolha uma solução porque é assim que você sempre fez. Quando perceber que ela não atende aos seus requisitos, você deve ser corajoso o suficiente para fazer uma mudança.
A diversidade em linguagens sem servidor é um excelente exemplo dessa abordagem.
Você deve escolher Go ou Rust para casos de uso orientados ao desempenho e Python para os outros (ou Node.JS se você tiver experiência).
Por fim, misturar um Python CDK com um Go lambda no mesmo projeto é aceitável se você usar o AWS CDK. Sua linguagem CDK NÃO precisa corresponder à linguagem Lambda.
Comments