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