O blog da AWS

Criando uma arquitetura baseada em eventos, utilizando Amazon EventBridge e Amazon Lambda

Por Allyson Oliveira, Arquiteto de Soluções na AWS e
Por Vinicius Batista, Arquiteto de Soluções na AWS

Organizações estão buscando modernizar suas aplicações, afim de usufruir de benefícios como maior economia na operação, reduzir tempo de entrega (time to market), disponibilizar novos canais de acesso aos usuários(por exemplo, através de dispositivos móveis) e integração com serviços diversos. Este blogpost traz o desafio de transformar aplicação monolítica (tida como antiga, ou legada) para um modelo de microserviços. Quando se fala em microserviços, é fundamental primeiro exercitar os objetivos da arquitetura futura antes de citar funções, serviços de containers e API’s. Dito isso, esse texto fala sobre o modelo de arquitetura baseada em eventos.

O que é arquitetura baseada em eventos?

Em um modelo baseado em eventos, podemos fazer um paralelo com a terceira lei de Newton, onde toda ação gera uma reação. Em um modelo tradicional(também chamado de request-based), os eventos são síncronos e acoplados. Observe a figura abaixo:

Note que quando uma solicitação (request) é executada pelo Componente A, o fluxo não é finalizado enquanto não houver uma resposta do Componente B. Essa arquitetura baseada em request-response é comum e utilizada principalmente em aplicações web.

Entretanto, surgem as seguintes perguntas. O que fazer quando precisamos de uma aplicação de processamento de cargas de trabalho em lotes (batches), que não dependem do retorno imediato de um request ? Ou ainda, aplicações que precisam ser altamente escaláveis, com rápida implementação e baixo acoplamento? Para isso, podemos contar com um modelo baseado em eventos. Diferente do modelo anterior, nessa arquitetura temos um modelo majoritariamente assíncrono e com menor acoplamento entre os componentes. Observe a figura abaixo:

Note que nesta arquitetura, diferente da tradicional, há alguns pontos de destaque, em sequencia:

1 – Os requests são executados e “esquecidos” (fire-and-forget). Ou seja, o Componente A não precisa aguardar o Componente B;

2 – O processamento pode ser executado em um momento adequado (por exemplo, em determinado horário da madrugada) ou quando outras condições de processamento forem atendidas;

3 – O response pode ser tardio – o Componente A será notificado pelo Componente B quando a tarefa for finalizada – ou essa resposta pode não existir. Esse ponto é fundamentalmente diferente do modelo de pooling, onde o Componente A realizaria consultas ao Componente B para obter o status do processamento. Esse modelo, ainda que utilizado com frequência, não é o tema desse blogpost.

Uma arquitetura baseada em eventos, assíncrona, possui as seguintes vantagens sobre um modelo síncrono:

  • Com o baixo acoplamento dos componentes, os mesmos podem ser desenvolvidos e entregues em momentos distintos, mitigando riscos para a solução como um todo;
  • Flexibilidade para escalar a infraestrutura dos componentes de forma separada, priorizando onde a capacidade de processamento ( throughput ) é crítica para a execução do fluxo em tempo hábil;
  • Possibilidade de execução de múltiplas versões do mesmo componente em ambiente produtivo.

­­­ Entretanto, conforme a arquitetura fica mais complexa, com diferentes eventos que são disparados em diferentes momentos, podemos fazer uso de um barramento de eventos. Um barramento de eventos é um sistema de uso geral para o envio de mensagens, que permite minimizar a interdependência entre componentes, desenvolver aplicativos orientado a eventos e que podem adaptar-se a diferentes fontes de processamento.

Note que no modelo acima, diferente de exemplos anteriores, existe o Barramento de eventos, responsável pelo roteamento de chamadas baseados em atributos de eventos, provendo um ambiente flexível para novos componentes e necessidades. Com tal barramento, reduzimos a complexidade na gestão de eventos, utilizando o mesmo como um centralizador de eventos e ações disparadas por tais eventos.

Processamento de arquivos utilizando uma arquitetura baseada em eventos

Desafio

