Como Escalar seu SaaS com AWS: Do MVP a Milhares de Usuários
Estratégias práticas para escalar infraestrutura SaaS na AWS — quando adicionar cada componente, como evitar over-engineering e quanto custa cada fase.
O erro de escalar antes da hora
A maioria dos problemas de escala que vemos não é "meu sistema não aguenta". É "gastei 3 meses construindo infraestrutura para 1 milhão de usuários quando tenho 200".
Escalar antes da hora tem custo: complexidade de operação, custo de infra, tempo de engenharia que poderia estar em produto. A regra correta: escale quando precisar, não quando imaginar que vai precisar.
Este guia mostra o que adicionar e quando.
Fase 0 → Fase 1: Do zero ao MVP (0–1.000 usuários)
A stack que funciona para a maioria dos MVPs SaaS na AWS:
Route 53 (DNS)
└→ CloudFront (CDN + cache de assets)
└→ ALB (Application Load Balancer)
└→ ECS Fargate (1–2 tasks da aplicação)
└→ RDS PostgreSQL db.t4g.medium (1 instância)
└→ ElastiCache Redis cache.t4g.micro
Custo estimado: US$ 150–300/mês.
O que essa stack aguenta: facilmente 500–1.000 usuários simultâneos com latência adequada, desde que as queries do banco sejam eficientes.
Sinais de que você saiu desta fase
- RDS CPU consistentemente > 60%
- Latência P95 > 500ms nas rotas principais
- Conexões ao banco próximas do limite (PostgreSQL padrão: 100 conexões)
- Time reclamando que deploy em produção causa instabilidade
Fase 1 → Fase 2: Crescimento (1.000–50.000 usuários)
Adicione cada componente na ordem que o gargalo aparecer:
1. Connection pooler (semana 1 do problema)
O PostgreSQL tem limite de conexões. Com múltiplas tasks ECS cada uma abrindo um pool, você esgota rápido. PgBouncer (ou RDS Proxy) resolve:
ECS Tasks → RDS Proxy (connection pooling) → RDS PostgreSQL
RDS Proxy é gerenciado pela AWS. Adiciona ~US$ 30–50/mês mas elimina o problema de conexões permanentemente.
2. Read replica (quando queries de leitura dominam)
Se 80% das suas queries são SELECT, uma read replica isola leitura de escrita:
Writes → RDS Primary
Reads → RDS Read Replica (mesmo AZ ou cross-AZ)
No código, use duas connection strings e roteie por tipo de operação. ORMs como Prisma suportam isso nativamente.
Custo: +50–100% do custo do RDS primário.
3. Cache agressivo (antes de escalar o banco)
Redis é mais barato que escalar RDS. Antes de fazer upgrade de instância, implemente cache para:
- Dados de configuração por tenant (mudam raramente)
- Resultados de queries caras com TTL de 1–5 minutos
- Sessões de usuário (se não usar JWT stateless)
- Rate limiting counters
async function getTenantConfig(tenantId: string) {
const cacheKey = `tenant:config:${tenantId}`
const cached = await redis.get(cacheKey)
if (cached) return JSON.parse(cached)
const config = await db.query('SELECT * FROM tenant_configs WHERE tenant_id = $1', [tenantId])
await redis.setex(cacheKey, 300, JSON.stringify(config)) // TTL: 5 minutos
return config
}
4. Auto Scaling no ECS (quando o compute é o gargalo)
Configure o ECS Service para escalar horizontalmente baseado em CPU ou request count:
# Terraform
resource "aws_appautoscaling_policy" "ecs_scale_out" {
name = "ecs-scale-out"
resource_id = "service/${var.cluster_name}/${var.service_name}"
scalable_dimension = "ecs:service:DesiredCount"
target_tracking_scaling_policy_configuration {
target_value = 70 # Mantém CPU em 70%
predefined_metric_specification {
predefined_metric_type = "ECSServiceAverageCPUUtilization"
}
scale_in_cooldown = 300
scale_out_cooldown = 60
}
}
Scale-out em 60 segundos, scale-in conservador em 5 minutos para evitar flapping.
5. Processamento assíncrono (quando operações lentas bloqueiam a API)
Operações que demoram mais de 200ms não devem bloquear o request HTTP:
HTTP Request → API → Publica job na fila SQS/BullMQ → Retorna 202 Accepted
↓
Worker processa job
↓
Webhook ou polling para resultado
Exemplos de candidatos a async: geração de relatórios, envio de e-mails em lote, processamento de arquivos, integração com APIs externas lentas.
Fase 2 → Fase 3: Escala real (50.000+ usuários)
Neste ponto, você tem dados suficientes para otimizar com precisão. Os padrões que mais aparecem:
Multi-AZ e alta disponibilidade
us-east-1a: ECS Tasks + RDS Primary
us-east-1b: ECS Tasks + RDS Standby (failover automático)
us-east-1c: ECS Tasks
ALB distribui tráfego entre os três AZs automaticamente.
RDS Multi-AZ tem failover automático em ~30 segundos sem perda de dados. Para SaaS com SLA de 99.9%, é indispensável.
Aurora PostgreSQL para workloads de leitura intensiva
Aurora escala reads horizontalmente com até 15 replicas de leitura e latência de replicação < 10ms. Se você tem dashboard de analytics acessado por muitos usuários simultaneamente, Aurora resolve com uma mudança de connection string.
Separar banco de analytics do banco operacional
Queries OLAP (relatórios, dashboards) têm padrões de acesso completamente diferentes de queries OLTP (operações do produto). Rodar as duas no mesmo banco gera contenção.
Solução: stream de eventos com Kafka → ClickHouse para analytics. O banco operacional fica para o produto, o ClickHouse aguenta bilhões de linhas com queries sub-segundo.
Observabilidade com OpenTelemetry
Em escala, você não consegue mais debugar no console. Implemente traces distribuídos:
import { NodeTracerProvider } from '@opentelemetry/sdk-node'
import { OTLPTraceExporter } from '@opentelemetry/exporter-otlp-http'
// Cada request recebe um trace_id que percorre toda a stack
// API → Worker → Banco → Cache → APIs externas
Com Grafana Tempo ou Datadog APM, você vê exatamente onde um request lento está gastando tempo.
Quanto custa cada fase
| Fase | Usuários | Infra AWS/mês | Principais componentes | |---|---|---|---| | MVP | 0–1.000 | US$ 150–300 | ECS Fargate, RDS t4g.medium, Redis t4g.micro | | Crescimento | 1k–50k | US$ 800–3.000 | + RDS Proxy, Read Replica, Auto Scaling | | Escala | 50k–500k | US$ 3.000–15.000 | + Multi-AZ, Aurora, ClickHouse | | Enterprise | 500k+ | US$ 15.000+ | + Multi-região, Global Accelerator |
Esses números assumem workload típico de SaaS B2B (não streaming de vídeo ou ML em tempo real).
Os 3 gargalos mais comuns e como resolver
1. Banco de dados lento
Diagnóstico com pg_stat_statements:
SELECT query, calls, mean_exec_time, total_exec_time
FROM pg_stat_statements
ORDER BY total_exec_time DESC
LIMIT 20;
As 20 queries mais lentas quase sempre revelam índices faltando ou N+1 queries.
2. Memória insuficiente no ECS
Se as tasks reiniciam frequentemente ou você vê OOM (Out of Memory) nos logs do CloudWatch: aumente a memória da task definition. ECS Fargate cobra por CPU + memória — mais memória nem sempre sai caro.
3. Custo crescendo mais rápido que usuários
Analise com AWS Cost Explorer por serviço. Os culpados mais comuns: NAT Gateway (tráfego de saída de subnets privadas) e transferência de dados entre AZs. Use VPC Endpoints para serviços AWS (S3, DynamoDB) para eliminar custo de NAT.
Precisa de uma avaliação da sua infraestrutura AWS ou quer planejar a próxima fase de escala?
Solicitar auditoria de infra → · Guia completo de infraestrutura Cloud AWS → · Falar com especialista →
Precisa de ajuda com cloud & infraestrutura?
A Codevops transforma ideias em produtos reais. Cuidamos de toda a parte técnica para que você foque no seu negócio. Respondemos em até 12 horas.
Falar com especialista →