Volver a la wiki

Guía de Optimización de Performance - CreaRack Pro

Guía de Optimización de Performance - CreaRack Pro

Optimizaciones de Queries (Database)

Problema N+1 Queries:

# ❌ MAL - Genera N+1 queries
devices = Device.objects.filter(rack__organization=org)
for device in devices:
    print(device.rack.name)  # Query adicional por cada device

Solución con select_related (ForeignKey):

# ✅ BIEN - Una sola query con JOIN
devices = Device.objects.select_related('rack').filter(rack__organization=org)
for device in devices:
    print(device.rack.name)  # No hay query adicional

Solución con prefetch_related (ManyToMany):

# ✅ BIEN - 2 queries en lugar de N+1
racks = Rack.objects.prefetch_related('device_set').filter(organization=org)
for rack in racks:
    for device in rack.device_set.all():  # No hay queries adicionales
        print(device.name)

2. Optimizaciones Implementadas

Blueprints API (blueprints/api.py)

Dashboard View (racks/views.py)

Network API (network/api.py)

Racks API (racks/api.py)

3. WebSocket Optimization (Valkey/Redis)

Problema de Desbordamiento: En entornos SaaS con alta concurrencia, el Channel Layer por defecto tiene una capacidad baja (100 mensajes), lo que puede causar desconexiones durante auditorías masivas.

Solución Implementada (settings/base.py):

CHANNEL_LAYERS = {
    "default": {
        "BACKEND": "channels_redis.core.RedisChannelLayer",
        "CONFIG": {
            "hosts": [("cache", 6379)],
            "capacity": 5000, # Aumentado de 100 a 5000
            "expiry": 10,     # Expiración rápida de mensajes viejos
        },
    },
}

4. Only() y Defer()

Limitar campos cargados:

# ✅ Solo cargar campos necesarios
racks = Rack.objects.only('id', 'name').filter(organization=org)

# ✅ Excluir campos grandes (como config_text)
backups = ConfigBackup.objects.defer('config_text').filter(device=device)

4. Database Indexes

Modelos con índices críticos:

class Device(models.Model):
    ip_address = models.CharField(max_length=50, db_index=True)
    rack = models.ForeignKey(Rack, on_delete=models.CASCADE, db_index=True)

    class Meta:
        indexes = [
            models.Index(fields=['rack', 'u_position']),
            models.Index(fields=['ip_address', 'vendor']),
        ]

5. Bulk Operations

Bulk Create:

# ✅ BIEN - Una sola query para insertar múltiples objetos
devices = [
    Device(name=f"Device {i}", rack=rack, u_position=i)
    for i in range(10)
]
Device.objects.bulk_create(devices)

# ❌ MAL - 10 queries separadas
for i in range(10):
    Device.objects.create(name=f"Device {i}", rack=rack, u_position=i)

Bulk Update:

# ✅ BIEN - Una sola query
Device.objects.filter(rack=rack).update(vendor='cisco_ios')

# ❌ MAL - N queries
for device in Device.objects.filter(rack=rack):
    device.vendor = 'cisco_ios'
    device.save()

Optimizaciones de Cache (Redis/Valkey)

1. Cache de Queries Frecuentes

from django.core.cache import cache

def get_rack_with_devices(rack_id):
    cache_key = f'rack_devices_{rack_id}'
    result = cache.get(cache_key)

    if result is None:
        rack = Rack.objects.select_related('group').prefetch_related('device_set').get(id=rack_id)
        result = {
            'rack': rack,
            'devices': list(rack.device_set.all())
        }
        cache.set(cache_key, result, timeout=300)  # 5 minutos

    return result

2. Invalidación de Cache

from django.db.models.signals import post_save
from django.dispatch import receiver

@receiver(post_save, sender=Device)
def invalidate_rack_cache(sender, instance, **kwargs):
    cache_key = f'rack_devices_{instance.rack_id}'
    cache.delete(cache_key)

Optimizaciones de Templates

1. Template Caching (Producción)

# config/settings/production.py
TEMPLATES[0]["OPTIONS"]["loaders"] = [
    (
        "django.template.loaders.cached.Loader",
        [
            "django.template.loaders.filesystem.Loader",
            "django.template.loaders.app_directories.Loader",
        ],
    ),
]

2. Static Files

# Collectstatic con whitenoise
python manage.py collectstatic --noinput

# Minificar JS/CSS en producción
npm run build

Monitoreo de Performance

1. Django Debug Toolbar (Dev)

# config/settings/dev.py
INSTALLED_APPS += ['debug_toolbar']
MIDDLEWARE += ['debug_toolbar.middleware.DebugToolbarMiddleware']

2. Query Logging

# config/settings/dev.py
LOGGING = {
    'handlers': {
        'console': {
            'class': 'logging.StreamHandler',
        },
    },
    'loggers': {
        'django.db.backends': {
            'handlers': ['console'],
            'level': 'DEBUG',
        },
    },
}

3. Silk (Profiling)

pip install django-silk

# Acceder a http://localhost:8000/silk/

Database Connection Pooling

Configuración en Producción

# config/settings/production.py
DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.postgresql",
        "CONN_MAX_AGE": 600,  # Mantener conexiones abiertas 10 minutos
        "OPTIONS": {
            "connect_timeout": 10,
        }
    }
}

Checklist de Optimización

Antes de hacer Deploy a Producción

Comandos Útiles

# Analizar queries lentas
python manage.py showmigrations
python manage.py dbshell
EXPLAIN ANALYZE SELECT * FROM racks_device WHERE rack_id = 1;

# Profiling con django-extensions
python manage.py runprofileserver

# Cargar datos de prueba
python manage.py loaddata fixtures/demo_data.json

Última actualización: 20-01-2026 Versión: v5.0.0-alpha

Véase también

Subir