Um cenário comum, e que impõe desafios de escalabilidade, é o processamento de Notas Fiscais Eletrônicas (NFE) baseadas em XML. Isso porque o processamento geralmente consiste em diversas etapas – validação do documento, iteração com aplicações externas – e condições variáveis, tais como conectividade de redes, demanda variável por processamento e tratamento de erros em diversas camadas.

Arquitetura

Com base nos desafios mencionados, vamos utilizar a seguinte arquitetura para entregar uma solução altamente escalável e desacoplada. Nela, temos os seguintes componentes:

Tome uma aplicação que faz um upload de arquivo do tipo .xml para um bucket S3 dentro da AWS. Com o upload concluído, o EventBridge aciona diferentes funções Lambda, que possuem responsabilidades distintas, como: fazer o parsing no arquivo .xml, conversão para o formato json, validação de regras de negócio e, por fim, salvar o resultado em uma tabela do DynamoDB. Todo esse fluxo é gerenciado por um barramento de serviços – nesse caso, o Amazon EventBridge – que inicia a execução de diferentes funções de acordo com um conjunto de regras baseadas em atributos e estados de eventos definidos anteriormente. Esse é um exemplo de como funciona a arquitetura baseada em eventos.

Nota: nesse blogpost o próprio usuário irá gerar a carga de arquivos a serem processados, diferente de uma aplicação em produção, onde essa integração normalmente é sistêmica.

Detalhamento da arquitetura e serviços utilizados

Serviço de geração de arquivos

O serviço de geração de arquivos faz-se necessário para gerar uma carga inicial de arquivos .xml de exemplo, para serem processados. Nesse caso, publicamos um endpoint HTTP utilizando o Amazon API Gateway, onde o usuário faz a solicitação através de chamada POST, informando a quantidade de arquivos a ser gerada.

O Amazon API Gateway é um serviço gerenciado e que permite o desenvolvimento, implantação, monitoria e segurança de APIs em qualquer escala. Com o API Gateway podemos implantar APIs baseadas em REST, HTTP e Websockets, dando suporte a cargas de trabalho conteinerizadas e sem servidor, além de aplicativos da Web.

No serviço de geração de arquivos, ao receber uma requisição, o API gateway converte a mesma em um evento do Amazon EventBridge.  Como os eventos são assíncronos, o usuário rapidamente recebe uma resposta ao request, já com o código de status HTTP 200(OK), ao invés de aguardar a geração de todos os arquivos.

Importante notar que, para fins de simplicidade, não foi implementada uma rotina de autenticação/autorização de acesso ao método http POST descrito aqui. Tal objetivo pode ser alcançado através do uso em conjunto do API Gateway com o serviço Amazon Cognito, ou ainda através de autorizadores Lambda(Lambda Authorizers).

O Amazon EventBridge é um barramento de eventos sem servidor que torna mais fácil a criação de aplicações orientadas por eventos em escala usando eventos gerados com base em suas aplicações, aplicações integradas de software como serviço (SaaS) e serviços da AWS. O EventBridge fornece uma transmissão de dados em tempo real de diferentes fontes de eventos, para destinos como o AWS Lambda e outras aplicações. Você pode configurar regras de roteamento para determinar para onde enviar seus dados para criar arquiteturas de aplicações que reagem em tempo real às suas origens de dados com o consumidor e criador de eventos completamente dissociados.

Em nosso exemplo, o EventBridge recebe um evento cuja fonte(Source) é a nossa API(“NFProcessor.api”), com o tipo de evento(Detail Type)  “file_generator_request”, contendo ainda o número de arquivos a serem gerados dentro do atributo Detail. Baseado nesses atributos e através de uma regra previamente cadastrada, o EventBridge faz a chamada assíncrona da função Lambda files_generator_function, responsável por criar os arquivos baseados em um modelo e enviar os mesmos para o Amazon S3.

Indo um pouco mais a fundo, veja como é a anatomia de uma regra do EventBridge

Para acessar a regra:

  • Na lista de regras, clique sobre o nome da Regra “blogpost-evendriven-FilesGeneratorFunctionTrigger.

  • Será exibida a tela de detalhes da regra

