"Precisamos aguentar 100.000 usuários simultâneos." Parece claro, mas o que isso significa tecnicamente? Quantos requests por segundo? Quantas conexões? Quanto de CPU? A tradução de métricas de negócio para carga técnica é uma das habilidades mais importantes — e mais mal executadas — em performance engineering.
Usuários simultâneos é métrica de negócio. Requests por segundo é métrica técnica. Saber traduzir entre elas é essencial.
O Problema da Tradução
Ambiguidade de "usuários"
O que "100K usuários" pode significar:
1. Usuários registrados: 100K contas
→ Relevância para carga: zero
2. Usuários ativos/mês (MAU): 100K
→ Talvez 10% online em pico
3. Usuários ativos/dia (DAU): 100K
→ Talvez 20% online em pico
4. Usuários simultâneos: 100K
→ Conectados ao mesmo tempo
5. Usuários fazendo ações: 100K
→ Gerando requests agora
A diferença prática
Cenário: "100K usuários ativos"
Interpretação errada:
100K usuários × 1 req/s = 100K req/s
(usuário não faz 1 request por segundo)
Interpretação correta:
100K usuários online
÷ 30s entre ações (think time)
= 3.333 req/s
Diferença: 30x
Modelo de Carga: Little's Law
A fórmula fundamental
L = λ × W
Onde:
L = Número de requests concorrentes (em processamento)
λ = Taxa de chegada (requests/segundo)
W = Tempo médio de processamento (segundos)
Exemplo:
λ = 100 req/s
W = 0.2s (200ms)
L = 100 × 0.2 = 20 requests simultâneos
Aplicação inversa
Se você sabe:
- Quantos usuários online: U
- Think time médio: T (segundos entre ações)
- Ações por sessão: A
Taxa de requests = U × A / T
Exemplo:
U = 10.000 usuários online
T = 30s think time
A = 1 (uma ação)
Taxa = 10.000 × 1 / 30 = 333 req/s
Modelando Comportamento Real
Funil de conversão
Entrada: 100K visitantes/hora
Funil:
Home page: 100K (100%)
Listagem: 70K (70%)
Produto: 50K (50%)
Add cart: 10K (10%)
Checkout: 5K (5%)
Pagamento: 4K (4%)
Requests por endpoint:
GET / : 100K/h = 28 req/s
GET /products : 70K/h = 19 req/s
GET /product/:id: 50K/h = 14 req/s
POST /cart : 10K/h = 3 req/s
GET /checkout : 5K/h = 1.4 req/s
POST /payment : 4K/h = 1.1 req/s
Total: ~66 req/s
Múltiplos requests por página
Página de produto carrega:
- HTML: 1 request
- API produto: 1 request
- API relacionados: 1 request
- API reviews: 1 request
- Imagens: 5 requests
- JS/CSS: 3 requests
Total: 12 requests por page view
Se 50K page views/hora:
50K × 12 = 600K requests/hora
= 167 req/s (não 14 req/s!)
Think time realista
Distribuição de think time (segundos):
Ação | Média | p50 | p95
------------------|-------|-----|-----
Ler página home | 15 | 10 | 60
Navegar listagem | 20 | 15 | 90
Analisar produto | 45 | 30 | 180
Decidir compra | 60 | 45 | 300
Preencher checkout| 120 | 90 | 400
Não use valores fixos!
Use distribuição (log-normal funciona bem)
Calculadora de Carga
Template de cálculo
## Cálculo de Carga - [Sistema]
### Premissas de Negócio
- Usuários ativos no pico: 50.000
- Sessão média: 10 minutos
- Think time médio: 30 segundos
- Ações por sessão: 20
### Cálculo Base
Taxa de ações = 50.000 / 30 = 1.667 ações/s
### Por Endpoint (baseado em analytics)
| Endpoint | % tráfego | req/s |
|----------|-----------|-------|
| GET /api/products | 40% | 667 |
| GET /api/product/:id | 30% | 500 |
| POST /api/cart | 15% | 250 |
| GET /api/checkout | 10% | 167 |
| POST /api/payment | 5% | 83 |
### Multiplicadores
- Cache misses (30%): +500 req/s ao DB
- Retries (5%): +83 req/s total
- Healthchecks: +10 req/s
### Carga Total Estimada
- API: 1.667 req/s
- DB queries: 2.500 req/s
- Cache ops: 4.000 req/s
### Margem de Segurança (2x)
- Target: 3.334 req/s sustentado
- Pico: 5.000 req/s por 5 minutos
Script de cálculo
def calculate_load(
active_users: int,
think_time_seconds: float,
session_duration_minutes: float,
pages_per_session: float,
requests_per_page: float,
safety_margin: float = 2.0
) -> dict:
"""
Calcula carga técnica a partir de métricas de negócio
"""
# Taxa base de page views
page_views_per_second = active_users / think_time_seconds
# Taxa de requests (incluindo assets, APIs, etc)
requests_per_second = page_views_per_second * requests_per_page
# Concurrent requests (Little's Law)
avg_response_time = 0.2 # assumindo 200ms
concurrent_requests = requests_per_second * avg_response_time
return {
"page_views_per_second": round(page_views_per_second, 1),
"requests_per_second": round(requests_per_second, 1),
"concurrent_requests": round(concurrent_requests, 1),
"target_with_margin": round(requests_per_second * safety_margin, 1),
"peak_capacity": round(requests_per_second * safety_margin * 1.5, 1)
}
# Exemplo
result = calculate_load(
active_users=50000,
think_time_seconds=30,
session_duration_minutes=10,
pages_per_session=20,
requests_per_page=8
)
print(result)
# {
# 'page_views_per_second': 1666.7,
# 'requests_per_second': 13333.3,
# 'concurrent_requests': 2666.7,
# 'target_with_margin': 26666.7,
# 'peak_capacity': 40000.0
# }
Validando o Modelo
Comparar com produção
-- Pico de requests por segundo
SELECT
date_trunc('minute', timestamp) as minute,
count(*) / 60.0 as rps
FROM access_logs
WHERE timestamp > now() - interval '7 days'
GROUP BY 1
ORDER BY rps DESC
LIMIT 10;
-- Pico de usuários únicos por minuto
SELECT
date_trunc('minute', timestamp) as minute,
count(distinct user_id) as unique_users
FROM access_logs
WHERE timestamp > now() - interval '7 days'
GROUP BY 1
ORDER BY unique_users DESC
LIMIT 10;
Calcular ratio real
-- Requests por usuário ativo
WITH hourly AS (
SELECT
date_trunc('hour', timestamp) as hour,
count(*) as requests,
count(distinct user_id) as users
FROM access_logs
WHERE timestamp > now() - interval '7 days'
GROUP BY 1
)
SELECT
avg(requests::float / nullif(users, 0)) as req_per_user_hour,
avg(requests::float / nullif(users, 0) / 3600) as req_per_user_second
FROM hourly;
Armadilhas Comuns
1. Ignorar o funil
❌ "100K usuários × 10 req/s = 1M req/s"
✅ Modelar o funil:
100K visualizam home
30K veem produto
3K fazem checkout
→ Requests variam por etapa
2. Think time de robô
❌ "Virtual user faz request, espera 1s, faz request"
✅ Think time realista:
Média 30s, distribuição log-normal
Varia por tipo de página
3. Esquecer requests internos
❌ "Calculei só requests da API"
✅ Incluir:
- Service-to-service calls
- DB queries por request
- Cache operations
- Background jobs triggered
4. Pico = Média
❌ "Média de 1000 req/s, vou testar 1000"
✅ Modelar picos:
Pico pode ser 3-5x a média
Testar para pico, não média
Exemplo Completo
Cenário: Black Friday
## Planejamento de Capacidade - Black Friday
### Histórico
- Black Friday 2023: 80K usuários pico
- Crescimento projetado: 50%
- Target 2024: 120K usuários pico
### Modelo de Carga
**Usuários ativos no pico**: 120.000
**Distribuição por jornada**:
| Jornada | % | Usuários | Think time | Req/s |
|---------|---|----------|------------|-------|
| Browse | 60% | 72K | 20s | 3.600 |
| Search | 25% | 30K | 15s | 2.000 |
| Checkout | 15% | 18K | 45s | 400 |
**Total base**: 6.000 req/s
**Multiplicadores**:
- Requests por página: ×8 = 48.000 req/s
- Cache miss (40%): +19.200 DB queries/s
- Margin (2x): 96.000 req/s
### Requisitos de Infraestrutura
- API servers: 96K / 2K per instance = 48 instances
- DB connections: 19.2K × 0.1s = 1.920 concurrent
- Cache: 48K × 0.01s = 480 concurrent ops
### Teste de Validação
- Carga sustentada: 50K req/s por 2h
- Pico: 100K req/s por 15min
- Spike: 150K req/s por 1min
Conclusão
Traduzir usuários em carga requer:
- Entender o que "usuários" significa no contexto
- Modelar o funil de comportamento
- Calcular think time realista
- Incluir todos os requests (não só API principal)
- Validar contra dados reais de produção
- Aplicar margem de segurança para picos
O número de usuários é o input. O número de requests é o output. A matemática no meio é o que separa sucesso de fracasso.
Este artigo faz parte da série sobre a metodologia OCTOPUS de Performance Engineering.