Criando a votação do BBB com serverless
Tags: serverless, aws, node, lambda
Published: 2021-05-12 03:13:31

O BBB 2021 foi um grande sucesso de audiência e também em participação nas votações para eliminação dos participantes.
A votação funciona de uma forma bastante simples. Num domingo, o Paredão era formado (formação com 3 pessoas candidatas a eliminação) e até a próxima terça-feira, a votação ficava aberta, ou seja, eram cerca de 48 horas para votação.

Durante a edição de 2021 desse programa, fui convidado para palestrar em um evento de TI e para trabalhar no conteúdo eu quis criar algo novo. E foi aí que juntei as duas coisas: BBB e Serverless. Dessa combinação surgiu o SSS - Super Serverless Sample (sim, o nome é horrível mas foi o que consegui pensar para ter 3 "S" no acrônimo).

A provocação que fiz foi: será que é possível atender aos requisitos da votação do BBB usando serverless?

Tivemos divulgação de estatísticas de votação do BBB, pelo time de TI da globo.com, onde foram alcançados números recordes de participação:

* 1,5 milhão de requisições por minuto no pico
* 1 bilhão de requisições dentro de 48 horas

Além disso, o resultado da rodada era divulgado 20 minutos após o encerramento da votação.

# Serverless

Serverless é um termo usado para aplicações e ferramentas que são gerenciadas pelo cloud provider e que tem precificação por utilização, ou seja, não se paga por tempo ocioso. Além disso, elas têm como padrão a alta disponibilidade, escalabilidade automática e segurança.

Por ter essas características, o Serverless tem bastante sinergia com os requisitos apontados na votação do BBB.

# Arquitetura

Com o desafio dos requisitos não funcionais da votação do BBB e tendo o Serverless como a solução para isso, desenhei uma arquitetura para a aplicação.
Foi utilizada a AWS como cloud provider.

Na imagem abaixo, vemos uma arquitetura bastante simples, mas com bastante poder de processamento.

![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ns7pu821t14bsg7ootxc.jpg)

* API Gateway: recebimento das requisições através de uma API Rest e enviando de forma assíncrona para processamento, proporcionando um alto *throughput*
* EventBridge: poderoso broker de mensagens que permite a execução paralela de cada mensagem de forma massiva. Alta capacidade de processamento das mensagens no mesmo ritmo que é recebido
* DynamoDB: armazenamento dos votos individuais
* SQS: envio de mensagens em lotes para processo assíncrono de contagem dos votos. O envio de lotes proporciona uma contagem mais rápida. Ao mesmo tempo, o SQS permite um processamento alto e controlado para não sobrecarregar o banco de dados
* RDS (Aurora Serverless): armazenamento da contagem dos votos, permitindo o incremento do valor e emissão de relatórios de forma mais otimizada

## Desafio da definição da arquitetura

Esse desenho de arquitetura mostrado anteriormente é a versão final, mas precisei iterar sobre ele para chegar nessas conclusões. Por isso, quero registrar também as escolhas que não atenderam as necessidades.
É importante dizer que serverless te entrega escala sem preocupação, mas isso não significa que você terá a escala necessária para resolver o seu problema. Isso porque cada serviço tem suas característica e apesar de em termos de infraestrutura você ter problema de escala, você pode ainda ter problema de vazão.

### API Gateway e SQS

Na primeira tentativa, utilizei o SQS conectado ao API Gateway para receber os votos de forma assíncrona direto do endpoint. Em termos de disponibilidade não tive nenhum problema, mas o consumo dessas mensagens não atendia a velocidade de contabilização de votos que precisava.
Por esse motivo, o uso de um Broker como o EventBridge fez mais sentido.

### DynamoDB Stream

Também na primeira versão da arquitetura, ao invés do uso de SQS como Destination da Lambda de registro de votos, eu havia utilizado a Lambda conectada no DynamoDB Stream para ouvir os eventos de cadastro. Em termos funcionais funcionou muito bem, mas assim como o Kinesis, o DynamoDB Stream trabalha com o conceito de `shard`. Sendo assim, só é possível paralelizar a mesma quantidade de `shards` configuradas no DynamoDB.
Mesmo tendo a opção de paralelizar e aumentar a capacidade, ainda ficou aquém da velocidade necessária para o problema.

# Desenvolvimento

Para realizar o desenvolvimento dessa aplicação foi utilizada a linguagem de programação NodeJS. A escolha foi por conta da simplicidade dos requisitos e também do baixo *cold start*.
Também teve o fator que eu já queria há algum tempo criar alguma função nessa linguagem. :)

O desenvolvimento todo foi realizado dentro de uma semana, trabalhando somente em dias úteis em torno de 2 horas por dia. Um total de 10 horas de desenvolvimento. Vale ressaltar que nunca desenvolvi com NodeJS, portanto nessa carga horária estão contemplados vários "perrengues" de adotar essa linguagem.

# Estatísticas

## Teste de carga

Uma parte importante da jornada foi o teste de carga. A característica do requisito era a alta escala de requisições. Por isso, era bem importante validar se a aplicação conseguiria ser um backend viável para a votação do BBB.

Para exercitar algumas requisições com objetivo maior de validar os requisitos funcionais, utilizei o JMeter.
Quando parti para testes de cargas mais massivo, utilizei o Artillery na versão serverless. Essa versão, utiliza funções Lambda para criar a carga. É serverless "contra" serverless.

Abaixo, algumas informações sobre os testes.

* Nos testes mais simples: 5k requisições por segundo
    * 10 segundos de duração
    * 50k requisições no total
* Testes de processamento: 20k requisições por segundo
    * 60 segundos de duração
    * 1,2mi requisições no total
    * Tempo de processamento do placar: 25 minutos

Foram vários testes de cargas nessas características, certamente mais de 10 mi requisições no total.

## Custos

Os valores abaixo são do intervalo todo de desenvolvimento, portanto esses custos incluem todos os testes realizados inúmeras vezes e não somente o teste final que resultou na estatística citada anteriormente. Alguns custos são contabilizados diariamente, o que poderia ter sido otimizado se usasse menos dias mas com a mesma carga horária.

* RDS: US$ 2,90 / dia
* VPC: US$ 1,44 / dia
* Lambda: US$ 1,00 total
* API Gateway: US$ 7,12 total
* DynamoDB: US$ 2,46 total
* SQS: US$ 0,21 total
* **Total: US$ 52,57**

# O que ainda poderia ser feito

O tempo utilizado para desenvolver a aplicação contemplou não só o desenvolvimento, mas também a concepção, desenho de arquitetura e todo o processo de testes. Por isso, o tempo acabou sendo pouco para criar algo mais completo.

Abaixo algumas coisas que poderiam ainda serem feitas no sistema:

* Abordagem mais robusta de dados: processar os mais rapidamente
    * Near realtime com Kinesis, por exemplo
* Pipeline para deploy automatizado
* Utilização de SecretsManager: para proteger a credencial do banco de dados RDS

# Conclusões

De maneira geral, a aplicação serverless se mostrou bastante viável para ser o backend de votação do BBB. Com pequenas melhorias é possível aumentar ainda mais o poder de processamento, especialmente para processar os votos mais rapidamente e ter o placar de forma mais antecipada.
Com uma carga horária bem pequena, foi criado uma aplicação que consegue processar 1,2 milhão de votos por minuto e entregar o placar em 25 minutos.

Essa aplicação está disponível no GitHub: https://github.com/epiresdasilva/super-serverless-sample

Conheça o podcast Sem Servidor, um podcast dedicado ao tema Serverless com conteúdos em Português: https://semservidor.com.br