O desconto que você não estava usando - por que Spot e Graviton são baratos
A fatura da AWS estourou o orçamento por dois meses seguidos. Ao procurar recursos para cortar, descobri que a verdadeira alavanca não era 'quanto usar', mas 'como comprar'. Por que Spot e Graviton são baratos, e por que existe um custo que parece desperdício mas não pode ser desligado (RDS Proxy) - a história do 'porquê' por trás de cada número da fatura.
Resumo
Quando mandam cortar a fatura da nuvem, a mão vai direto para 'o que desligar', mas se os recursos já estão otimizados, a alavanca que sobra é a forma de pagamento. O Fargate Spot é a AWS liquidando capacidade ociosa sob a condição de 'posso retomar em 2 minutos', por isso é 70% mais barato (e por ser condicional, fica restrito ao staging). Já o Graviton é um chip ARM desenhado pela própria AWS, sem margem de intermediário, por isso é 20% mais barato (e por não ter condição, vai até a produção). Por outro lado, existem custos como o RDS Proxy que parecem desperdício mas são, na verdade, um seguro contra picos de conexão. Ler a fatura não é cortar números - é entender o motivo de cada um: aproveitar os descontos cujas condições você consegue bancar, e manter os custos que evitam incidentes.
Nesta página
A fatura da AWS estourou o orçamento por dois meses seguidos. O custo real ficou acima do limite mensal por uma margem de um dígito percentual - não era um valor alto em termos absolutos, mas a tendência era de alta. Fui revisando os recursos um a um em busca de algo para cortar, e a conclusão foi inesperada: quase não havia mais recurso para reduzir. A verdadeira alavanca não estava em "quanto usar", mas em "como comprar". O que aprendi nesse processo foi que cada número da fatura tem um motivo, e só entendendo esse motivo dá para decidir o que desligar e o que manter.
Os recursos já estavam enxutos
Primeiro olhei o volume de uso. Só que essa parte já tinha recebido bastante atenção. O NAT gateway já tinha sido eliminado em favor de uma sub-rede pública, os logs eram retidos por só 7 dias, o tracing usava amostragem de 1%, e o dashboard de observabilidade estava encaixado dentro do limite gratuito. O banco de dados e o Redis já rodavam em instâncias ARM mais baratas, o S3 tinha tiering automático, e o bastion só subia quando necessário. Praticamente tudo que dava para espremer em nível de recurso já tinha sido espremido.
A fatura de junho, por item, ficou assim: o maior item sozinho era o banco de dados (RDS), com cerca de 40% do total, seguido pelo compute (ECS Fargate) com cerca de 17%, load balancer e WAF empatados com cerca de 10% cada, e IP público, cache (ElastiCache) e S3 fechando a lista com percentuais de um dígito cada. Reduzir ainda mais o tamanho das instâncias aqui seria um retrocesso - o banco já tinha um histórico de ter sido aumentado por falta de memória, e o WAF estava ali de propósito para validar regras antes de cada deploy em produção. A alavanca que sobrava não era o recurso, era a forma de pagamento. Continuar usando o mesmo recurso, só que comprando mais barato.
Por que o Spot é barato
A primeira coisa que chamou atenção foi que todo o compute estava sendo comprado no preço cheio de on-demand. A AWS tem um canal para vender o mesmo servidor bem mais barato: o Fargate Spot. É cerca de 70% mais barato que o on-demand.
Esse preço baixo tem um motivo. A AWS constrói seus data centers para atender ao pico de demanda. No dia a dia, sobra servidor ocioso. Deixar essa capacidade parada gera receita zero, então a AWS vende essa sobra por um preço baixíssimo, sob a condição de "se um cliente de preço cheio aparecer, você libera em 2 minutos". É o mesmo princípio de uma companhia aérea liquidando assentos vazios pouco antes da decolagem: se o avião vai decolar vazio mesmo, a receita é zero de qualquer jeito, então vender com uma condição atrelada ainda é lucro.
A questão central é se dá para bancar essa condição - "libera se pedirem". Em produção, é complicado: se há usuários conectados e a tarefa é retomada em 2 minutos, o serviço treme, ainda que brevemente. Mas o staging é diferente: não há usuário real, e ficar alguns minutos fora do ar só incomoda um QA por um instante. Por isso movi a API do staging para o Spot. O desempenho é idêntico ao do on-demand, porque roda no mesmo hardware, com o mesmo vCPU e a mesma memória. A única coisa que muda é a condição de disponibilidade - "pode ser retomado" - e essa é uma condição que o staging aceita de bom grado. Depois de aplicar, as tarefas do staging passaram a rodar normalmente sobre o Spot.
Por que o Graviton é barato
O segundo ponto foi o chip do compute. O banco de dados e o Redis já usavam instâncias ARM, mas o Fargate que roda a aplicação em si ainda estava no x86. Migrando para o Graviton, o chip ARM desenhado pela própria AWS, dá para ter o mesmo desempenho por cerca de 20% a menos.
O motivo desse preço menor é diferente do caso do Spot. Numa instância comum, a AWS compra o CPU da Intel ou da AMD, então o valor que pagamos já embute a margem do fabricante do chip. O Graviton é um chip desenhado pela própria AWS, então essa margem intermediária não existe. Além disso, a arquitetura ARM consome menos energia e gera menos calor para realizar a mesma operação, o que reduz também o custo de eletricidade e resfriamento do data center. Do ponto de vista da AWS, o custo é menor, então vender com 20% de desconto ainda dá lucro - e é também uma estratégia para atrair clientes para o próprio ecossistema de chips.
A diferença importante está aqui: o desconto do Spot vem com a condição de "aceitar ser retomado", mas o desconto do Graviton não tem condição nenhuma. É simplesmente um chip mais barato. Por isso o Spot só pode ser usado no staging, enquanto o Graviton se aplica até em produção. E há pouco com que se preocupar em termos de desempenho: o Node.js tem desempenho por vCPU no Graviton equivalente ou até superior ao x86. O único ponto de atenção é o cold start - na primeira subida do app, a velocidade de núcleo único importa, e aí o Graviton pode ser um pouco mais lento que um x86 recente, adicionando alguns segundos à inicialização. Por isso a ordem foi: medir o tempo de inicialização primeiro no staging, para só depois promover para produção. A única checagem prévia necessária é confirmar se os módulos nativos têm build para arm64.
Resumindo a natureza dos dois descontos: o do Spot é a recompensa por aceitar o incômodo, por isso vem com condição (e fica restrito ao staging); o do Graviton é a vantagem de custo do próprio chip da AWS repassada ao cliente, por isso não tem condição (e vai até a produção). Com o mesmo desempenho, não havia razão para continuar pagando o preço cheio do x86. Na prática, essa otimização não foi tanto economizar algo novo, mas sim começar a receber, só agora, um desconto que já existia e não estava sendo aproveitado.
Também existe custo que não pode ser desligado
Só que, ao vasculhar a fatura, também existe uma armadilha na direção oposta: itens que parecem desperdício, mas na verdade são um seguro.
O RDS Proxy era um desses casos. Tinha um custo mensal fixo, e à primeira vista parecia candidato a corte. Uma das funções do Proxy é fazer a rotação automática de secrets sem downtime, e essa rotação estava desligada. Sem usar a rotação, por que manter o Proxy?
Isso era uma leitura errada. O propósito original do Proxy não é a rotação, é conter picos de conexão. Quando um deploy ou um scale-out aumenta de repente o número de tarefas, as conexões para o banco disparam junto - e o banco tem um limite de conexões simultâneas. O Proxy fica na frente, agrupa e multiplexa essas conexões para não ultrapassar esse limite. E justamente esse banco era uma instância que já tinha um histórico de ter sido aumentada por falta de memória, e cada conexão consome memória. Ou seja, aquele custo fixo não era desperdício - era o prêmio do seguro que impede o banco de cair por excesso de conexões a cada deploy. Desligar aquilo não seria economizar, seria retirar a proteção.
A origem da leitura errada foi um comentário no código. O comentário que descrevia o Proxy estava escrito quase todo sob a ótica da rotação, o que levava quem lia a concluir, por engano, que "se a rotação está desligada, o Proxy também é desnecessário". Por isso, em vez de tirar o Proxy do plano de corte, adicionei uma linha ao comentário: "o propósito principal é conter picos de conexão; a rotação é um recurso adicional." Para que a próxima pessoa a olhar a fatura não caia no mesmo engano.
Cada número da fatura tem um motivo
Quando mandam reduzir o custo da nuvem, a mão vai direto para "o que desligar". Diminui instância, desliga funcionalidade, apaga recurso. Mas o que aprendi dessa vez foi o oposto: antes de cortar, a pergunta é "por que esse número está aqui".
Alguns números são descontos não aproveitados. Como o Spot e o Graviton, existe um canal para comprar o mesmo recurso mais barato, e simplesmente se estava pagando o preço cheio. Cada um desses descontos tem seu próprio motivo de ser barato, e entender esse motivo - se é aceitar ser retomado, ou se é uma vantagem de custo sem condição - é o que define onde aplicar com segurança. Outros números, ao contrário, são um seguro que não pode ser desligado. Mesmo parecendo desperdício, se aquilo está evitando um incidente, aquela linha não é gasto, é defesa.
No fim, ler a fatura não é tornar os números menores - é entender o motivo de cada um. Entendendo o motivo, dá para aproveitar os descontos cujas condições você consegue bancar e manter os custos que evitam incidentes. Foi só isso que fizemos: não economizamos algo novo, apenas separamos o desconto a receber do seguro a manter.
Perguntas frequentes
Dá para usar o Fargate Spot em produção?
O trade-off do Spot é que a tarefa pode ser retomada após um aviso de 2 minutos. Se o ambiente consegue absorver essa interrupção, pode ser usado até em produção. Numa configuração de alta disponibilidade com várias tarefas, onde uma redução de capacidade por alguns minutos não é crítica, dá para aplicar parcialmente. Mas se for uma tarefa única ou uma carga sensível a interrupções, é arriscado - o mais seguro é começar pelo staging, onde uma interrupção é inofensiva.
Migrar para o Graviton (ARM) não derruba o desempenho?
Na maioria das cargas de trabalho o desempenho é equivalente ou até melhor. Em especial o Node.js tem desempenho por vCPU equiparável ao x86 no Graviton. O único ponto de atenção é o cold start: quando o app sobe pela primeira vez, a velocidade de núcleo único é um pouco menor que a de um x86 recente, o que pode adicionar alguns segundos à inicialização. Basta medir esse tempo de inicialização no staging antes de promover para produção, e verificar antecipadamente se os módulos nativos têm build para arm64.
Artigos relacionados
- 💻 Dev
Quando um bucket tem dois donos, ganha quem fez apply por último
Adicionei uma regra de lifecycle no S3 e o terraform apply falhou. A causa: duas resources eram donas, cada uma por conta própria, da configuração de lifecycle do mesmo bucket. O lifecycle do S3 não funciona por regra, e sim por documento inteiro, então o último vencedor apaga em silêncio as regras do outro.
- 💻 Dev
Os testes estavam verdes, mas nenhuma notificação tinha sido enviada
O código que enfileirava os jobs falhava sempre, desde o primeiro dia. O erro era engolido, e os testes seguiam verdes graças aos mocks. A história de como um único caractere de dois-pontos matou três funcionalidades em silêncio.
- 💻 Dev
Chegou um alerta dizendo que o banco tinha caído. O banco nunca caiu
Em um único dia acumularam-se quatro alertas CRITICAL. 504, P2028 do Prisma, 500 no admin e 'serviço DATABASE fora do ar'. Abri primeiro as métricas do RDS: durante 21 horas seguidas, a CPU não passou de 19,7%. O lento não era o banco, eram as idas e voltas atravessando o Atlântico vinte e cinco vezes - e o alerta de 'fora do ar' foi o próprio health check que o fabricou.