Os pontos mais importantes de uma regra do EventBridge são:

  • O padrão do evento(event pattern), onde são definidas em quais condições essa regra deve ser ativada. No exemplo acima, sempre que o evento possuir o campo source = NFProcessor.api, e a compo detail-type = file_generator_request, essa ação será ativada. Podemos utilizar padrões customizados, como o utilizado no exemplo, ou ainda, selecionarmos padrões de acordo com o serviço AWS de origem(por exemplo, criação de recursos AWS como máquinas EC2, Buckets S3, etc). Clique aqui para visualizar a página contendo a lista mais atual.
  • O alvo(Target) do evento é onde definimos a ação que essa regra irá disparar. Além de funções lambda, também podemos definir como ações a publicação do evento em uma fila SQS, enviar dados para uma stream no Kinesis, acionar step functions e muitos outros. Para mais serviços, acesse a página com a lista atualizada.

O AWS Lambda é um serviço de computação sem servidor (serverless) orientado a eventos. Permite executar código para praticamente qualquer tipo de aplicação, sem provisionar ou gerenciar servidores. Pode ser utilizado para processar dados em escala, backends, modelos de Machine Learning, e aplicaçõe orientadas a evento, como nesse caso que estamos detalhando.

O Amazon S3 é o serviço da AWS de armazenamento de objeto, que oferece escalabilidade, disponibilidade, segurança e performance, com uma ampla variedade de categorias de armazenamento para diferentes casos de uso, podendo ser utilizado para backup e restauração, ambiente de recuperação de desastres, arquivamento, data lakes, etc.

Serviço de conversão de arquivos

O serviço de conversão de arquivos é iniciado assim que um objeto(arquivo) é gerado dentro do bucket do Amazon S3. Para gerar um evento de criação, fazemos uso do AWS CloudTrail, que é um serviço que monitora e registra a atividade da conta por toda a infraestrutura AWS, e que é nativamente integrado ao EventBridge. Com isso, sempre que um novo arquivo for carregado no bucket, um evento é automaticamente enviado para o EventBridge. Assim como em outros casos, uma regra previamente cadastrada faz o EventBridge chamar a função Lambda on_file_received_function. Tal função tem como objetivo fazer a conversão do arquivo .xml para o formato json. Abaixo podemos ver uma imagem do código dessa função.

Assim que a função é iniciada(linha 11), obtemos o nome do bucket e a chave(nome do arquivo) dos parâmetros que são enviados na chamada da função pelo EventBridge. Com isso, recuperamos o arquivo do bucket S3(linha 27) e tentamos convertê-lo para json(linha 29). Caso a conversão ocorra com sucesso(linha 45), um novo evento é criado, com o tipo file-converted, e o detalhe com o conteúdo do arquivo em formato json.

Em caso de erro na conversão(por exemplo, um arquivo faltando um atributo xml), uma exceção é lançada(linha 32), e um evento do tipo file-converted-error e o detalhe contendo o nome do arquivo e a exceção gerada. Com base nesses atributos, cadastramos uma regra que converte esse evento em uma mensagem, que é então postada em uma fila de mensagens mortas(dead letter queue) do Amazon SQS para posterior avaliação e reprocessamento, se necessário.

O Amazon Simple Queue Service (SQS) é um serviço de filas de mensagens gerenciado que permite o desacoplamento e a escalabilidade de microsserviços, sistemas distribuídos e aplicações sem servidor. Com o SQS, temos um sistema de mensageria elástico, confiável, econômico e que elimina a carga administrativa de infraestrutura. Além disso, o Amazon SQS integra-se nativamente a serviços dentro e fora da AWS através de SDK(Software Development Kit) disponível em diversas linguagens.

Serviço de validação de dados

No serviço de validação de arquivos, o EventBridge ao receber o evento file-converted, chama a função lambda on_file_converted. Essa função tem como objetivo executar validações de regras de negócios no conteúdo do arquivo. Para fins de simplicidade, a única validação efetuada nesse blog é em relação ao tamanho do campo “placa”, conforme verificamos entre as linhas 30-34, abaixo:

Caso a placa contenha mais ou menos de 7 caracteres, retornamos uma mensagem de validação contendo a string “PLACA_INVALIDA”, além de registrar no log(linha 32) a ocorrência de um erro de validação, que pode ser consultado através do Amazon CloudWatch Logs.

Caso necessário, poderíamos adotar mais validações em outros campos nessa função, ou ainda criar outras funções – a depender da complexidade das validações.

