A maneira fácil de computação sem servidor

A própria computação sem servidor (literalmente "sem servidor") ganhou grande popularidade em 2014 após o anúncio do AWS Lambda - uma das primeiras plataformas sem servidor. Desde então, a popularidade da abordagem sem servidor só tem crescido, mas o desenvolvimento de ferramentas, infelizmente, não está acompanhando.



Meu nome é Vladislav Tankov, em 2018-2020 estudei no programa de mestrado corporativo da JetBrains na ITMO, e desde 2017 trabalho na JetBrains .



No verão de 2018, no hackathon JetBrains, vários de meus colegas e eu tentamos fazer uma ferramenta para a linguagem Kotlin que simplifica a criação de aplicativos sem servidor analisando o código do aplicativo.



Após o hackathon, já no âmbito do trabalho científico do programa de mestrado corporativo da JetBrains, decidi continuar o desenvolvimento deste projeto. Ao longo de dois anos, a ferramenta expandiu significativamente e adquiriu funcionalidade, mas manteve seu nome - Kotless ou Kotlin Serverless Framework.



O que é sem servidor



Primeiro, vamos lembrar em que consiste a plataforma de computação sem servidor mais simples. Essa plataforma inclui três componentes principais:



  • o sistema de execução de funções sem servidor - pequenos aplicativos que processam determinados eventos;
  • um conjunto de interfaces diferentes do mundo externo (ou uma plataforma em nuvem, como AWS) para o sistema de eventos da plataforma, como uma interface HTTP;
  • o próprio sistema de eventos, que fornece a transferência de eventos de interfaces para funções e resultados de processamento de funções para interfaces.


Esses três componentes são suficientes para construir um aplicativo bastante complexo. Por exemplo, um aplicativo da Web é apenas uma interface HTTP externa (no caso da AWS, será APIGateway ) e para cada recurso processado (como / route / my ) sua própria função de manipulador sem servidor. Você pode construir um aplicativo mais complexo que usa bancos de dados e chama outras funções sem servidor, como na imagem.



Bem, você pode construir tais aplicativos, mas por quê?



Os aplicativos sem servidor têm várias vantagens atraentes que justificam a ocupação da arquitetura.



  • As funções sem servidor não funcionam quando não são necessárias. Na verdade, a função apenas processa eventos - por que deveria consumir recursos de computação se não há eventos?
  • As funções sem servidor podem tratar eventos do mesmo tipo em paralelo. Ou seja, se / route / my se tornou muito popular e mil usuários o solicitaram de uma vez, então a plataforma sem servidor pode simplesmente iniciar 1000 manipuladores, um por evento.


Juntos, esses pontos somam talvez um dos mantras mais importantes sem servidor: o aplicativo sem servidor escala de zero a infinito. Esse aplicativo não gasta dinheiro quando não está em demanda e é capaz de processar milhares de solicitações por segundo, quando necessário.



Problema



Vamos dar uma olhada em um exemplo muito simples na linguagem Kotlin:



@Get("/my/route")
fun handler() = "Hello World"


É bastante óbvio que tal aplicativo pode ser implementado usando a abordagem sem servidor. À primeira vista, é suficiente criar uma interface HTTP com algum endereço DNS e mapear / my / route para o manipulador divertido () .



Na verdade, a criação de tal aplicativo exigiria muito mais do que adicionar uma única anotação. Por exemplo, no caso da AWS:



  • Você precisará implementar um manipulador de interface para um evento específico, neste caso o RequestStreamHandler.
  • Você precisará descrever a infraestrutura da aplicação sem servidor: descrever a API HTTP da aplicação, descrever todas as funções do manipulador e associar suas funções à interface, escolhendo cuidadosamente as permissões.
  • Finalmente, você terá que coletar todas as funções do manipulador, carregar na plataforma sem servidor e implantar a infraestrutura apropriada.


Não existem poucos passos para uma aplicação tão simples, certo?



