Pular para o conteúdo principal

Desempenho e Escalabilidade

Arquitetura de Desempenho

Componentes Implementados

Sistema de Cache Multicamadas:

  • Redis 7.2: Cache distribuído para dados de sessão e consultas frequentes
  • Django Cache Framework: Cache de views e fragmentos de template
  • Vite: Otimização e compressão de arquivos estáticos

Processamento Assíncrono:

  • Celery: Processamento de tarefas em segundo plano
  • Redis como broker: Fila de mensagens para tarefas
  • Celery Beat: Agendamento de tarefas periódicas

Banco de Dados Otimizado:

  • PostgreSQL 14: Banco relacional principal
  • Índices estratégicos: Campos de busca frequente indexados
  • Pool de conexões: Django connection pooling configurado

Estratégias de Escalabilidade

Infraestrutura com Kubernetes

Recursos de Orquestração Disponíveis:

  • Escalonamento horizontal automático: Ajuste dinâmico de pods baseado em demanda
  • Balanceamento de carga: Distribuição equilibrada entre instâncias
  • Implantações sem interrupção: Rolling updates para atualizações contínuas
  • Gestão de configurações: ConfigMaps e Secrets centralizados
  • Monitoramento de saúde: Liveness e readiness probes

Containerização com Docker

Estrutura de Contêineres:

# docker-compose.yml (ambiente de desenvolvimento)
services:
backend:
build: ./backend
environment:
- DJANGO_SETTINGS_MODULE=config.settings
depends_on:
- postgres
- redis

frontend:
build: ./frontend
environment:
- VITE_API_URL=http://backend:8000

postgres:
image: postgres:14-alpine
volumes:
- postgres_data:/var/lib/postgresql/data

redis:
image: redis:7.2-alpine
volumes:
- redis_data:/data

celery:
build: ./backend
command: celery -A config worker -l info
depends_on:
- redis
- postgres

minio:
image: minio/minio:latest
command: server /data --console-address ":9001"
volumes:
- minio_data:/data

Otimização de Banco de Dados

Estratégias Implementadas no PostgreSQL

Pool de Conexões Django:

# settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'portal_talentos',
'CONN_MAX_AGE': 600, # Conexões persistentes por 10 minutos
'OPTIONS': {
'connect_timeout': 10,
}
}
}

Índices Criados:

-- Índices para busca de candidatos
CREATE INDEX idx_candidates_cpf ON candidates_candidate(cpf);
CREATE INDEX idx_candidates_user ON candidates_candidate(user_id);

-- Índices para processos seletivos
CREATE INDEX idx_selective_process_company ON job_vacancies_selectiveprocess(company_id);
CREATE INDEX idx_selective_process_status ON job_vacancies_selectiveprocess(status);

-- Índices para candidaturas
CREATE INDEX idx_submission_candidate ON job_vacancies_candidatesubmission(candidate_id);
CREATE INDEX idx_submission_process ON job_vacancies_candidatesubmission(selective_process_id);
CREATE INDEX idx_submission_score ON job_vacancies_candidatesubmission(ai_score);

Otimizações do Django ORM

Uso de select_related e prefetch_related:

# views.py - Exemplo de otimização
class SelectiveProcessViewSet(viewsets.ModelViewSet):
def get_queryset(self):
return SelectiveProcess.objects.select_related(
'company',
'company__user'
).prefetch_related(
'stages',
'submissions__candidate__user',
'submissions__candidate__academic_formations'
).annotate(
submission_count=Count('submissions'),
avg_score=Avg('submissions__ai_score')
)

Paginação de Resultados:

# pagination.py
from rest_framework.pagination import PageNumberPagination

class StandardResultsSetPagination(PageNumberPagination):
page_size = 20
page_size_query_param = 'page_size'
max_page_size = 100

Estratégia de Cache

Cache com Redis e Django

Configuração do Redis:

# settings.py
CACHES = {
'default': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': 'redis://redis:6379/1',
'OPTIONS': {
'CLIENT_CLASS': 'django_redis.client.DefaultClient',
'PARSER_CLASS': 'redis.connection.HiredisParser',
'CONNECTION_POOL_CLASS': 'redis.BlockingConnectionPool',
'CONNECTION_POOL_CLASS_KWARGS': {
'max_connections': 50,
'timeout': 20,
},
},
'KEY_PREFIX': 'portal_talentos',
'TIMEOUT': 300, # 5 minutos padrão
}
}

# Uso de cache em views
from django.core.cache import cache
from django.views.decorators.cache import cache_page
from rest_framework.decorators import api_view

@cache_page(60 * 5) # Cache por 5 minutos
@api_view(['GET'])
def list_active_processes(request):
"""Lista processos seletivos ativos com cache"""
cache_key = 'active_processes'

# Tenta buscar do cache
cached_data = cache.get(cache_key)
if cached_data:
return Response(cached_data)

# Se não houver cache, busca do banco
processes = SelectiveProcess.objects.filter(
status='active'
).select_related('company').prefetch_related('stages')

serializer = SelectiveProcessSerializer(processes, many=True)

# Armazena no cache
cache.set(cache_key, serializer.data, 300) # 5 minutos

return Response(serializer.data)

Padrões de Invalidação de Cache

# cache_utils.py
from django.core.cache import cache
from django.db.models.signals import post_save, post_delete
from django.dispatch import receiver

class CacheInvalidator:
"""Gerenciador de invalidação de cache"""

