Capacidade e Performance — Extraindo o Máximo do VPS Atual¶
Data da análise: 2026-08-18 · Baseada em medições reais em produção (specs do host, configuração dos serviços, sondagem de latência) — não em estimativas genéricas.
1. Sumário executivo¶
O VPS atual (4 vCPU, 15GB RAM) está superdimensionado para a configuração atual do software. O hardware usa ~5% da capacidade; os tetos de hoje vêm de três escolhas de configuração, todas ajustáveis sem custo:
| Hoje | Após Fase 1 (config) | Após Fase 2 (código leve) | |
|---|---|---|---|
| Atendentes ativos simultâneos | ~30–50 | ~100+ | ~150+ |
| Conversas WhatsApp ativas (bot respondendo em segundos) | ~100–200 | ~400–600 | ~800+ |
| Gargalo dominante | 1 processo ASGI | Celery/API da Meta | os 4 vCPUs |
Os três limitadores, por ordem de impacto:
- Backend em um único processo daphne — views síncronas do Django sob ASGI executam serializadas; na prática ~10–20 req/s sustentados para views reais.
- Celery com
--concurrency=2— o processamento de mensagens (bot, pesquisas, respostas via API da Meta) faz no máximo ~200–350 msgs/min. - Throttle de 1000 req/hora por usuário — morde um atendente ativo antes de a infraestrutura sentir qualquer coisa.
2. Diagnóstico medido (2026-08-18)¶
Host e containers¶
| Recurso | Valor | Uso em repouso |
|---|---|---|
| vCPU | 4 | < 5% |
| RAM | 15GB (11GB disponíveis) | backend 94MB · postgres 90MB · redis 5MB |
| Disco | 193GB (178GB livres) | banco: 14MB |
| Postgres | max_connections=100, shared_buffers=256MB | ~6 conexões em uso |
| Redis | maxmemory 512MB, allkeys-lru | 5MB |
Medições de latência (produção, carga leve)¶
/health(view leve, DB+cache): p50 14ms, p95 19ms.- 100 requisições com concorrência 10: ~133 req/s — teto do processo único para views triviais. Views reais (inbox, supervisão: 50–100ms) ⇒ ~10–20 req/s sustentados.
Arquitetura de processamento (pontos fortes já corretos ✓)¶
- Webhook da Meta só valida HMAC e enfileira (
process_meta_webhook.delay) — responde em milissegundos, atende o limite de 3s da Meta e aguenta rajadas. - Tempo real via WebSocket (channels/Redis, capacity 1500) — conexões ociosas são baratas; centenas de agentes conectados não é problema.
- Ondas de performance já aplicadas: N+1 eliminados, índices B-tree, bulk operations em campanhas, envios em lote via Celery,
CONN_MAX_AGE=600.
3. Plano de otimização por camada¶
Cada item traz ganho estimado, risco e esforço. Nada aqui exige trocar de VPS.
Fase 1 — Só configuração (maior ganho, ~1h de trabalho, risco baixo)¶
1.1 API: múltiplos workers ASGI (o ajuste mais importante)¶
Trocar o daphne único por gunicorn com 3 workers uvicorn (uvicorn atende HTTP e WebSocket):
| Text Only | |
|---|---|
- Ganho: ~3x na capacidade de API (cada worker tem seu próprio event loop e executor de views síncronas). RAM: +~200MB (sobrando 11GB).
- Por que 3 e não 4: deixa 1 vCPU folgado para Postgres/Redis/Celery.
- Risco: baixo; validar WebSocket (inbox/supervisão) após a troca. Alternativa equivalente: N processos daphne atrás de um upstream no nginx.
1.2 Celery: subir a concorrência e separar filas¶
--concurrency=2→ 4 (RAM disponível; o trabalho é I/O-bound na API da Meta, então mais workers = mais respostas em paralelo).- Separar filas:
mensagens(webhook/bot — latência importa) ecampanhas(volume — pode esperar). Hoje uma campanha grande na frente da fila atrasa a resposta do bot para quem está conversando. Dois workers dedicados resolvem:
| Text Only | |
|---|---|
- Ganho: ~2x no throughput de mensagens e bot imune a filas de campanha.
1.3 Throttle: não punir atendente ativo¶
user: 1000/hour (~16 req/min) é apertado para operação intensa de inbox. Recomendação: escopo separado — user: '120/min' para autenticados (ainda protege contra abuso) mantendo anon: 100/hour e login: 5/min como estão.
1.4 Nginx: estáticos e compressão¶
- Servir
/static/direto do nginx (alias para o volumestatic_volume) em vez de proxy ao backend — tira carga do processo Python. - Conferir
gzip onpara JSON/HTML e cache longo para/_next/static/(hash no nome ⇒Cache-Control: immutable). - Ganho: menor uso de CPU do backend por request; páginas mais rápidas.
Fase 2 — Código leve (dias, risco baixo-médio)¶
2.1 Cache de agregações quentes (Redis)¶
KPIs do topo da inbox, dashboard e supervisão fazem agregações a cada acesso. Com 30+ atendentes, isso vira a maior carga de leitura. Cachear no Redis com TTL curto (10–30s) — o dado é "quase tempo real" e o custo cai para ~zero. Ganho: grande redução de CPU/DB nos horários de pico de equipe.
2.2 Batch/debounce de broadcasts WebSocket¶
Em pico de mensagens, cada evento gera broadcast para todos os supervisores. Agrupar atualizações num intervalo de ~1s reduz fan-out sem perda perceptível.
2.3 Índices Postgres pendentes (do DEPLOY.md §6)¶
GIN + pg_trgm para busca textual (Contact.name, Product.name) e GIN em MessageLog.payload — aplicar via migração com AddIndexConcurrently (atomic=False). Só importa quando a base crescer (>50k contatos/mensagens); com 14MB de banco é irrelevante, mas deixar pronto evita surpresa.
Fase 3 — Disciplina de crescimento (contínuo)¶
- Teste de carga em staging antes de prometer números em contrato (k6/locust simulando: N atendentes × M conversas × campanhas). É o único jeito honesto de transformar estimativa em garantia.
- Observabilidade mínima: Sentry já integrado ✓; adicionar alerta simples de CPU/RAM/fila do Celery (ex.: cron que checa
celery inspect active+docker statse loga/notifica). - Rotação de logs do app (
backend/logs/app.logguarda meses; rotação já configurada — conferir se o limite de 10MB×5 está ativo de fato). - Quando o VPS virar o limite de verdade (CPU >70% sustentado na Fase 2): aí sim, upgrade de vCPU — a arquitetura atual escala verticalmente sem mudanças até ~8 vCPUs.
4. O que não vale a pena fazer agora¶
- Tuning agressivo de Postgres — o banco tem 14MB e usa 90MB de RAM; os parâmetros atuais (256MB shared_buffers etc.) já são generosos.
- Réplicas / load balancer / Kubernetes — complexidade sem retorno nesta escala; o VPS atual aguenta uma ordem de magnitude a mais com as Fases 1–2.
- Trocar Redis/broker — 5MB usados de 512MB; irrelevante.
- Microsserviços — o monólito atual é o desenho certo para este tamanho.
5. Limites externos (independem do VPS)¶
- API da Meta: limite de tier do número (mensagens business-initiated/dia), ~80 msgs/s por par e janela de 24h. Em campanhas grandes, o teto pode ser da Meta, não do servidor. O design atual (fila + retry) já respeita isso.
- Latência da Meta (~0,3–0,8s por envio) domina o tempo de resposta do bot — mais workers Celery compensam com paralelismo, mas o piso por mensagem é esse.
6. Estimativas honestas — e suas ressalvas¶
Os números deste relatório vêm de: specs reais, configuração lida do código, medição leve em produção e aritmética de capacidade. Não substituem teste de carga. Use-os para planejamento interno; para compromisso contratual com um cliente grande, rode a Fase 3 (staging + k6) antes.
| Cenário | Estimativa |
|---|---|
| Hoje (Highlas: 7 usuários, 88 contatos) | ~5% da capacidade em uso |
| Config atual, pico teórico | ~30–50 atendentes + ~100–200 conversas ativas |
| Fase 1 aplicada | ~100 atendentes + ~400–600 conversas ativas |
| Fase 1+2 aplicadas | ~150 atendentes + ~800 conversas; gargalo = 4 vCPUs |