Ao finalizar a validação, é gerado um novo evento do tipo file-validated, contendo em no detalhe o nome do arquivo e eventuais mensagens de validação (por exemplo, PLACA_INVALIDA), que serão trabalhados no próximo serviço.

Serviço de persistência de dados

Após os dados serem convertidos e validados, entra em cena o serviço de persistência de dados. Esse último serviço tem como objetivo persistir informações sobre os arquivos processados em uma tabela do Amazon DynamoDB.

O Amazon DynamoDB é um banco de dados de chave-valor NoSQL, sem servidor(Serverless) e totalmente gerenciado, projetado para executar aplicações de alta performance em qualquer escala. O DynamoDB oferece segurança integrada, backups contínuos, replicação multirregional automatizada, armazenamento em cache na memória e ferramentas de exportação de dados. Além disso, através do recurso DynamoDB streams, podemos desenvolver aplicações que necessitam de resposta em tempo quase real a alterações efetuadas nos dados, recurso útil em aplicações como jogos, comércio eletrônico e processamento de dados em tempo quase real.

Assim que um evento do tipo file-validated é recebido, a função lambda on_file_validated é acionada.

A persistência é efetuada no método saveToDatabase, entre as linhas 23 e 45. Após inicializar uma conexão com o banco(linha 27), é verificado o status daquele registro, podendo o mesmo ser “OK” caso não haja mensagens de validação, ou ainda NOT_OK, caso existam mensagens de validação. Logo após, é efetuada a persistência do nome do arquivo, status, data e hora, além de eventuais mensagens de validação, encerrando assim, o processamento de um determinado arquivo.

Etapas da implantação

Pré-requisitos

Antes de iniciarmos o processo de migração, certifique-se que sua conta AWS está ativa, e que seu usuário IAM possua permissão nos seguintes serviços:

  • AWS IAM
  • Amazon API Gateway
  • Amazon EventBridge
  • Amazon Lambda
  • Amazon S3
  • Amazon SQS
  • AWS CloudTrail
  • Amazon DynamoDB

Certifique-se também que sua máquina possui:

  • AWS SAM(Serverless Application Model) CLI devidamente instalado e configurado. Você pode encontrar um passo-a-passo de instalação nesse link.
  • A ferramenta Docker instalada
  • Caso seu computador rode o Microsoft Windows, certifique-se de ter acesso ao console do Windows Powershell(não é necessária permissão administrativa para os passos que serão executados)

Instalando a solução

Para criar o ambiente , execute os seguintes passos:

  • Clone o repositório git contendo o código desse post

Utilizando o comando git, faça o download do código:
git clone git@github.com:aws-samples/event-driven-arch-eventbridge-lambda.git

  • Execute o build da aplicação usando o AWS SAM cli

No terminal do Linux/MacOS ou no Powershell(Windows), execute o comando para validar/compilar o código:

sam build

Ao finalizar a compilação, a seguinte mensagem será exibida:

  • Execute a instalação da aplicação usando o AWS SAM cli

Ainda no terminal, execute o seguinte comando

sam deploy –-guided

Alguns parâmetros serão solicitados pelo assistente:

Stack name: O nome da sua pilha. Por exemplo, blogpost-eventdriven
AWS region: Região AWS onde os recursos serão criados. Utilize a região us-east-1 para esse blog
Confirm changes before deploy: Permite verificar os recursos que serão criados antes dos mesmos serem efetivamente criados.
Allow SAM CLI IAM role creation: Permitir que a SAM cli crie recursos IAM(roles, usuários, etc).
Disable rollback: Desabilita o rollback automático se as alterações não forem bem-sucedidas.
Save arguments to configuration file: Permite salvar os parâmetros informados nesse assistente em um arquivo texto.
SAM configuration file: Nome do arquivo onde os parâmetros serão salvos
SAM configuration environment: Nome do perfil que será utilizado no arquivo de configurações.

Ao final da execução, a pilha será instalada/configurada. Essa ação leva alguns minutos e, ao final, uma tela como a abaixo será exibida. Anote os dados da seção Outputs em um arquivo local.

As saídas informadas são:

