Comparando open source e serviços de nuvem na construção de uma infraestrutura de gestão de webhooks
Até aqui, na nossa série sobre soluções de gestão de webhooks, já vimos como arquitetar um blueprint de design. Também mergulhamos em cada componente que forma a solução de webhooks proposta e discutimos como a nossa infraestrutura de webhooks pode ser monitorada para melhorar a performance, detectar problemas e evitar falhas.
Chegamos agora à parte divertida: construir! Neste artigo, vamos usar o RabbitMQ para implementar o design proposto no caminho open source e a AWS no caminho de serviços de nuvem. Para cada solução, vamos ver os prós e contras da abordagem.
Também vou compartilhar a minha própria experiência construindo uma versão enxuta. Deixei de fora o rate limiter e o sistema de retry para manter o design leve; por mais que eles contribuam para a tolerância a falhas e a confiabilidade da infraestrutura, o sistema ainda opera sem eles. Além disso, o rate limiter e o sistema de retry são componentes customizados, com formas variadas de operação e implementação. Um rate limiter, por exemplo, pode ser implementado com diferentes tipos de algoritmo (como token bucket, leaking bucket e sliding window counter), cada um com os seus méritos e limitações.
No fim, você terá informações úteis para decidir como quer implementar a arquitetura no seu caso de uso específico.
O que considerar ao decidir entre open source e serviços de nuvem
Solução proposta
- Os produtores de webhooks disparam requisições e as enviam a um API gateway.
- O API gateway coloca as mensagens de webhook em uma fila (ou filas) no message broker e adiciona um
Trace IDpara fins de rastreamento. - O message broker bufferiza as mensagens de webhook para processá-las de forma assíncrona e as roteia para um pool de consumidores.
- Um rate limiter fica depois do message broker e empurra as mensagens aos consumidores em um ritmo que eles conseguem suportar.
- Quando o processamento falha, dead letter queues coletam as mensagens com falha para serem reprocessadas por um sistema de retry.
- Métricas e logs são coletados em todos os componentes do sistema.
- Métricas e logs são usados para configurar alertas nos casos em que os administradores precisam agir.

