Blog
Cem laboratórios reproduzíveis que constroem competência de arquitetura na AWS na ordem em que ela se usa: começa numa aplicação .NET 8 de três camadas que sobe de verdade — ECS Fargate, RDS em sub-rede privada, front na borda, tudo em Terraform — e avança por serverless, sistemas distribuídos, segurança, operação e dados até arquitetura de solução com IA. Cada laboratório tem entregável verificável, três arquiteturas (mínima, produção e evolução) e uma seção de limpeza, porque laboratório de arquitetura deixa recurso cobrando depois que a aula termina.
A primeira aplicação completa: três camadas em duas AZs, banco que a internet não alcança, segredo rotacionado pelo RDS e deploy por digest — com o Terraform e o C# inteiros.
A sub-rede é privada por causa da tabela de rotas, não de uma flag. Duas camadas de sub-rede em duas AZs, NAT Gateway do lado certo, plano de endereçamento escrito — e a prova, por medição, de que o banco deixou de ter endereço alcançável.
O 5xx do deploy não vem da versão nova: vem de três relógios que não se conhecem. Tag imutável por SHA, excedente que permite as duas versões conviverem, prazo de drenagem derivado do p99 — e a prova de que a desregistragem acontece antes do SIGTERM, observada nos estados da task.
Segredo não é parâmetro sensível: é parâmetro com relógio. O ECS resolve o valor uma única vez, no arranque da task — então ligar rotação sem ensinar a aplicação a reler troca um vazamento por uma indisponibilidade agendada, que chega horas depois numa conexão nova.
A borda não é um interruptor: o domínio e o certificado decidem se ela responde, e a chave de cache mais o Cache-Control da origem decidem se ela economiza. Sem os dois lados, o CloudFront é só um salto de rede a mais.
A política não reage ao pico: reage ao retrato do pico, revelado tarde. A decisão nunca é qual número subir — é qual métrica observar, e quanto valem os quatro atrasos entre a chegada da carga e a chegada da capacidade.
Multi-AZ compra disponibilidade e a réplica compra leitura — e a latência que você está medindo não é vendida por nenhuma das duas, porque sai de uma consulta sem índice e de uma conta de conexão que é tasks × pool, não pool.
Log não é texto para humano ler: é dado para máquina consultar, e o que transforma um no outro é um identificador que atravessa todas as camadas — e ele já existe antes do seu código, porque o balanceador o injeta.
Você não explica uma fatura, você a instrumenta antes de ela crescer — e são dois relógios de retroatividade: a ativação da tag retroage por meses, a presença da tag no recurso não retroage por nenhum mecanismo.
RTO e RPO não são metas que se declaram numa reunião: são números que só existem depois do ensaio. E as duas maiores parcelas do RTO não estão na AWS — estão em detectar e em repontar a aplicação para o endpoint novo que a restauração cria.
O API Gateway não substitui o ALB — administra um contrato que o ALB não sabe que existe. Sem terceiro para administrar, ele é só um salto de rede a mais e uma fatura por requisição. Prova por aritmética: cota em memória de cada task vira média entre réplicas.
Sessão em memória não é defeito de escala: é um estado do cliente guardado no servidor errado. O token devolve esse estado sem consultar o Cognito a cada requisição — e o preço do ganho é que revogar deixa de ser imediato.
Cache não é cópia mais rápida do banco: é uma segunda fonte de verdade que você aceitou manter. A pergunta não é o que cachear — é quanto tempo você tolera estar errado, e toda regra de invalidação responde a ela.
Não se escolhe banco por tipo de dado — escolhe-se pelo padrão de acesso. A mesma feature implementada em RDS, Aurora e DynamoDB, medida sob carga, prova por que DynamoDB é previsível quando o acesso é conhecido e perde feio quando a pergunta é nova.
A pergunta não é quando o Aurora pode escalar sem travar sua transação — no Serverless v2 ele sempre pode. A pergunta é o que decide o piso e o teto de ACU, e a resposta é carga medida, não medo de bloqueio que pertence à v1.
A chave primária do DynamoDB não descreve a entidade: é a resposta compilada à pergunta que a tabela existe para responder. Modelar entidade primeiro e consulta depois transforma toda pergunta nova em Scan — a conta real está no módulo.
Assinar não é transportar: a URL assinada tira a aplicação do caminho do byte sem tirá-la da decisão. O preço é que o limite de tamanho deixa de ser código e vira condição de assinatura — e PUT simples não tem essa condição nenhuma.
A migration não precisa de janela: o acoplamento entre schema e código precisa. O defeito quase nunca é a duração do DDL — é a fila de bloqueio, onde uma transação aberta segurando um lock fraco faz todo leitor novo esperar atrás do ALTER.
LIKE com curinga à esquerda não usa índice — vira varredura completa, e o PostgreSQL já tem índice invertido de verdade antes de OpenSearch se justificar. A mesma busca nos dois, com o limite de cada um medido.
A escolha não é de framework: é de onde o HTML é montado, e isso decide o que a borda cacheia, o TTFB e quanto computação você paga por visita. Achado na documentação: TTL mínimo acima de zero faz o CloudFront ignorar Cache-Control: no-store da origem.
Fargate cobra por existir; Lambda cobra por rodar — e o cold start é o preço que ela paga, a cada ambiente novo, pelo mesmo boot que o Fargate faz uma vez e nunca mais cobra. Job de baixa frequência sofre MAIS cold start, não menos.
SQS entrega ao menos uma vez — a duplicata não é bug, é o contrato. O que decide se ela vira cobrança duplicada é a escrita condicional do consumidor, não nenhum parâmetro da fila. DLQ, ReportBatchItemFailures e reprocessamento provado.
O terceiro consumidor não deveria pedir linha nova no produtor — a lista de quem recebe nunca devia morar no código dele. SNS move essa lista para as assinaturas, e "publish com sucesso" mede aceitação, não entrega ao assinante.
A teia não nasce de faltar fila — nasce de cada consumidor decidir sozinho a quem perguntar. EventBridge move essa decisão para uma regra nomeada, e o contrato de evento versionado impede a pergunta de quebrar quando o produtor muda um campo.
O try/catch de 400 linhas não é feio por estilo: é ilegível porque em que passo estou e quantas vezes já tentei moram no mesmo texto. Step Functions separa a máquina de estados, visível, do código de cada passo, pequeno e testável isolado.
ECS cobra pela hora que a task existe; API Gateway + Lambda + DynamoDB cobram pela invocação que atendem. O ponto em que uma curva cruza a outra é aritmética sobre volume, não opinião sobre arquitetura.
O defeito da EC2 do cron não é o desperdício: é o silêncio. Quando o job não roda, o único sintoma é o efeito ausente. EventBridge Scheduler transforma ausência de execução em falha observável, com DLQ e alarme por agendamento.
O atraso não é preguiça de quem deveria rodar o script — é ausência de gatilho. Notificação direta do bucket trava a evolução como o fanout travava o produtor: só cabe um destino. EventBridge resolve com trilha de estado por arquivo.
Um job de polling não só atrasa — ele perde transições intermediárias entre execuções. DynamoDB Streams troca a pergunta por aviso, mas a ordem que garante é por chave de partição, não global, e a retenção é de 24 horas.
O job de 20 minutos não esbarra em um limite do Lambda — esbarra em cinco ao mesmo tempo, e a gambiarra que resolve o timeout piora os outros quatro. Step Functions orquestrando uma task Fargate resolve os cinco de uma vez.
Um serviço só está pronto para ser extraído quando termina a própria transação sem depender de outro serviço no mesmo commit. A maioria dos cortes ruins nasce de dividir por camada técnica em vez de por essa fronteira.
Numa cadeia síncrona, a disponibilidade é o produto das disponibilidades, não a média — quatro serviços a 99,9% cada dão 99,6%, quase quatro vezes mais indisponibilidade. O serviço saudável no meio relata a falha alheia como se fosse sua.
IP de task muda a cada implantação — gravá-lo fixo é um bug adiado. Service Connect, Cloud Map isolado e VPC Lattice respondem perguntas diferentes, não são três níveis da mesma escala, e isolamento de rede não é identidade de quem chama.
"Vamos de Kubernetes" sem critério é quase sempre currículo, não requisito. EKS não troca de motor — acrescenta um segundo plano de operação sobre o mesmo Fargate que o ECS já usa, e esse plano só se paga com um requisito real.
Quando cada serviço tem seu próprio banco, não existe mais transação ACID cruzando os dois. A saga resolve com transações locais e compensação explícita — código que desfaz o efeito, não rollback mágico, e a compensação também pode falhar.
Retry sem espera crescente faz um serviço já sobrecarregado receber mais carga exatamente quando tenta se recuperar. Jitter quebra a sincronização que o backoff exponencial sozinho não quebra — retry storm reproduzido antes e depois.
O usuário que acabou de salvar e não vê a própria mudança não pensa "consistência eventual" — pensa que o sistema tem bug. Leitura-própria-escrita resolve o sintoma para o autor, enquanto todo outro usuário segue eventualmente consistente, de propósito.
Isolamento de tenant não é feature da aplicação — é decisão de onde mora a fronteira. Um WHERE esquecido no modelo por linha vaza tudo; RLS com FORCE torna isso impossível no motor do banco. Os três modelos implementados, com teste de vazamento executável.
O rollback do blue/green não é publicar a versão antiga de novo — é apontar um listener para uma frota que nunca parou de existir. Só o canário resolve deploy ruim aparecendo com 100% do tráfego dentro, porque blue/green direto ainda expõe todo mundo de uma vez.
O gargalo real não se acha perguntando quantos usuários — acha-se subindo a carga em degraus até sobrar uma camada só saturada, e ela quase nunca é a que a intuição aponta primeiro. O sucesso do autoscaling é o que aperta o banco.
AdministratorAccess "para não travar" é medo disfarçado de pragmatismo. IAM Access Analyzer deriva a policy do uso REAL registrado no CloudTrail — mas derivada de evidência e correta não são sinônimos: o caminho raro vira AccessDenied na pior hora.
A chave estática é perigosa não só por poder vazar — é perigosa porque a cadeia de credenciais do SDK a testa ANTES da task role, então uma role bem configurada fica muda, sem erro nenhum, atrás de uma variável que ninguém removeu.
SCP nunca concede nada — só recorta o teto do que a policy IAM já concedeu. É por isso que a fronteira de conta é mais forte que qualquer policy: um wildcard pensado para dev pode casar com prod por prefixo, e só a conta torna isso impossível.
Tráfego para o S3 sai da VPC, atravessa a internet e volta, pago por GB no NAT. Endpoint Gateway para S3/DynamoDB é gratuito; endpoint Interface via PrivateLink resolve o resto sem o tráfego sair da rede da AWS — e ainda sai mais barato que o NAT.
Redundância de rede híbrida não é ter dois túneis — é ter dois caminhos físicos independentes. VPN já entrega dois túneis IPsec de série, e nenhum sobrevive à queda do único roteador on-premises que os origina.
O byte nunca é cifrado pela CMK — é cifrado por uma chave de dados efêmera, e a CMK só cifra essa chave. Trocar para CMK própria não muda como o byte é cifrado, muda quem controla a política que decide quem pode pedir a operação.
O custo de um bot não nasce da resposta que ele recebe — nasce do fato de que, para dizer "não", a task já rodou. Bloquear na borda impede que ela chegue a rodar. Ataque simulado bloqueado no WAF, com custo evitado medido.
O achado de segurança não morre por falta de detecção — GuardDuty e Config já detectam sozinhos. Ele morre porque nenhum dos dois tem prazo no vocabulário. É o EventBridge, não o console, que transforma achado em ticket com SLA.
O CPF no log não vaza pelo banco — vaza porque o log É um banco de dados de CPF que ninguém tratou como banco de dados: mesmo dado, controle de acesso mais largo, retenção decidida por outra pessoa. Varredura sem achado, log sem dado pessoal.
Desativar a credencial vazada não mata a sessão temporária que ela já emitiu. CloudTrail via Athena diz se essa segunda contenção é necessária, e é o mesmo dado que mede o raio de alcance — contenção cronometrada sobre trilha real, não suposição.
Log, métrica e trace deixam de exigir disciplina para se correlacionar quando nascem da mesma biblioteca sob o mesmo Resource. Trocar de backend de observação vira reconfigurar o coletor, nunca reinstrumentar a aplicação.
40 alarmes de causa técnica são excesso sem priorização, não falta de monitoramento. Burn rate com duas janelas separa pico transiente de consumo sustentado antes de acionar o plantão — 3 SLOs com orçamento de erro, não alarme por sensação.
Um painel fica verde quando a porta de entrada responde e fica cego quando o negócio parou. 30 gráficos técnicos existem porque a métrica estava disponível — não porque alguém decidiu qual pergunta o painel precisa responder às 3h.
A credencial de deploy deixa de ser algo que existe ENTRE deploys — passa a ser emitida, usada e descartada DENTRO de cada execução. Quem pode publicar é decidido pelo sub/aud da trust policy, não por quem guarda uma chave.
Estado remoto elimina a corrida entre dois apply simultâneos — drift não. Drift só aparece quando alguém pergunta pela API real via terraform plan, e essa pergunta precisa rodar sozinha, agendada, ou ninguém a faz.
Dev e prod não divergem porque alguém errou uma variável — divergem porque existem duas cópias do código Terraform, cada uma editada em separado. A cura não é disciplina, é tornar a cópia estruturalmente impossível.
Alta disponibilidade no desenho é uma afirmação não testada até alguém derrubar a zona de verdade. O cenário pronto do FIS não testa Fargate — testar exige compor a ação certa, com hipótese escrita e SLO como critério de sucesso.
O RTO de um plano de DR não vem da estratégia escolhida no papel — vem de quanto da segunda região já estava de pé antes do desastre. É isso, não o nome, que separa backup/restore, pilot light, warm standby e multi-site ativo-ativo.
Savings Plans comprado sobre o tamanho atual é desconto sobre desperdício assinado por até três anos. Compute Optimizer primeiro, compromisso depois — e Spot só para carga tolerante a interrupção, nunca a API síncrona.
A revisão não descobre risco novo — troca decisões dispersas em 59 laboratórios por um risco alto ou médio por pergunta. O risco mais alto de verdade é o pilar que nenhum dos 59 tratou ainda, não o que teve resposta ruim.
Réplica de leitura reduz carga sobre o primário, mas não reduz contenção: consulta OLTP e OLAP continuam competindo pelo mesmo buffer cache. A solução estrutural é extrair via CDC, não mais réplica nem mais capacidade.
40 mil arquivos no S3 não é problema de volume — é ausência de contrato por camada dizendo se cada arquivo é bruto, limpo ou pronto. Sem esse contrato, toda consulta vira arqueologia. Lake Formation concede acesso por tabela e coluna.
PutRecords devolve 200 mesmo com falha parcial — o erro mora no corpo, não no status. Chave de partição de baixa cardinalidade cria hot shard: throughput do stream inteiro cai ao pior shard, não à soma de todos.
Bytes varridos são decisão de escrita, não de consulta: formato decide quanto de cada arquivo é lido, partição decide quantos arquivos abrem, buffer do Firehose decide se compensa abri-los. Colunar + partição + arquivo saudável.
Schema conhecido só por quem escreveu o script morre quando essa pessoa esquece ou sai. Glue Data Catalog é o metastore central; crawler infere schema mas não é mágico — conflito de tipo entre arquivos exige decisão explícita.
Athena cobra por byte varrido, não por tempo de execução — cada otimização de formato e partição já era otimização de custo. Workgroup com limite corta consulta cara antes de terminar; CTAS materializa scan pesado uma vez só.
Corrigir um registro histórico no data lake em Parquet puro significa reescrever a partição inteira — caro e arriscado. Tabela Iceberg traz transação, UPDATE/DELETE de verdade e consulta a um estado passado sem tocar no presente.
Athena resolve consulta ad-hoc esparsa, não painel executivo com concorrência — 8 widgets, 4 a 40 segundos cada, pior com vários executivos ao mesmo tempo. Redshift Serverless com DISTKEY certo e materialized view tira isso de baixo de 3s.
Catálogo Glue pronto também deixa um analista de BI enxergar CPF e margem de custo por produto — dado que deveria estar restrito por papel. Lake Formation dá permissão fina por coluna e por linha, com teste de negativa provando que o bloqueio funciona.
Um produtor upstream muda a unidade de uma coluna sem avisar, e um pipeline — ou um modelo — aprende silenciosamente sobre números errados. Contrato de dado com Glue Data Quality barra o registro ruim, manda para quarentena e alerta quem produziu.
Um classificador foi publicado em produção sem nunca medir contra as três condições que já decidiam a mesma coisa. Regra como baseline, modelo em modo sombra, log comparativo — e o número real de quem venceu, custo do erro incluído.
Acurácia de 90% no notebook e ruim em produção — a mesma feature calculada duas vezes, de dois jeitos sutilmente diferentes. SageMaker Feature Store centraliza o cálculo num só lugar, consultado do treino e da inferência, com skew medido em zero.
Um modelo treinado num notebook local três meses atrás está em produção e ninguém reproduz o resultado — hiperparâmetro perdido, seed não fixada. Training Job mais Experiments rastreia commit, hash do dado e hiperparâmetro até a métrica.
Endpoint de GPU ligado 24 horas para 200 inferências por dia, espalhadas em poucos horários — o resto é custo parado. Os quatro modos de servir um modelo medidos lado a lado, custo e latência reais, cada um ligado ao consumidor que o pede.
Modelo promovido direto do notebook porque a métrica offline melhorou — e pior em produção, sem versão anterior para voltar. Model Registry, gate de aprovação e rollback exercitado de verdade, com o tempo de volta medido em segundos.
Mesmo com Model Registry pronto, o retreino ainda é disparado à mão, quando alguém lembra — semanas sem retreinar, às vezes com dado incompleto. Pipeline orquestrado, disparado por dado novo, com cache de passo e linhagem completa.
Um modelo serve há dois meses, o log técnico está limpo, e mesmo assim errou — só o negócio percebeu. Model Monitor com baseline distingue drift de dado de drift de conceito, com alarme disparado sobre dado deslocado de propósito.
AUC melhor no teste offline, receita igual em produção — e um segmento inteiro pode estar pior, mascarado pela média. SageMaker Clarify mede viés, teste A/B liga a avaliação a um número de negócio real, não só estatística.
Chamada ao endpoint sem timeout: sob pico ou cold start, ela trava, e a requisição do usuário trava junto — mesmo sendo um score auxiliar. Polly dá timeout, retry, circuit breaker e um caminho degradado explícito, sem travar o cliente.
Notebook ligado 24h, endpoint maior do que o tráfego pede, artefato de treino nunca limpo, GPU ociosa no modo errado — quatro vazamentos, uma fatura. Cost Explorer e Compute Optimizer acham o custo parado, com a métrica do modelo intacta.
Time quer usar um LLM e ninguém sabe onde a chamada mora. Cliente .NET 8 chamando Bedrock via streaming, retry seletivo, IAM escopada ao modelo — não `bedrock:*` — e custo por chamada logado desde a primeira linha.
Prompt editado direto no console para "melhorar" — e a qualidade caiu por dias, sem ninguém achar a causa. Prompt versionado como código, com golden set que reprova a promoção antes de qualquer cliente ver a piora.
LLM plugado direto responde algo plausível e errado, sem indicar de onde tirou — porque não tem acesso ao documento real. RAG recupera o trecho certo primeiro, cita a fonte, e mede a taxa de acerto: 35% virou 92,5%.
Knowledge Bases com OpenSearch Serverless foi escolhido "porque é o padrão da documentação" — nunca comparado. As quatro opções (OpenSearch gerenciado, self-managed, S3 Vectors, pgvector) medidas no mesmo acervo, recall e custo reais.
Os erros residuais do RAG não eram de geração — eram de recuperação: busca vetorial generaliza demais um código de produto exato. BM25 léxico + vetor, fundidos por RRF, com reranking, sobem o acerto sem mudar o LLM de geração.
Guardrail configurado no RAG virou sinônimo de "está seguro" — e 3 de 10 tentativas de contorno testadas passaram. O limite real do controle, com o caso de contorno documentado e a defesa em profundidade que falta.
IAM role ampla "para o agente conseguir agir" e sem teto de voltas — um pedido foi reembolsado três vezes. Uma Lambda e uma IAM role por ferramenta, teto de iteração no código do orquestrador, idempotência antes de qualquer ação real.
Golden set determinístico não avalia geração aberta, e "melhorou" virou impressão de quem leu cinco exemplos. Golden set maior, LLM como juiz com critério explícito, e o viés do próprio juiz medido — não assumido como objetivo.
Fatura de token cresceu 6× num mês: contexto repetido sem cache, modelo caro para tarefa simples, lote síncrono sem desconto de batch. Cache explícito de prompt, modelo por tarefa e Bedrock batch, com a mesma qualidade medida.
Documento do lojista A citado na resposta ao lojista B — filtro de tenant só no prompt, não na busca, e um documento malicioso injetando instrução escondida. Filtro obrigatório na query de recuperação, conteúdo tratado como dado, nunca comando.
Em voz, 3 segundos de silêncio derruba a ligação — latência é requisito que elimina o modelo mais capaz, não um detalhe de infraestrutura. Modelo escolhido pelo prazo, escalonamento para humano instrumentado, não fallback silencioso.
PDF mandado direto pro LLM extrair tudo trocou um valor de nota fiscal e aprovou R$ 45 mil em vez de R$ 1.284,50. Textract extrai o determinístico com confiança por campo; LLM só interpreta; abaixo do limiar, revisão humana no desenho.
Um engenheiro perguntou sobre reembolso e recebeu um dado financeiro confidencial — mesmo índice, times diferentes. Identity Center filtra por permissão da fonte NA recuperação, não no prompt de sistema: a mesma pergunta responde diferente.
"Parafuso 3/4" não achava o produto certo, e a busca ruim derrubava conversão. Recuperação híbrida + rerank decide QUAIS produtos aparecem; geração só apresenta — nunca reordena. Teste A/B mediu 55% de ganho relativo em conversão.
Classificar 2 milhões de itens chamando o Bedrock síncrono, um por um, esbarra em limite de taxa e nunca termina no prazo. Bedrock Batch com Step Functions faz o mesmo trabalho pela metade do custo, numa janela de horas, sem ninguém esperando.
Plantão levanta às 3h para fazer sempre o mesmo roteiro manual: abrir painel, correlacionar métrica, trace e log. Agente com ferramentas SOMENTE-LEITURA por IAM — não por prompt — produz hipótese com evidência, sem poder agir.
O veredito de um reembolso recusado foi sobrescrito, e o log expirou em 14 dias — quando a auditoria perguntou, ninguém reconstruiu a decisão. S3 Object Lock em modo Compliance torna a trilha imutável de verdade: nem admin apaga.
Um job de lote consumiu 91% da cota compartilhada de tokens, e a latência do atendimento em tempo real disparou de 1,8s para 9,7s. Conta por time, cota isolada por Service Quotas, chargeback por LINKED_ACCOUNT — não por tag frágil.
O modelo preferido só existe numa região, e o dado do cliente não pode sair da região dele — os dois requisitos colidem. Route 53 roteia por origem, réplica separada do que pode sair, condição de IAM por região barra o pior caso.
Os 99 laboratórios anteriores viram UM sistema: revisão Well-Architected dos seis pilares sobre o todo, e um Disaster Recovery ensaiado de verdade — RTO e RPO medidos, não estimados, com sustentabilidade honestamente ainda em risco alto.