Ir para o conteúdo
Voltar ao blog
Desenvolvimento 12 min

WebSockets Serverless: Arquitetura de Produção com AWS e Node.js

Domine a comunicação em tempo real sem gerenciar servidores. Guia técnico sobre AWS API Gateway, Lambda e DynamoDB para alta concorrência.

Diagrama técnico de arquitetura serverless usando AWS Lambda e API Gateway para WebSockets.

Manter uma conexão TCP aberta por horas apenas para esperar uma simples mensagem de 'notificação' é um desperdício de recursos que seu orçamento não deveria ignorar. Enquanto no passado nos resignávamos a gerenciar frotas de EC2 com instâncias de Socket.io suando sob o peso de 50.000 conexões simultâneas, a era serverless mudou as regras. Não se trata de saber se você consegue fazer, mas se consegue fazer sem que sua infraestrutura se torne um pesadelo de manutenção.

O Problema dos WebSockets no Mundo Stateless

Por definição, o AWS Lambda é stateless. Ele liga, processa e morre. Os WebSockets, pelo contrário, são a própria definição de stateful: exigem uma conexão persistente entre cliente e servidor. Como reconciliar esses dois mundos? A resposta não está em forçar o Lambda a ficar vivo, mas em delegar a gestão do estado da conexão a uma camada superior: AWS API Gateway.

A Anatomia da Conexão

Em uma arquitetura de WebSockets serverless, o fluxo é dividido em três responsabilidades claras:

  • Gestão de Conexão: O API Gateway mantém o socket aberto com o cliente.
  • Persistência de Estado: O DynamoDB armazena o connectionId associado ao usuário.
  • Processamento Lógico: Funções Lambda que são ativadas apenas quando uma mensagem chega ou precisa ser enviada.

Passo 1: Configurando as Rotas no API Gateway

Diferente de uma API REST, os WebSockets na AWS funcionam por meio de rotas predefinidas. Você precisa configurar pelo menos três:

  1. $connect: Disparado quando o cliente inicia o handshake.
  2. $disconnect: Disparado quando o cliente sai ou a conexão é perdida.
  3. $default: O coringa para qualquer mensagem que não corresponda a rotas específicas.
"O erro mais comum é não implementar um mecanismo de limpeza para conexões órfãs no DynamoDB. Se o cliente desaparecer sem um $disconnect limpo, sua tabela ficará cheia de IDs inúteis."

Passo 2: Persistência do ConnectionId no DynamoDB

// Exemplo de lógica Lambda para $connect
const AWS = require('aws-sdk');
const ddb = new AWS.DynamoDB.DocumentClient();

exports.handler = async (event) => {
  const connectionId = event.requestContext.connectionId;
  const userId = event.queryStringParameters.userId;

  await ddb.put({
    TableName: 'ConnectionsTable',
    Item: { connectionId, userId, ttl: Math.floor(Date.now() / 1000) + 3600 }
  }).promise();

  return { statusCode: 200, body: 'Connected.' };
};

Usar um TTL (Time To Live) no DynamoDB é uma prática recomendada para evitar custos desnecessários e manter o banco de dados enxuto. Se o usuário não atualizar sua sessão, a entrada desaparece automaticamente.

Passo 3: O Desafio da Comunicação Outbound

Enviar uma mensagem do servidor para o cliente é onde muitos desenvolvedores se confundem. O Lambda não pode simplesmente 'responder' ao evento de invocação original para enviar dados assíncronos mais tarde. Você deve usar o ApiGatewayManagementApi.

O Processo de 'Push'

Quando ocorre um evento no seu sistema (ex: uma nova venda, uma mensagem de chat), sua lógica deve:

  • Consultar no DynamoDB o connectionId do destinatário.
  • Instanciar o SDK da AWS apontando para a callback URL do seu API Gateway.
  • Chamar postToConnection com o ID e o payload.
const apigw = new AWS.ApiGatewayManagementApi({
  endpoint: event.requestContext.domainName + '/' + event.requestContext.stage
});

try {
  await apigw.postToConnection({
    ConnectionId: targetId,
    Data: JSON.stringify({ message: 'Olá do servidor' })
  }).promise();
} catch (e) {
  if (e.statusCode === 410) {
    // Conexão não existe mais, remover do DB
  }
}

Comparativo: Serverless vs. Servidores Tradicionais

CaracterísticaServerless (AWS)Tradicional (EC2/Node.js)
EscalabilidadeAutomática (milhares de conexões/seg)Manual / Auto-scaling complexo
Custo Ocioso$0 (pagamento por uso)Custo fixo mensal por instância
Gestão de EstadoExterna (DynamoDB/Redis)Em memória (volátil)
ManutençãoBaixa (Serviço Gerenciado)Alta (Patches, segurança)

Considerações de Latência e Limites

Nem tudo são flores. A arquitetura serverless introduz a latência de 'cold start' se suas funções Lambda não forem invocadas com frequência. Além disso, o API Gateway tem um limite padrão de 10.000 conexões simultâneas (aumentável via suporte). Se você está construindo o próximo WhatsApp, pode precisar de uma camada de otimização adicional com ElastiCache para reduzir os tempos de leitura dos IDs de conexão.

Como abordamos isso na Julsmind SAS

Na Julsmind SAS, projetamos sistemas que não apenas funcionam, mas são economicamente viáveis a longo prazo. Implementamos arquiteturas de WebSockets serverless para fintechs na Colômbia e startups nos EUA, alcançando reduções de custos de infraestrutura de até 60% ao eliminar servidores ociosos. Nosso foco é a robustez: desde o tratamento de reconexões exponenciais no cliente até a orquestração de eventos complexos no backend usando EventBridge.

Você está enfrentando problemas de escalabilidade em suas notificações em tempo real ou quer migrar de uma arquitetura legada? Vamos conversar sobre como otimizar seu stack tecnológico em nossa página de contato e levar seu produto ao próximo nível.

Tem um projeto em mente?

Solicite um orçamento gratuito com a nossa equipe — sem compromisso.

Solicitar orçamento