@staticmethod
def invalidate_user_cache(user_id):
"""Invalida cache relacionado ao usuário"""
cache_keys = [
f'user:{user_id}',
f'profile:{user_id}',
f'recommendations:{user_id}',
f'submissions:{user_id}',
]
cache.delete_many(cache_keys)

@staticmethod
def invalidate_process_cache(process_id):
"""Invalida cache de processo seletivo"""
cache_keys = [
f'process:{process_id}',
f'process_stages:{process_id}',
f'process_candidates:{process_id}',
]
cache.delete_many(cache_keys)
# Invalida também cache de listagem
cache.delete('processes:list')

# Signals para invalidação automática
@receiver(post_save, sender='candidates.Candidate')
def invalidate_candidate_cache(sender, instance, **kwargs):
CacheInvalidator.invalidate_user_cache(instance.user_id)

@receiver(post_save, sender='job_vacancies.SelectiveProcess')
def invalidate_process_cache_on_save(sender, instance, **kwargs):
CacheInvalidator.invalidate_process_cache(instance.id)

Otimização de Consultas

Análise de Desempenho

Django Debug Toolbar (desenvolvimento):

# settings/development.py
if DEBUG:
INSTALLED_APPS += ['debug_toolbar']
MIDDLEWARE += ['debug_toolbar.middleware.DebugToolbarMiddleware']
INTERNAL_IPS = ['127.0.0.1', 'localhost']

Exemplos de Otimização

Uso eficiente do Django ORM:

# Antes da otimização - múltiplas consultas
def get_candidate_data_slow(candidate_id):
candidate = Candidate.objects.get(id=candidate_id)
formations = candidate.academic_formations.all() # Query adicional
experiences = candidate.professional_experiences.all() # Query adicional
skills = candidate.skills.all() # Query adicional
return {
'candidate': candidate,
'formations': formations,
'experiences': experiences,
'skills': skills
}

# Depois da otimização - query única com prefetch
def get_candidate_data_optimized(candidate_id):
candidate = Candidate.objects.prefetch_related(
'academic_formations',
'professional_experiences',
'skills'
).select_related(
'user',
'address'
).get(id=candidate_id)

return {
'candidate': candidate,
'formations': candidate.academic_formations.all(), # Já carregado
'experiences': candidate.professional_experiences.all(), # Já carregado
'skills': candidate.skills.all() # Já carregado
}

Testes de Carga

Ferramentas de Teste

Locust para Testes de Carga:

# locustfile.py
from locust import HttpUser, task, between

class PortalTalentosUser(HttpUser):
wait_time = between(1, 3)

@task(3)
def buscar_vagas(self):
self.client.get("/api/v1/job-vacancies/selective-processes/")

@task(2)
def ver_detalhes_vaga(self):
# Simula visualização de detalhes
process_id = 1 # ID de teste
self.client.get(f"/api/v1/job-vacancies/selective-processes/{process_id}/")

@task(1)
def candidatar(self):
# Simula candidatura
self.client.post("/api/v1/job-vacancies/submissions/", json={
"selective_process": 1,
"candidate": 1
})

Otimização de Recursos Estáticos

Compressão e Minificação com Vite

// vite.config.js
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import compression from "vite-plugin-compression";

export default defineConfig({
plugins: [
react(),
compression({
algorithm: "gzip",
ext: ".gz",
}),
compression({
algorithm: "brotliCompress",
ext: ".br",
}),
],
build: {
minify: "terser",
terserOptions: {
compress: {
drop_console: true,
drop_debugger: true,
},
},
rollupOptions: {
output: {
manualChunks: {
"react-vendor": ["react", "react-dom"],
"mui-vendor": ["@mui/material", "@mui/icons-material"],
},
},
},
},
});

Monitoramento de Desempenho

Logs e Métricas

Configuração de Logs Django:

# settings.py
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'verbose': {
'format': '{levelname} {asctime} {module} {message}',
'style': '{',
},
},
'handlers': {
'file': {
'level': 'INFO',
'class': 'logging.handlers.RotatingFileHandler',
'filename': '/var/log/portal_talentos/django.log',
'maxBytes': 1024 * 1024 * 10, # 10 MB
'backupCount': 5,
'formatter': 'verbose',
},
},
'loggers': {
'django': {
'handlers': ['file'],
'level': 'INFO',
},
'portal_talentos': {
'handlers': ['file'],
'level': 'DEBUG',
},
},
}

Middleware de Monitoramento

# middleware/monitoring.py
import time
import logging

logger = logging.getLogger('portal_talentos.performance')

class PerformanceMonitoringMiddleware:
def __init__(self, get_response):
self.get_response = get_response

def __call__(self, request):
start_time = time.time()

response = self.get_response(request)

duration = time.time() - start_time

# Log de desempenho
logger.info(
f"Path: {request.path} | "
f"Method: {request.method} | "
f"Status: {response.status_code} | "
f"Duration: {duration:.3f}s"
)

# Adiciona header de tempo de resposta
response['X-Response-Time'] = f"{duration:.3f}"

return response

Boas Práticas de Desempenho

Otimizações Implementadas

Backend Django:

  • Uso consistente de select_related e prefetch_related
  • Paginação em todas as listagens
  • Cache de views com django-cache
  • Processamento assíncrono com Celery para tarefas pesadas
  • Pool de conexões com PostgreSQL

Frontend React:

  • Code splitting automático com Vite
  • Lazy loading de componentes
  • Otimização de imagens
  • Cache de assets estáticos
  • Minificação e compressão de bundles

Infraestrutura:

  • Contêineres Docker otimizados
  • Kubernetes para orquestração em produção
  • Redis para cache distribuído
  • MinIO para armazenamento de objetos