martes, julio 21, 2026
InicioProgramaciónTu API es lenta y no sabes por qué: Guía paso a...

Tu API es lenta y no sabes por qué: Guía paso a paso para encontrar y matar los cuellos de botella

Acabas de lanzar tu API en producción. Todo funciona… hasta que llegan los primeros 100 usuarios y la respuesta pasa de 200ms a 5 segundos. El pánico se apodera de ti.

No, no necesitas más servidores. Necesitas entender dónde se está perdiendo el tiempo. En este post vamos a ponernos el sombrero de detective y rastrear cada milisegundo de tu API: desde que llega la petición hasta que sale la respuesta.

Te voy a enseñar las herramientas y técnicas que usan los equipos de performance para encontrar y eliminar cuellos de botella en cualquier stack: Node.js, Python, PHP o Go. Porque una API rápida no es un lujo, es una necesidad.

 ¿QUÉ ABORDAR EN EL POST?


Diagnóstico inicial: Medir antes de tocar nada

Contexto técnico:
Antes de optimizar, necesitas saber dónde estás parado. No se puede mejorar lo que no se mide.

  • Herramientas básicas:
    • curl -w para medir tiempos desde el cliente.
    • Postman / Insomnia con métricas de respuesta.
    • Chrome DevTools (Network tab) para ver el timeline completo.
  • Métricas clave:
    • TTFB (Time To First Byte): Tiempo hasta que el servidor empieza a enviar datos.
    • Latencia de red: Tiempo de viaje de la petición.
    • Tiempo de procesamiento: Lo que tarda tu código en ejecutarse.

Ejemplo práctico:

bash

# Medir TTFB y tiempo total de una API
curl -w "TTFB: %{time_starttransfer}s\nTiempo total: %{time_total}s\n" \
     -o /dev/null -s https://tuapi.com/endpoint

Pregunta clave:
¿Tu API es lenta por la red, por el servidor o por tu código?


El servidor: ¿Está al límite?

Contexto técnico:
Muchas veces el problema no es tu código, sino que el servidor está ahogado.

  • Recursos a monitorizar:
    • CPU: Si está al 100%, tu código es pesado o tienes un bucle infinito.
    • RAM: Si se está usando swap, el rendimiento cae en picado.
    • Disco (I/O): Lecturas/escrituras lentas pueden ralentizar todo.
    • Red: Ancho de banda saturado o conexiones abiertas.
  • Herramientas:
    • htopglances para CPU/RAM.
    • iotopiostat para disco.
    • nethogsiftop para red.
    • netstatss para conexiones activas.

Ejemplo práctico:

bash

# Ver uso de CPU y RAM en tiempo real
htop

# Ver estadísticas de disco
iostat -x 2

# Ver conexiones activas al puerto 80/443
ss -tulpn | grep :80

Pregunta clave:
¿Tu servidor tiene recursos disponibles o ya está saturado?

El gestor de procesos y servidor web: Configuración y tuning

Contexto técnico:
Tu servidor web (Nginx/Apache) y el gestor de procesos (PM2, Gunicorn, PHP-FPM) tienen configuraciones que afectan directamente el rendimiento.

  • Nginx:
    • Número de workers (worker_processes).
    • Límite de conexiones por worker (worker_connections).
    • Buffers y timeouts.
  • PM2 (Node.js):
    • Modo cluster para usar todos los núcleos de la CPU.
    • Límite de memoria y reinicio automático.
  • Gunicorn (Python):
    • Número de workers (workers = (2 x núcleos) + 1).
    • Threads y timeouts.
  • PHP-FPM:
    • Número de procesos hijos (pm.max_children).
    • Tiempo de ejecución máximo (request_terminate_timeout).

Ejemplo práctico (Nginx):

nginx

worker_processes auto;  # Un worker por núcleo de CPU
worker_connections 1024;

# Buffers para peticiones grandes
client_body_buffer_size 10K;
client_header_buffer_size 1k;

Ejemplo práctico (PM2 en modo cluster):

bash

# Iniciar app usando todos los núcleos de la CPU
pm2 start app.js -i max --name "mi-api"

Pregunta clave:
¿Tu servidor web está configurado para exprimir al máximo el hardware disponible?

La base de datos: El cuello de botella número 1

Contexto técnico:
Si tu API consulta una BBDD, estadísticamente, ese es el punto más lento.

  • Problemas comunes:
    • Falta de índices: Consultas que escanean toda la tabla.
    • N+1 queries: Hacer 100 consultas en lugar de 1 (típico en ORMs).
    • Consultas pesadas: Joins mal optimizados o falta de filtros.
    • Sin caché: La misma consulta se ejecuta una y otra vez.
  • Herramientas de diagnóstico:
    • PostgreSQL: pg_stat_statementsEXPLAIN ANALYZE.
    • MySQL: slow_query_logEXPLAIN.
    • MongoDB: explain() y perfil de consultas lentas.

Ejemplo práctico (PostgreSQL):

sql

-- Activar logs de consultas lentas
ALTER SYSTEM SET log_min_duration_statement = 1000; -- 1 segundo

-- Analizar plan de ejecución
EXPLAIN ANALYZE SELECT * FROM usuarios WHERE email = 'test@mail.com';

Ejemplo práctico (MySQL):

sql

-- Activar slow query log
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 1;

