Home Comunidade Eventos YouTube Networks Desafios // produtos Academy News CTI | CVE Contato

03 - AWS SQS-SNS (Gerenciado)

#dlq#fanout#sns#sqs#visibility-timeout
video explicativo
Video explicativoEspaco reservado para o video desta anotação — adicione video: https://youtu.be/... no frontmatter da nota.

AWS SQS e SNS (Gerenciado)

SQS e SNS são os serviços gerenciados de mensageria da AWS: o SQS é uma fila de mensagens com entrega para um consumidor, e o SNS é um serviço de publicação-assinatura que entrega a mesma mensagem a múltiplos assinantes. Juntos, cobrem o ciclo completo de mensageria sem servidores para operar, sem patches e com elasticidade automática, o que os torna o default de desacoplamento em arquiteturas na AWS, desde filas de tarefas simples até fanout de eventos para dezenas de destinos. A relevância em produção é dupla: eliminam a operação de broker, trocando por configuração, e cobram por uso, o que muda a economia em cargas variáveis. O preço do gerenciado está nas cotas por região, nas garantias específicas de cada tipo de fila e no acoplamento ao modelo de serviço da nuvem. Dominar visibility timeout, redrive de DLQ e o padrão de fanout do SNS para SQS é o que separa uma arquitetura serverless sólida de uma que perde mensagens em silêncio.

SQS standard versus FIFO

A fila standard é o default: throughput praticamente ilimitado, entrega at-least-once e ordem best effort. Isso significa duplicidades ocasionais e mensagens que podem chegar fora da ordem de publicação. Para a maioria das filas de trabalho, isso é aceitável e barato, desde que o consumidor seja idempotente.

O custo do serviço segue operações: publicação, recebimento e armazenamento por GB-mês, o que torna o custo proporcional ao uso real e praticamente nulo em ambientes de baixo volume. Em cargas de pico extremo, a ausência de provisionamento prévio elimina a etapa de dimensionamento que filas auto-hospedadas exigem, e o trade-off aparece no custo unitário comparado a um cluster próprio em volume constante alto.

A fila FIFO troca throughput por garantias: ordem exata dentro de grupos de mensagens e deduplicação por chave no intervalo de deduplicação. O throughput por grupo é limitado e histórico, com elevação em modos recentes, mas o desenho continua pedindo bom número de grupos de mensagens para paralelizar: todos os eventos de uma mesma entidade compartilham o MessageGroupId e são ordenados e processados sequencialmente dentro do grupo, enquanto grupos diferentes fluem em paralelo.

A decisão prática: standard quando o volume é alto e a duplicidade é absorvível por idempotência; FIFO quando a ordem por entidade é requisito de negócio, como atualizações de saldo e sequência de estados de pedido. Converter depois é migration real, porque a semântica de consumo muda; decidir no desenho.

Característica Standard FIFO
Throughput Praticamente ilimitado Limitado, escala por grupos de mensagens
Entrega At-least-once, com duplicidades ocasionais At-least-once com deduplicação por chave
Ordenação Best effort, sem garantia Exata dentro do MessageGroupId
Contenção Nenhuma Fila por grupo: grupo lento segura os próprios eventos
Caso ideal Tarefas independentes, notificações Estados de entidade, cobrança, saldo

Visibility timeout

O visibility timeout é o mecanismo central do SQS: ao receber uma mensagem, ela fica invisível para os demais consumidores durante o período configurado; se o consumidor não deletar a mensagem nesse intervalo, ela volta a ficar visível e pode ser entregue novamente. É o equivalente do lock com prazo, e é o que permite concorrência sem confirmação explícita por lock distribuído.

O erro clássico é configurar o timeout menor que o tempo real de processamento. O consumidor A ainda processa, o timeout expira, a mensagem fica visível e o consumidor B a entrega de novo, gerando processamento duplicado e, em fila FIFO, bloqueio de grupo. A regra é timeout maior que o p99 do processamento, com margem; quando o processamento pode estourar, a API de change message visibility estende o prazo em execução, e o heartbeat do worker renova até concluir.

A outra face é timeout longo demais: mensagem que falhou silenciosamente demora a voltar para tentativa. O desenho saudável combina timeout calibrado com maxReceiveCount no redrive, de modo que mensagens problemáticas sejam contadas e envidadas à DLQ em número finito de tentativas.

Em operação com Lambda, o timeout de visibilidade também precisa cobrir o tempo de processamento da função incluindo retries internos do runtime, e o tamanho do lote influencia: lote de 10 itens processado em 2 minutos exige visibilidade bem acima disso, senão outro poller recebe o mesmo lote em paralelo e o processamento duplica em escala.

SNS como fanout