Para aqueles que são iniciados no mistério da infraestrutura como código, observarei que, é claro, parte do processo pode ser automatizado, mas essa automação em si exige o aprendizado de uma abordagem completamente nova (na verdade, descrever a infraestrutura como código) e uma nova linguagem. Esta parece ser uma tarefa desnecessariamente difícil para um desenvolvedor que deseja implantar um aplicativo rudimentar.



É possível fazer algo mais fácil? Em alguns casos (e especificamente neste) - sim!



Infraestrutura em código



Vejamos o outro lado: em vez de forçar o usuário a descrever a infraestrutura, tentaremos derivá-la do código de usuário já escrito.



Considere o mesmo exemplo novamente:



@Get("/my/route")
fun handler() = "Hello World"


Sabemos que o usuário deseja que as solicitações para / my / route sejam tratadas por esta função - então vamos sintetizar uma infraestrutura que criará uma API HTTP com / my / route , criará a função sem servidor necessária e fará toda a mágica necessária para conectá-los!



Em meu artigo na Automated Software Engineering 2019, chamei essa abordagem de Infraestrutura no Código. Na verdade, extraímos a descrição da infraestrutura do código do aplicativo que a define implicitamente, ou seja, ela está realmente contida "dentro" do código.



Deve-se notar que doravante, apenas a síntese de aplicativos HTTP API é considerada. Uma abordagem semelhante pode ser usada para processar filas e para processar eventos na plataforma de nuvem, mas isso é uma questão de desenvolvimento posterior do Kotless.



Implementação



Esperançosamente, neste ponto, a ideia está clara e restam três questões principais:



  • Como extrair informações do código?
  • Como criar uma infraestrutura com base nessas informações?
  • Como executo um aplicativo na nuvem?


Análise



O Kotlin Compiler Embeddable nos ajudará com isso.



Apesar de o exemplo ser sobre anotações, na realidade, a API HTTP da aplicação, dependendo da biblioteca utilizada, pode ser definida de formas completamente diferentes, por exemplo:



//ktor-like style
get("my-route") {
    "Hello World"
}


Para analisar código arbitrário, o Kotlin Compiler Embeddable acabou sendo mais familiar e conveniente (devido ao grande número de exemplos).



No momento, Kotless pode analisar três frameworks principais:



  • Kotless DSL - framework de anotação próprio do Kotless
  • Spring Boot é uma estrutura da Web popular, as anotações são analisadas;
  • Ktor é um framework Kotlin da Web popular, as funções de extensão são analisadas.


No processo de análise do código, o Esquema Kotless é coletado - esta é uma representação independente de plataforma do aplicativo sem servidor. É usado para sintetizar a infraestrutura e tornar o processo de análise independente de uma plataforma de nuvem específica.



Síntese



Vamos sintetizar o código do Terraform. Terraform foi selecionada como uma das ferramentas de infraestrutura como código mais populares com uma ampla gama de plataformas de nuvem com suporte, o que garante que a Kotless seja capaz de oferecer suporte a novas plataformas de nuvem e estabilidade na implantação de aplicativos.



A síntese é feita a partir do Esquema Kotless, que contém uma descrição da API HTTP do aplicativo e suas funções, bem como alguns dados adicionais (por exemplo, o nome DNS desejado).



Para a síntese em si, uma biblioteca Terraform DSL criada especialmente é usada. O código de síntese se parece com isto:



val resource = api_gateway_rest_api("tf_name") {
    name = "aws_name"
    binary_media_types = arrayOf(MimeType.PNG)
}


O DSL garante a formatação e integridade referencial entre os diferentes recursos Terraform, o que simplifica muito a expansão do conjunto de recursos sintetizados.



O código sintetizado é implantado na plataforma de nuvem com um aplicativo Terraform simples.



Corrida



