03 - AWS SQS-SNS (Gerenciado)
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.