-- Ver índices recomendados
EXPLAIN SELECT * FROM pedidos WHERE fecha > '2024-01-01';

Pregunta clave:
¿Tu BBDD está devolviendo solo lo necesario o estás sobrecargándola?

El código: Optimizaciones directas

Contexto técnico:
Aquí es donde tu habilidad como programador marca la diferencia.

  • Errores típicos:
    • Bucles innecesarios anidados (O(n²)).
    • Procesamiento de datos que podría hacerse en la BBDD.
    • Conversiones de formato redundantes.
    • Uso de librerías pesadas para tareas triviales.
  • Técnicas de optimización:
    • Asincronía: Usar async/await o promesas para no bloquear el event loop.
    • Streaming: Procesar datos en trozos en lugar de cargar todo en memoria.
    • Lazy loading: Cargar solo lo que se necesita en ese momento.
    • Pool de conexiones: Reutilizar conexiones a BBDD o servicios externos.

Ejemplo práctico (Node.js):

javascript

// MAL: Bloquea el event loop
const data = fs.readFileSync('/archivo-gigante.json');
const result = data.map(item => transformar(item));

// BIEN: Streaming y asincronía
const stream = fs.createReadStream('/archivo-gigante.json', { highWaterMark: 64 * 1024 });
stream.on('data', (chunk) => {
procesarChunk(chunk);
});

Ejemplo práctico (Python):

python

#  MAL: N+1 queries con ORM
for user in usuarios:
pedidos = Pedidos.objects.filter(usuario_id=user.id) # Una consulta por usuario

# BIEN: Una sola consulta con join
pedidos = Pedidos.objects.select_related('usuario').all()

Pregunta clave:
¿Estás usando las estructuras de datos y algoritmos adecuados para tu caso de uso?

La caché: El turbo de tu API

Contexto técnico:
La caché es la forma más rápida de mejorar el rendimiento sin tocar ni una línea de código (siempre que se use bien).

  • Tipos de caché:
    • Caché en memoria: Redis, Memcached para respuestas frecuentes.
    • Caché de HTTP: Cabeceras Cache-ControlETag en el navegador.
    • Caché de consultas: Guardar resultados de BBDD que apenas cambian.
    • CDN: Servir contenido estático desde servidores cercanos al usuario.
  • Estrategias:
    • Cache-Aside: La app consulta caché primero, y si no hay, va a BBDD y guarda.
    • Write-Through: Escribir en BBDD y caché al mismo tiempo.
    • TTL (Time To Live): Definir cuánto tiempo vive cada dato en caché.

Ejemplo práctico (Redis + Node.js):

javascript

const redis = require('redis');
const client = redis.createClient();

async function getUsuario(id) {
    // 1. Intentar obtener de caché
    const cached = await client.get(`usuario:${id}`);
    if (cached) return JSON.parse(cached);
    
    // 2. Si no está en caché, consultar BBDD
    const usuario = await db.query('SELECT * FROM usuarios WHERE id = ?', [id]);
    
    // 3. Guardar en caché con expiración (TTL de 1 hora)
    await client.setex(`usuario:${id}`, 3600, JSON.stringify(usuario));
    
    return usuario;
}

Ejemplo práctico (Cabeceras HTTP):

nginx

# En Nginx, caché de archivos estáticos por 1 año
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
    expires 1y;
    add_header Cache-Control "public, immutable";
}

Pregunta clave:
¿Qué datos se repiten constantemente y podrían servirse desde caché?

Monitorización: El ojo que todo lo ve

Contexto técnico:
No sirve de nada optimizar si no tienes visibilidad de lo que pasa en producción.

  • Herramientas recomendadas:
    • APM (Application Performance Monitoring):
      • New Relic, Datadog, Dynatrace (pagos).
      • Elastic APM, Prometheus + Grafana (open source).
    • Logs estructurados:
      • Usar JSON en logs para poder filtrar y buscar fácilmente.
      • Centralizar logs con ELK (Elasticsearch, Logstash, Kibana) o Loki.
    • Alertas:
      • Configurar alertas cuando el tiempo de respuesta supere un umbral.
      • Monitorear errores 500 y 504.

Ejemplo práctico (Prometheus + Grafana):

yaml

# Configurar métricas personalizadas en Node.js
const client = require('prom-client');
const httpRequestDuration = new client.Histogram({
    name: 'http_request_duration_seconds',
    help: 'Duración de peticiones HTTP',
    labelNames: ['method', 'route', 'status']
});

app.use((req, res, next) => {
    const end = httpRequestDuration.startTimer();
    res.on('finish', () => {
        end({ method: req.method, route: req.route?.path, status: res.statusCode });
    });
    next();
});

Pregunta clave:
¿Tienes visibilidad real de lo que pasa en tu API o trabajas a ciegas?

Matar cuellos de botella no es magia ni intuición. Es un proceso metódico de medición, análisis y acción.

Empieza siempre midiendo. Luego ataca donde más duele: primero el servidor, luego la configuración, después la BBDD, y finalmente el código. La caché es tu aliada, y la monitorización, tu mejor inversión.

Tu API puede ser rápida. Solo necesitas saber dónde mirar.

RELATED ARTICLES

DEJA UNA RESPUESTA

Please enter your comment!
Please enter your name here

- Advertisment -

Most Popular

Recent Comments