Pular para conteúdo

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:

  1. 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.
  2. Celery com --concurrency=2 — o processamento de mensagens (bot, pesquisas, respostas via API da Meta) faz no máximo ~200–350 msgs/min.
  3. 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
gunicorn app.asgi:application -k uvicorn.workers.UvicornWorker \
  -w 3 --bind 0.0.0.0:8000 --timeout 120
  • 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) e campanhas (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
celery -A app worker -Q mensagens --concurrency=3 ...
celery -A app worker -Q campanhas --concurrency=2 ...
  • 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 volume static_volume) em vez de proxy ao backend — tira carga do processo Python.
  • Conferir gzip on para 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 stats e loga/notifica).
  • Rotação de logs do app (backend/logs/app.log guarda 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