Fatores a ter em mente ao construir
| Fator | Definição |
|---|---|
| Facilidade de implementação | O sistema deve exigir o mínimo possível de esforço e tempo do seu time de desenvolvimento. |
| Escalabilidade | A capacidade de o sistema crescer diante da pressão de um volume maior de webhooks, sem degradar a performance. |
| Opções de configuração | A capacidade de ajustar as configurações do sistema para controlar o fluxo de webhooks e melhorar a confiabilidade e a performance. |
| Conhecimento técnico exigido | A curva de aprendizado não deve ser íngreme demais e a documentação deve estar disponível para todos. O sistema também não deve depender de silos de conhecimento. |
| Custo ($$) | O sistema deve ser projetado para ser econômico em desenvolvimento, manutenção e escala. |
| Confiabilidade/Performance | O sistema deve ser tolerante a falhas e ter alto throughput para webhooks. |
| Flexibilidade de escolha | Os componentes do sistema devem ser facilmente substituíveis por opções melhores ou preferidas. |
| Extensibilidade | Deve ser fácil adicionar novos recursos ao sistema sem quebrar os existentes. |
| Conjunto de recursos | O sistema deve ter os recursos essenciais para dar conta do recado, mas também a capacidade de acomodar novos recursos que melhorem performance e usabilidade. |
Construindo a solução com a tecnologia open source RabbitMQ
A minha primeira tentativa de construir a arquitetura foi com tecnologias open source. O design é formado por diferentes componentes, então precisei tomar a decisão importante de escolher a tecnologia open source para cada um. Depois de pensar bastante, principalmente com base na minha experiência com as tecnologias e na facilidade de uso, cheguei ao seguinte:
| Componente/Serviço | Tecnologia |
|---|---|
| API gateway | Aplicação servidor em Node.js |
| Fila de mensagens | RabbitMQ |
| Consumidores | Workers em Node.js |
| Coletor de métricas | StatsD e Graphite |
| Visualização de métricas | Grafana |
Com as tecnologias dos componentes escolhidas, a decisão seguinte foi sobre a ferramenta de orquestração da infraestrutura. Eu poderia iniciar e parar os serviços manualmente ou com scripts bash elaborados, mas usar uma ferramenta de orquestração deixa a implementação bem mais fácil.
A propósito, caso você ainda não tenha adivinhado, todos os meus serviços rodam em contêineres Docker. Isso facilita subir e derrubar componentes.
O Docker Compose se destacou como a melhor opção, já que eu estava construindo esta demonstração no meu ambiente local de desenvolvimento. Para produção, no entanto, o docker-compose não serve. Uma ferramenta de orquestração mais robusta, como Kubernetes ou Docker Swarm, é mais apropriada para ambientes produtivos.
Depois de várias horas lidando com problemas do docker, dos componentes da arquitetura e do meu próprio código, consegui implementar o blueprint do design arquitetural da solução de webhooks.
Eu poderia falar sem parar sobre como construí isto e consertei aquilo, mas acredito que o meu arquivo docker-compose.yaml (mostrado abaixo) conta a história de forma mais eloquente:
version: "3.9"
services:
api-gateway:
build: gateway/.
ports:
- "1337:1337"
depends_on:
- message-queue
- metrics-collector
restart: always
message-queue:
image: "rabbitmq:3.9-management"
ports:
- "5672:5672"
- "15672:15672"
- "15692:15692"
worker:
build: consumer/.
deploy:
mode: replicated
replicas: 3
depends_on:
- message-queue
metrics-collector:
image: "graphiteapp/graphite-statsd:1.1.6-1"
ports:
- "8080:80"
- "8125:8125/udp"
graphana:
image: "grafana/grafana:6.5.2"
ports:
- "8000:3000"
Se você não fala docker-compose, provavelmente não vai entender o que acontece nesse arquivo. Então vamos percorrê-lo serviço por serviço.
São 5 serviços em execução nesse arquivo, cada um descrito abaixo:
api-gateway: este é o serviço de API gateway rodando em um contêiner Docker construído a partir de umDockerfilelocal na raiz da pasta da aplicação Node.js. Ele expõe a porta1337e usa a opçãodepends_ondodocker-composepara garantir que não inicie antes que a fila de mensagens e o serviço de coleta de métricas estejam no ar. Isso porque o API gateway precisa se conectar a esses serviços para funcionar. A opçãorestarttambém é usada para garantir que o serviço volte a subir em caso de desligamento.message-queue: este serviço usa a imagem Dockerrabbitmq:3.9-managementpara subir uma instância do RabbitMQ já com a interface web de gerenciamento. A porta5672é exposta para que outros serviços se conectem à instância do RabbitMQ, enquanto a porta15672é exposta para acessar a interface de gerenciamento pelo navegador.worker: os serviços de worker são os consumidores das requisições de webhook. Eles se conectam automaticamente à fila e, dependendo do método de consumo, fazem polling das mensagens ou recebem mensagens empurradas pela instância do RabbitMQ. Usei as opçõesmodeereplicaspara implantar 3 instâncias do worker e distribuir a carga de webhooks. Esses consumidores também dependem de a fila de mensagens estar rodando antes de iniciarem.metrics-collector: este é o serviço responsável por coletar métricas dos vários componentes da infraestrutura. Usando a imagem Dockergraphiteapp/graphite-statsd:1.1.6-1, sobe-se uma instância do Graphite e do StatsD. A porta8080é mapeada para a porta80do Graphite e a portaudp8125do StatsD é encaminhada para a coleta de métricas. Como o RabbitMQ já vem com a sua solução de gerenciamento, que inclui um conjunto de recursos de monitoramento e visualização, estou coletando métricas apenas do API gateway.graphana: o Grafana é a ferramenta de visualização de métricas da infraestrutura. As métricas coletadas pelo StatsD no Graphite são consultadas pelo Grafana. O resultado dessas consultas é traduzido em gráficos, tabelas e outros tipos de visualização suportados pelo Grafana. O serviço é exposto na porta8000, que mapeia para a porta3000do Grafana, acessível pelo navegador emhttp://localhost:8000.
Todo o código deste projeto pode ser encontrado neste repositório do GitHub. Sinta-se à vontade para ajustá-lo e experimentar.
Com os serviços bem orquestrados no docker-compose, executar o comando a seguir sobe os serviços na ordem em que devem iniciar:
docker-compose up
Observação: se você estiver rodando o comando acima pela primeira vez, adicione a opção
--builddepois deuppara construir os arquivos Docker locais em imagens.
A imagem abaixo mostra os serviços subindo após a execução do comando docker-compose up.