CloudTrailBucket: Nome do bucket que armazenará os eventos gerados no S3, e que servirão de entrada para o EventBridge
FileReceiverBucket: Nome do bucket que receberá os arquivos criados
FileGenerationCommandLinuxMacOS: comando para geração de arquivos de exemplo, caso você esteja utilizando Linux ou MacOS
FileGenerationCommandWindows: comando para geração de arquivos de exemplo, caso você esteja utilizando Microsoft Windows

Testando a solução

Para gerar uma massa de arquivos, execute o comando gerado na saída da pilha de acordo com o sistema operacional de sua máquina.

Linux e MacOS – execute na aplicação de terminal

Microsoft Windows – execute no PowerShell

Nota: você pode substituir o número 100 em numberOfFiles pelo número de arquivos que deseja gerar. Por padrão, além dos arquivos considerados válido, a aplicação também irá gerar um adicional de 20% de arquivos considerados inválidos(faltando um atributo xml).

No exemplo acima, serão gerados 120 arquivos, sendo 100 arquivos considerados com dados válidos, e 20 arquivos com dados inválidos.

O response será uma mensagem como a abaixo:

Logo após executarmos o comando acima, é possível visualizar os arquivos .xml criados no bucket S3 através do console do Amazon S3. Ao selecionarmos o bucket de arquivos criados(blogpost-eventdriven-filereceiverbucket), já poderemos ver os arquivos gerados.

Conforme os arquivos forem carregados, todas as etapas do processamento serão executadas para cada arquivo.

Para verificar que os arquivos inválidos foram devidamente encaminhados para a fila do Amazon SQS definida anteriormente, execute os seguintes passos:

  • Acesse a console do Amazon SQS
  • No menu ao lado esquerdo, clique em Queues
  • Será exibida uma listagem de filas. Clique sobre o nome da fila “blogpost-eventdriven-OnFileConvertedErrorQueue”

  • Na tela de informações da fila, clique no botão Send and Receive messages

  • Clique em Pool for messages. As mensagens serão listadas imediatamente. Clique sobre o ID de uma mensagem para exibi-la.

Detalhe de um arquivo incorreto:

Para verificar os arquivos que estavam corretos e foram validados, podemos utilizar a console do DynamoDB. Para isso:

  • Na console AWS, navegue até DynamoDB.
  • No menu a esquerda, clique em Items

  • Selecione a tabela blogpost-eventdriven-FileStatusTable

  • Uma lista com os registros serão exibidos.

Limpando os recursos criados

Esvaziando os buckets
Para remover todos os recursos criados, siga os passos abaixo:

  • Navegue até o console do serviço S3. Na lista de buckets, selecione o radiobox do bucket blogpost-evenddriven-filereceiver. A seguir, clique em Empty.

  • Confirme a exclusão, digitando permanently delete no campo requisitado, e a seguir clicando no botão Empty.

Nota: Repita essa operação para o bucket blogpost-eventdriven-cloudtrailbucket

Remover os recursos da stack criada

  • Navegue até o serviço CloudFormation
  • Selecione a stack blogpost-eventdriven e a seguir, clique no botão Delete Stack

  • Clique em Delete Stack e aguarde.

  • Todos os recursos criados anteriormente serão devidamente removidos.

Resolução de Problemas

Caso a exclusão da pilha termine com uma status DELETE_FAILED, verifique se os buckets encontram-se vazios seguindo os passos descritos em “Esvaziando os buckets”. Após a limpeza, execute novamente a exclusão para finalizar.

Conclusão

Graças a capacidade de integração dos serviços AWS como EventBridge, SQS, Lambda e S3, podemos desenvolver um pipeline de processamento de notas fiscais eficiente, flexível e de baixo custo, utilizando uma arquitetura baseada em eventos, que nos permite adicionar/modificar/remover fluxos conforme necessidade. E tudo isso sem se preocupar com infraestrutura.


Autores

 

Vinicius Soares Batista é Arquiteto de Soluções da AWS Brasil com foco no desenvolvimento de parceiros no setor público. Tem especial interesse por desenvolvimento de software, IoT e migrações.

 

 

 

 

Allyson Oliveira é Arquiteto de Soluções da AWS Brasil com foco em segurança de containers, devsecops e SRE, atendendo o setor público das regiões sul e sudeste.