O SNS é o componente de distribuição: um produtor publica no tópico, e o tópico entrega cópias para todos os assinantes, que podem ser filas SQS, funções Lambda, endpoints HTTP, e-mail, SMS ou push. Cada assinatura pode ter filtros de política de mensagem, entregando apenas os eventos que interessam ao destino, o que reduz custo e processamento descartado.

No papel de arquitetura, o SNS resolve o fanout sem que o produtor conheça os destinos. Um evento PedidoCriado publicado uma vez alimenta faturamento, estoque, e-mail e analytics; o novo consumidor se assina e aplica filtro, e o produtor não muda uma linha. É a versão gerenciada do padrão publish-subscribe, com entrega empurrada ao assinante em vez de puxada.

A entrega do SNS é at-least-once e a ordem não é garantida em tópicos standard; tópicos FIFO existem com subscrição para filas FIFO e garantem ordem por MessageGroupId. O tamanho máximo de mensagem é 256 KB; payloads maiores seguem o padrão de claims check, publicando referência para o conteúdo em S3, ou o modo de publicação de payload grande gerenciado pelo próprio SNS com S3.

O SNS também serve para além da integração interna: notificação de eventos de contas e serviços, como alertas de CloudWatch e alarmes, usam o mesmo modelo de tópico e assinatura, o que unifica o padrão de distribuição de mensagens na plataforma inteira, de eventos de negócio a eventos de infraestrutura.

O padrão SNS fanout para SQS

A combinação SNS com múltiplas filas SQS é o formato comum de fanout gerenciado na AWS: o tópico entrega cada evento para cada fila assinada, e cada consumidor processa sua cópia no próprio ritmo, com a própria DLQ e o próprio visibility timeout. O desenho isola falhas por consumidor, porque cada fila absorve a lentidão ou queda do seu processamento sem contagiar os outros.

Esse padrão substitui o fanout manual, em que o produtor publicava N mensagens em N filas, código que envelhece mal e perde consistência quando o terceiro destino aparece. No SNS, a inclusão de destino é configuração: criar a fila, assinar no tópico, aplicar filtro de política. A permissão precisa permitir que o tópico envie à fila, via política de acesso na fila restrita ao ARN do tópico.

A segurança do conjunto tem três camadas: criptografia em repouso com chave gerenciada na fila e no tópico, política de acesso na fila que só aceita mensagens do ARN do tópico específico, e restrição de quem pode publicar no tópico por política do próprio SNS. Publicar em tópico sem restrição e deixar fila aceitando qualquer remetente são as duas brechas mais frequentes em auditoria.

O desenho do consumidor segue as regras de sempre: idempotência no processamento, pois a entrega é at-least-once em toda a cadeia, e DLQ por fila, configurada no redrive policy, com alarme sobre o número de mensagens na DLQ. O envelope da mensagem precisa ser tratado: com raw message delivery ativado na subscrição, a fila recebe o payload puro; sem ele, o consumidor recebe o envelope JSON do SNS e precisa desembrulhar.

{
  "TopicArn": "arn:aws:sns:us-east-1:123456789012:pedidos",
  "Message": "{\"evento\": \"PedidoCriado\", \"pedido_id\": \"P-90123\", \"total\": 15990}",
  "MessageAttributes": {
    "tipo_evento": {"DataType": "String", "StringValue": "PedidoCriado"},
    "regiao": {"DataType": "String", "StringValue": "sudeste"}
  }
}
# Elementos de infraestrutura do padrão fanout (IaC, extrato ilustrativo)
TopicoPedidos:
  Type: AWS::SNS::Topic
FilaFaturamento:
  Type: AWS::SQS::Queue
  Properties:
    VisibilityTimeout: 300            # acima do p99 do processamento
    RedrivePolicy:
      deadLetterTargetArn: !GetAtt FilaFaturamentoDlq.Arn
      maxReceiveCount: 5              # quinta entrega falha vai para DLQ
SubscricaoFaturamento:
  Type: AWS::SNS::Subscription
  Properties:
    TopicArn: !Ref TopicoPedidos
    Protocol: sqs
    Endpoint: !GetAtt FilaFaturamento.Arn
    RawMessageDelivery: true          # consumidor recebe o payload puro
    FilterPolicy:
      tipo_evento: [PedidoCriado]     # fila só recebe o que processa

DLQ nativa e integração com Lambda

A dead letter queue é configuração nativa em fila e em assinatura, com contagem de recebimentos como gatilho. No SQS, o redrive policy define a fila de destino e o maxReceiveCount; quando o contador estoura, a mensagem vai para a DLQ com o histórico de tentativas em atributos. No SNS, a DLQ da assinatura captura falhas de entrega do próprio tópico, um caso distinto que costuma ser esquecido.