Com todos os serviços no ar, podemos fazer os dados fluírem testando a nossa infraestrutura de webhooks. Para isso, adicionei um módulo de teste de carga ao projeto. Esse módulo usa o Autocannon para simular uma requisição POST com um payload (como na maioria das requisições de webhook) e enviar requisições ao endpoint /ingest do API gateway.
O script do teste é mostrado abaixo e pode ser encontrado no arquivo loadtest/index.js na raiz do projeto da solução de webhooks.
"use strict";
const autocannon = require("autocannon");
autocannon(
{
url: "http://localhost:1337",
amount: 3000,
connections: 10,
pipelining: 1,
duration: 300,
requests: [
{
method: "POST",
path: "/ingest",
body: JSON.stringify({ name: Date.now().toString(36) }),
onResponse: (status, body, context) => {
if (status === 200) {
} // on error, you may abort the benchmark
},
},
],
},
console.log,
);
Esse teste de carga envia um total de 3000 requisições usando 10 conexões concorrentes ao longo de 300 segundos para o endpoint /ingest definido para a ingestão de webhooks no API gateway. O payload é um JSON simples com um parâmetro name definido como o horário atual.
Sinta-se à vontade para adicionar mais scripts de teste de carga a esse arquivo para simular outros cenários de volume de webhooks.
Para rodar o teste, use o comando a seguir na raiz do projeto da solução de webhooks:
node loadtest
Abaixo estão capturas dos monitores do RabbitMQ mostrando a taxa de ingestão (linha verde) e de consumo (linha laranja) das requisições de webhook:

Também montei uma visualização no Grafana para exibir as requisições bem-sucedidas (linhas verdes) e com falha (linhas vermelhas) no API gateway:

Os logs do docker-compose no terminal mostram como a fila distribui as requisições aos workers em round-robin, como abaixo:

Construindo a solução com serviços de nuvem da AWS
Foi divertido construir com tecnologias open source, se ignorarmos todas as vezes em que discuti com o meu computador e vasculhei toneladas de documentação. O grau de controle sobre como cada componente opera e o nível de customização foram alguns dos principais benefícios que percebi nessa abordagem.
Decidi, então, replicar o mesmo blueprint usando um provedor de nuvem. Precisei escolher um provedor que oferecesse serviços para cada componente do design da solução de webhooks.
Amazon Web Services (AWS), Microsoft Azure e Google Cloud Platform eram as opções óbvias e, como a AWS é anedoticamente a mais popular das três, escolhi a AWS.
O passo seguinte foi escolher o(s) serviço(s) da AWS para cada componente da arquitetura. A tabela abaixo mostra os serviços que usei para construir a solução:
| Componente | Serviço AWS |
|---|---|
| API gateway | Amazon API Gateway + AWS Lambda |
| Fila de mensagens | Amazon Simple Queue Service (SQS) |
| Consumidores | AWS Lambda |
| Monitoramento e visualização | AWS CloudWatch |
A minha estratégia para construir essa solução pode ser descrita nos seguintes passos:
- As requisições de webhook são recebidas pelo API gateway em um endpoint
POST. Esse endpoint está conectado a uma função Lambda. - A função Lambda cuida de adicionar a requisição de webhook à fila SQS.
- A fila SQS é criada e a função Lambda anterior é adicionada como Lambda trigger da fila.
- Outra função Lambda é criada para fazer polling da fila SQS em busca de mensagens de webhook. Essa função tem uma configuração de concorrência que determina o número de instâncias de consumidor que podem ler mensagens da fila simultaneamente, adicionando mais paralelismo ao processamento.
- A fila SQS é então adicionada como trigger da função Lambda consumidora, para que a função receba as novas mensagens colocadas na fila.
Assim que configurei todos esses componentes e resolvi alguns problemas de AWS Identity and Access Management (IAM), a maldição de toda tarefa de configuração na AWS, a solução estava pronta. Eu tinha um endpoint de API para onde enviar as minhas requisições de webhook e vê-las processadas conforme o esperado.
Uma grande vantagem do caminho de serviços de nuvem é que a maioria deles escala automaticamente conforme o seu volume de webhooks. Você também pode configurar como os serviços escalam para cima ou para baixo conforme a carga varia.
A AWS ainda traz o luxo adicional de ter uma aba de monitoramento para cada instância de serviço. Na aba Monitor, você vê métricas importantes selecionadas pelo time da AWS como essenciais para a operação do serviço. Você também pode criar mais dashboards para adicionar à página de monitoramento.
Isso é alimentado pelo AWS CloudWatch, então não precisei configurar o monitoramento separadamente. Abaixo estão capturas de tela ilustrando o monitoramento da função Lambda do API Gateway, da fila SQS e da função Lambda consumidora durante um teste de carga no endpoint da API.
Monitor da Lambda do API Gateway