Resta executar o aplicativo na plataforma sem servidor. Como já mencionado, todas as funções sem servidor são essencialmente manipuladores para alguns eventos, em nosso caso, solicitações HTTP.



É necessário conectar a estrutura com a qual o aplicativo é criado (por exemplo, Spring Boot) e a plataforma sem servidor. Para fazer isso, no momento da construção do aplicativo, Kotless adiciona um "dispatcher" especial ao código do aplicativo - um manipulador de eventos específico da plataforma que serve como um adaptador entre a estrutura usada no aplicativo e a plataforma em nuvem.



Ferramenta



A própria ferramenta, que inclui todo o pipeline descrito para a criação da infraestrutura, foi implementada como um plugin para o sistema de compilação do Gradle. Além disso, todos os módulos principais são bibliotecas separadas, o que simplifica muito o suporte de outros sistemas de construção.



Usar o plug-in é simples. Após a configuração, o usuário tem apenas uma tarefa do Gradle - implantar , que executa todas as etapas necessárias para implantar o aplicativo atual na nuvem.



A personalização do lado do usuário também é bastante direta. O próprio plugin é aplicado primeiro:



plugins {
  io("io.kotless") version "0.1.5" apply true
}


Depois disso, o usuário adiciona a estrutura de que precisa:



dependencies {
  //Kotless DSL 
  implementation("io.kotless", "lang", "0.1.5")
}


Por fim, ele configura o acesso à AWS para que Kotless possa implantar:



kotless {
  config {
    bucket = "kotless.s3.example.com"

    terraform {
      profile = "example"
      region = "us-east-1"
    }
  }
}


Lançamento local



É fácil ver que o último ponto requer que o usuário esteja familiarizado com a AWS e tenha pelo menos uma conta da AWS. Esses requisitos assustaram os usuários que queriam primeiro tentar localmente se a ferramenta fosse certa para eles.



É por isso que Kotless suporta o modo de inicialização local. Usando os recursos padrão da estrutura escolhida (Ktor, Spring Boot e Kotless DSL, é claro, podem executar aplicativos localmente), o Kotless implanta o aplicativo na máquina do usuário.



Além disso, o Kotless pode executar a emulação AWS (usada pelo LocalStack ) para que o usuário possa verificar localmente se o aplicativo está se comportando conforme o esperado.



Desenvolvimento adicional



Enquanto escrevia Kotless (e com ele minha tese de mestrado), consegui apresentá-lo no ASE 2019, KotlinConf 2019 e no podcast Talking Kotlin. Em geral, a ferramenta foi recebida favoravelmente, embora no final de 2019 não parecesse mais uma novidade (naquela época, Zappa, Claudia.js e AWS Chalice já haviam se tornado populares).



No entanto, no momento, Kotless é talvez a ferramenta mais famosa de sua classe no mundo Kotlin, e certamente pretendo desenvolvê-la.



Em um futuro próximo, pretendo estabilizar a API e a funcionalidade atuais, preparar tutoriais e projetos de demonstração para tornar o aprendizado da ferramenta mais fácil para novos usuários.



Por exemplo, planejamos preparar um conjunto de tutoriais sobre como criar bots de bate-papo usando Kotless. Parece que as tecnologias sem servidor são ótimas para esse caso de uso (e os usuários do Kotless já estão escrevendo bots do Telegram), mas a falta de ferramentas adequadas dificulta significativamente o uso generalizado.



Finalmente, um dos aspectos mais importantes de toda a arquitetura da ferramenta é sua independência de plataforma. Em um futuro não muito distante, espero oferecer suporte ao Google Cloud Platform e ao Microsoft Azure, que permitirão que os aplicativos sejam movidos de nuvem para nuvem com literalmente um único botão.



Eu gostaria de esperar que Kotless e ferramentas similares realmente ajudem a introdução de tecnologias sem servidor para as massas e mais e mais aplicativos consumam recursos apenas quando estão em execução, reduzindo ligeiramente a entropia do universo :)



All Articles