A integração com Lambda é o motor do serverless: a fila pode ser source de evento, e o Lambda escala automaticamente com o backlog, com paralelismo controlado por grupo de mensagens em FIFO. O comportamento de falha importa: erro na função faz o lote voltar para a fila e recontar recebimentos, e configurações de bisect do lote evitam reprocessar tudo quando um item específico falha.

Operacionalmente, o trio de alarmes mínimo é: idade aproximada da mensagem mais antiga na fila, número de mensagens na DLQ e taxa de erro da função consumidora. Idade crescente indica backlog por capacidade; DLQ com volume indica bug ou dependência quebrada; os dois juntos indicam incidente em andamento.

Sintoma em produção Causa provável Mitigação
Idade da mensagem mais antiga cresce Consumidor sem capacidade ou travado Escalar consumo, revisar paralelismo e lote
Duplicidade de processamento Visibilidade menor que o processamento Calibrar timeout, estender em tarefa longa
Mensagens na DLQ com erro 400 Contrato de payload quebrado Corrigir produtor, replanejar schema
Mensagens na DLQ com erro 5xx Dependência instável no processamento Corrigir dependência e redrive de volta à fila
Fila FIFO parada em um grupo Um MessageGroupId travado por falha Isolar grupo problemático, revisar lógica de bloqueio
Lambda repete o mesmo lote Item venenoso no lote Bisect de lote e DLQ por falha parcial

Cenários reais de produção

E-commerce com fanout de pedido: o serviço de pedidos publica no tópico, e quatro filas assinam com filtros, faturamento recebe PedidoCriado, estoque recebe os dois eventos, e-mail apenas PedidoPago. Cada consumidor escala e falha isoladamente; durante uma instabilidade do serviço de e-mail, o checkout seguiu normal e o backlog de e-mail foi drenado depois, sem perda.

Processamento de uploads com Lambda: cada arquivo novo é anunciado em fila, o Lambda valida, gera miniaturas e grava resultados. Sob pico de upload, o serviço escala de 10 a 300 execuções e volta ao repouso; a DLQ captura os arquivos malformados, e a equipe investiga por relatório diário em vez de chamado por usuário.

Integração com sistema de terceiro lento: o ERP parceiro aceita no máximo 50 requisições por minuto. A fila recebe o volume do negócio e um consumidor com taxa controlada, via throttle próprio e visibilidade longa, empurra ao ERP no ritmo aceitável; o resto do sistema nunca soube que o parceiro é lento.

Erros comuns e boas práticas

  • Usar standard onde a ordem importa: estado de pedido processado fora de sequência gera saldo errado; FIFO com MessageGroupId por entidade é a resposta, com grupos em número suficiente para paralelismo.
  • Visibility timeout menor que o processamento: duplicidade e bloqueio em FIFO; calibrar com margem e usar extensão de visibilidade em tarefas longas.
  • Esquecer o envelope do SNS na fila: o consumidor tenta parsear o payload e falha por causa do wrapper; ativar raw message delivery na subscrição quando o destino é fila.
  • Não configurar DLQ no SQS e na subscrição do SNS: são dois pontos de falha distintos, entrega do tópico e processamento da fila, e cada um precisa do seu redrive.
  • Ignorar as cotas do serviço: 256 KB por mensagem, limites de throughput em FIFO e quotas de região; desenho que pressupõe broker próprio esbarra em limites que ninguém leu.
  • Deixar mensagens expirarem em silêncio: a retenção padrão de 4 dias apaga dados; a retenção precisa ser decisão explícita compatível com a janela de investigação e reprocesso.
  • Fanout manual com N publicações do produtor: cada novo destino exige código e reintroduz inconsistência; tópico SNS com filtros é o desenho que escala em destinos.
  • Consumir sem idempotência: toda a cadeia é at-least-once, SNS e SQS; chave de deduplicação ou verificação de processamento anterior é requisito, não otimização.
  • Não monitorar DLQ por alarme imediato: mensagem em DLQ é compromisso não cumprido com usuário real; alarme precisa disparar no primeiro item, não em threshold alto.
  • Redrive de volta à fila principal sem idempotência confirmada: reprocessar em massa a DLQ depois de correção duplica efeitos se o consumidor não for idempotente; validar a chave de idempotência antes de mover mensagens.
  • Tratar SNS e EventBridge como equivalentes: SNS fanout é simples e barato para distribuição direta; EventBridge entra quando há roteamento por conteúdo, bus de eventos entre contas e transformação de entrada.
  • Repartir payload em atributos do SNS: atributos são metadados para filtros, não extensão do corpo; dado que faz parte do evento vai no corpo da mensagem dentro do limite de 256 KB.