Monitor do SQS

Monitor das Lambdas consumidoras

A maioria dos provedores de nuvem tem monitoramento embutido. Assim como o AWS CloudWatch, a Microsoft tem o Azure Monitor e o Google tem o Cloud Monitoring no GCP.
Apesar da integração fluida entre os serviços nativos da AWS usados para construir a solução de webhooks, uma coisa que notei foi a restrição de recursos de cada componente.
Diferentemente da abordagem open source, você fica limitado ao que a AWS oferece. Por mais que a AWS tente entregar todos os recursos e opções de configuração de que você precisa, isso não supera a flexibilidade e o controle de construir os seus serviços com tecnologias open source.
Comparando as duas abordagens
Agora que discutimos e experimentamos diferentes abordagens para implementar a nossa solução de webhooks, é hora de comparar. Na tabela abaixo, compartilho a minha experiência com as duas abordagens sob os mesmos fatores que viemos analisando ao longo deste artigo:
| Open source | Provedor de nuvem | |
|---|---|---|
| Facilidade de implementação | Depende do conhecimento técnico e do tamanho do time. Levei 2 dias para configurar direito o Docker e o Docker Compose, e isso só porque eu estava enferrujado, não por falta de experiência com essas tecnologias. | Um tempo de implementação relativamente mais rápido que o das tecnologias open source. Eu não tinha experiência prévia com SQS, mas consegui configurá-lo em cerca de 30 minutos depois de assistir a alguns tutoriais em vídeo. |
| Escalabilidade | A responsabilidade de escalar a infraestrutura recai sobre o arquiteto ou projetista do sistema. Precisei rodar testes de carga, medir throughput e usar essa informação para determinar o número de nós de cada componente. Não é uma técnica de escala sustentável se não for automatizada. | A maioria dos componentes tem recursos de escalabilidade embutidos para suportar tráfego crescente. As minhas funções Lambda na AWS escalam automaticamente com o aumento da carga, e havia configurações tanto no SQS quanto nas funções Lambda para melhorar a performance conforme o caso de uso. |
| Opções de configuração | Altamente configurável. Tanto em código quanto pelas diferentes interfaces web das minhas instâncias de RabbitMQ, Grafana e StatsD, consegui aplicar opções de configuração em nível granular. Por exemplo, configurei acknowledgments automáticos no consumo de mensagens e persisti as mensagens da fila em disco até serem consumidas. | Limitado às opções de configuração oferecidas pelo provedor. O SQS, por exemplo, tem algumas opções para tarefas como período de retenção de mensagens e dead lettering. Também existem opções no SDK do cliente, mas a flexibilidade de configuração não chegava perto da do RabbitMQ. |
| Conhecimento técnico exigido | Exige conhecimento especializado de arquitetura e dos diferentes componentes arquiteturais. Antes de usar o RabbitMQ, li metade de um livro sobre ele e assisti a alguns cursos. Também precisei consultar a documentação online de tempos em tempos para verificar breaking changes entre versões e exemplos de implementação. | Boa parte da complexidade é abstraída, o que facilita para iniciantes implantar uma infraestrutura poderosa e confiável. Como mencionei, configurar funções Lambda e SQS foi direto ao ponto depois de assistir a alguns vídeos no YouTube. |
| Custo ($$) | Começa pequeno e cresce com a escala. Com a minha configuração open source, os planos gratuitos de algumas empresas de hospedagem hospedariam a minha infraestrutura sem problemas. Mas sei que precisarei de mais para trabalho real em produção, e isso vai crescer conforme o volume de webhooks aumentar. | O preço cresce com o uso de recursos. A concorrência de preços entre provedores é uma enorme vantagem. Os preços de serviços como Lambda, API Gateway e SQS pareceram bastante justos pelo que vi ao construir. Tudo o que construí e testei também me custou menos de um centavo, mas todos sabemos que não é assim em produção real. Tráfego alto também tem o potencial de gerar contas altas em serviços de nuvem. |
| Confiabilidade/Performance | Depende da qualidade do seu design arquitetural e do poder computacional disponível. As minhas decisões de design durante a construção se apoiaram em um bom conhecimento de arquitetura. Não existe manual nem bala de prata para o “melhor” design que leva à “melhor” performance. | Depende dos SLAs e SLOs anunciados pelo provedor. Por exemplo, o SLO mensal de uptime da AWS para o Simple Queue Service (SQS) é “Less than 99.9% but greater than or equal to 99.0%” |
| Flexibilidade de escolha | Muito flexível, já que você escolhe as tecnologias que quer na sua stack. Eu conhecia melhor o RabbitMQ para filas, então fui com ele, mas poderia ter usado Kafka se me sentisse mais confortável. | Depende da oferta do provedor. Como eu queria usar só a AWS, tive que aprender a fazer filas do jeito SQS. Embora eu tenha conseguido traduzir o meu conhecimento geral sobre filas, não pude usar nenhuma habilidade específica de RabbitMQ para melhorar a experiência. |
| Extensibilidade | Você sempre pode usar sistemas de mensageria e gateways para integrar diferentes tipos de tecnologias/serviços. Eu sabia que, se fosse adicionar mais componentes, poderia usar mensageria e servidores proxy para conectar serviços que naturalmente não usam o mesmo protocolo. | Só é possível conectar a outras tecnologias/serviços suportados pelo provedor de nuvem. O AWS Identity and Access Management me permitiu conectar todos os meus serviços simplesmente concedendo as permissões certas aos componentes. |
| Conjunto de recursos | Todo recurso necessário precisa ser adicionado conscientemente à infraestrutura. Precisei projetar e construir todos os meus recursos de monitoramento do zero. Não havia presets e os templates disponíveis eram muito limitados. | A maioria dos serviços vem com recursos adicionais (AWS EC2, SQS, API Gateway etc. já trazem monitoramento e logging embutidos). No entanto, o monitoramento não era tão customizável quanto quando usei tecnologias open source como StatsD e Grafana para desenhar as visualizações que eu queria. |
Vale notar que este não é um exercício para escolher um “vencedor”. Como em toda decisão de arquitetura de software, a resposta é sempre “depende”.
Ainda assim, com a tabela acima eu apresentei as minhas observações sobre as duas abordagens principais sob diferentes fatores. Não é uma lista exaustiva, mas espero que sirva de guia para decisões que se encaixem melhor no seu cenário.
Quando usar uma abordagem híbrida para desenvolver a solução de webhooks
Uma abordagem híbrida é simplesmente combinar o melhor dos dois mundos (open source e ofertas de nuvem) com base em critérios como performance, conhecimento técnico ou familiaridade e preferências pessoais ou do time.
Essa estratégia também favorece o atendimento dos fatores que consideramos ao decidir entre tecnologias open source e serviços de nuvem. Podemos usar os melhores atributos de cada opção para obter o melhor resultado em cada fator analisado.
Vamos ver como usar essa estratégia com base nos fatores discutidos para extrair o melhor das duas opções.
- Facilidade de implementação: para um componente como a fila de mensagens, que pode ser fácil de configurar mas exige alto grau de proficiência para ser bem projetada, essa é uma área em que você pode aproveitar a estabilidade de um serviço de nuvem como o AWS SQS.
- Escalabilidade: boa parte dos serviços de nuvem já traz escalabilidade embutida. É um atributo que vale aproveitar se você não tem um time habilidoso em escalar arquiteturas complexas. Por exemplo, usar funções Lambda como workers de webhook resolve a escalabilidade no lado do consumo.
- Opções de configuração: componentes como o API gateway, em que você executa operações customizadas antes do enfileiramento — como terminação TLS, transformação de payload e verificação —, ficam melhores construídos com tecnologia open source. Isso porque as necessidades de cada time são diferentes nesses componentes.
- Conhecimento técnico exigido: se o time já tem o conhecimento para construir e escalar um componente, há mais vantagem em usar tecnologias open source e construir do zero. Se não tem, você pode plugar um serviço de nuvem com curva de aprendizado curta para cumprir o papel do componente.
- Custo: isso pode ir para os dois lados. Mas, por experiência, percebi que tecnologias open source costumam ser mais baratas no começo. À medida que o volume de webhooks cresce, o custo de hospedar e escalar a solução sobe. Os serviços de nuvem tentam operar no modelo de pagamento por uso e alguns reduzem escala quando o seu tráfego está baixo, ajudando a economizar. A escolha vai depender do estágio atual do seu produto, do seu time e do número de usuários.
- Confiabilidade/Performance: o argumento aqui é parecido com o da escalabilidade. Se o seu time é proficiente o bastante para chegar ao melhor design nesse atributo, para um componente como monitoramento, use tecnologias open source. Se não, use um serviço de nuvem para assumir a responsabilidade do componente.
- Flexibilidade de escolha: o componente de fila é uma área em que a abordagem híbrida realmente ajuda a encontrar o melhor encaixe para o seu design. Digamos que você comece com o AWS SQS e depois descubra que o Kafka tem recursos que suportam a direção que a sua infraestrutura está tomando: você pode trocar o SQS pelo Kafka para obter a melhor performance possível.
- Extensibilidade: uma abordagem híbrida permite usar as tecnologias que melhor se conectam ao seu conjunto de aplicações existente ou que facilitam a extensão pelo time. Por exemplo, se você precisa alimentar um serviço AWS existente com dados das suas filas, pode usar o SQS. Por outro lado, se precisa levar dados da fila para um sistema central de métricas como o Prometheus, pode usar o RabbitMQ.
- Conjunto de recursos: dependendo da flexibilidade do seu time quanto aos recursos essenciais de um componente, você pode usar open source ou um serviço de nuvem. Por exemplo, se as suas filas precisam de forte suporte a separação de mensagens por tópico e a streaming, talvez seja o caso de usar o Kafka. Mas, se você só quer um sistema de filas confiável e simples, usar um serviço como o AWS SQS é o recomendado.
Conclusão
Neste artigo, demonstramos o uso de tecnologias open source e de provedores de nuvem para implantar a nossa solução de webhooks. Também discutimos uma abordagem híbrida que tenta, de forma pragmática, combinar as duas para extrair o melhor dos dois mundos. Por fim, comparamos cada abordagem sob fatores importantes para a sustentabilidade da solução.
Se você está avaliando construir a sua solução de webhooks do zero ou comprar uma solução existente, leia o artigo sobre construir versus comprar. Com essas informações em mãos, você conseguirá não só tomar decisões que atendem às suas necessidades de infraestrutura, como também ajudar o seu negócio a economizar e oferecer uma experiência confiável aos usuários.
Este guia foca em construir a infraestrutura de webhooks por conta própria. Se você prefere pular a construção e usar uma solução gerenciada feita para isso, o Event Gateway da Hookdeck cuida de todos os componentes discutidos acima — enfileiramento, roteamento, lógica de retry, rate limiting, monitoramento e alertas — como um único serviço gerenciado. Para uma comparação entre construir e comprar, veja o nosso guia para construir ou comprar a sua infraestrutura de webhooks.
Infraestrutura de webhooks, gerenciada para você
A Hookdeck cuida da ingestão, entrega, observabilidade e recuperação de erros — para que você não precise.