TTFB Request Duration: Reducir el tiempo de procesamiento del servidor

La request duration es el tiempo que su servidor dedica a procesar una solicitud. Es el factor que más contribuye al TTFB en la mayoría de los sitios. Aprenda sobre Server-Timing, almacenamiento en caché, optimización de bases de datos y correcciones de plataforma.

Arjen Karel Core Web Vitals Consultant
Arjen Karel - linkedin
Last update: 2026-03-03

Reducir la subparte Request Duration del Time to First Byte

Este artículo forma parte de nuestra guía sobre el Time to First Byte (TTFB). La request duration es la quinta y última subparte del TTFB. Mide el tiempo que su servidor dedica realmente a procesar una solicitud: recibirla, ejecutar la lógica de la aplicación, consultar las bases de datos y generar la respuesta HTML. De todas las subpartes del TTFB, la request duration es sobre la que usted tiene más control. En mi experiencia auditando sitios con CoreDash, es el factor que más contribuye a un TTFB lento en la mayoría de los sitios web.

El Time to First Byte (TTFB) se puede desglosar en las siguientes subpartes:

¿Busca optimizar el Time to First Byte? Este artículo se centra en la parte de request duration del Time to First Byte. Si no está seguro de lo que significa request duration, comience primero con qué es el Time to First Byte y corregir e identificar problemas de TTFB.

Qué ocurre durante la Request Duration

La request duration comienza en el momento en que el servidor recibe la solicitud HTTP y termina cuando envía el primer byte de la respuesta. Todo lo que haga su servidor en medio cuenta para la request duration. En un sitio web dinámico típico, esto incluye:

  1. Request routing: el servidor web (Nginx, Apache, IIS) recibe la solicitud y la dirige a la capa de aplicación.
  2. Application bootstrap: el framework se inicializa. En WordPress esto significa cargar el núcleo, las extensiones activas y el tema. En Node.js/Express esto significa la ejecución de middleware.
  3. Lógica de negocio: se ejecuta el código de su aplicación: comprobaciones de autenticación, validación de permisos, transformación de datos, selección de plantillas.
  4. Consultas a la base de datos: la aplicación consulta MySQL, PostgreSQL, MongoDB o cualquier almacén de datos que utilice. Este suele ser el paso más lento.
  5. Generación de la respuesta: la aplicación renderiza la respuesta HTML (o JSON) a partir de plantillas, árboles de componentes o lógica de serialización.

Cada uno de estos pasos añade tiempo. Un servidor bien optimizado completa toda la cadena en menos de 100ms. Uno mal optimizado puede tardar 800ms o más, y eso es antes de que el DNS, la conexión y la latencia de red entren en escena.

Cómo medir la Request Duration con la API Server-Timing

La cabecera HTTP Server-Timing es la mejor herramienta para diagnosticar la request duration. Le permite enviar desgloses de tiempo desde el servidor directamente al navegador, donde aparecen en las DevTools y son accesibles a través de la Performance API. Esto significa que puede medir pasos individuales (consultas a la base de datos, renderizado de plantillas, búsquedas en caché) y ver exactamente qué es lento.

El formato de la cabecera Server-Timing es:

Server-Timing: db;dur=53.2;desc="Database queries",
               app;dur=24.1;desc="Application logic",
               tpl;dur=18.7;desc="Template rendering"

Estos valores aparecen en el panel Network de las Chrome DevTools, bajo la pestaña "Timing", ofreciéndole una cascada del lado del servidor que se asigna directamente a su código.

Server-Timing en PHP

La función hrtime(true) de PHP proporciona precisión de nanosegundos, lo que la hace ideal para medir operaciones individuales del lado del servidor. He aquí cómo añadir Server-Timing a una aplicación PHP:

\/\/ Medir el tiempo de consulta a la base de datos con precisión de nanosegundos
$dbStart = hrtime(true);
$result = $pdo->query('SELECT * FROM products WHERE active = 1');
$dbDuration = (hrtime(true) - $dbStart) \/ 1e6; \/\/ Convertir a ms

\/\/ Medir el renderizado de la plantilla
$tplStart = hrtime(true);
$html = renderTemplate('product-list', ['products' => $result]);
$tplDuration = (hrtime(true) - $tplStart) \/ 1e6;

\/\/ Enviar la cabecera Server-Timing al navegador
header(sprintf(
    'Server-Timing: db;dur=%.1f;desc="Database", tpl;dur=%.1f;desc="Template"',
    $dbDuration,
    $tplDuration
));

Server-Timing en Node.js / Express

En Node.js, utilice process.hrtime.bigint() para una temporización de alta resolución. Un patrón de middleware le permite medir el tiempo total de procesamiento de la solicitud y las operaciones individuales:

\/\/ Middleware de Express para las cabeceras Server-Timing
app.use((req, res, next) => {
  const start = process.hrtime.bigint();
  const timings = [];

  \/\/ Añadir un ayudante al objeto de respuesta
  res.serverTiming = (name, desc) => {
    const mark = process.hrtime.bigint();
    return () => {
      const dur = Number(process.hrtime.bigint() - mark) \/ 1e6;
      timings.push(`${name};dur=${dur.toFixed(1)};desc="${desc}"`);
    };
  };

  \/\/ Antes de enviar la respuesta, añadir la cabecera
  const originalEnd = res.end.bind(res);
  res.end = (...args) => {
    const total = Number(process.hrtime.bigint() - start) \/ 1e6;
    timings.push(`total;dur=${total.toFixed(1)};desc="Total"`);
    res.setHeader('Server-Timing', timings.join(', '));
    originalEnd(...args);
  };

  next();
});

\/\/ Uso en un controlador de rutas
app.get('\/products', async (req, res) => {
  const endDb = res.serverTiming('db', 'Database');
  const products = await db.query('SELECT * FROM products');
  endDb();

  const endTpl = res.serverTiming('tpl', 'Template');
  const html = renderTemplate('products', { products });
  endTpl();

  res.send(html);
});

Cuellos de Botella comunes en la Request Duration

Después de instrumentar cientos de servidores, veo los mismos cuellos de botella una y otra vez. Estas son las causas más comunes de una request duration lenta, ordenadas por la frecuencia con la que las encuentro:

  • Consultas lentas a la base de datos: consultas sin índices, patrones de consulta N+1, escaneos completos de tablas en tablas grandes. Esta es la causa número uno. Un solo índice que falte en una tabla de productos de WooCommerce puede añadir entre 300 y 500ms por solicitud.
  • Falta de almacenamiento en caché de páginas: regenerar el mismo HTML para cada visitante cuando el contenido no ha cambiado. Esto es especialmente común en los sitios de WordPress sin una caché de objetos o una extensión de caché de página.
  • Cómputos costosos: ejecutar cálculos complejos, procesamiento de imágenes o agregación de datos en cada solicitud en lugar de cachear los resultados.
  • Llamadas a APIs externas: solicitudes síncronas a APIs de terceros (pasarelas de pago, sistemas CRM, servicios de inventario) que bloquean la respuesta hasta que se completan.
  • Código de aplicación no optimizado: cargar módulos no utilizados, ejecutar middleware innecesario o utilizar algoritmos ineficientes para el procesamiento de datos.
  • Cold starts: en las plataformas serverless (AWS Lambda, Cloudflare Workers, Vercel Functions), la primera solicitud después de un periodo de inactividad incurre en una sobrecarga de inicialización del contenedor.

Soluciones específicas por plataforma

WordPress

Los sitios de WordPress son particularmente vulnerables a una request duration lenta porque cada carga de página arranca todo el núcleo de WordPress, todas las extensiones activas y el tema. Esto es lo que marca la mayor diferencia:

  • Instale una caché de objetos persistente: Redis o Memcached. WordPress ejecuta docenas de consultas a la base de datos por carga de página, muchas de ellas idénticas entre visitantes. Una caché de objetos (a través de una extensión como Redis Object Cache) almacena estos resultados en memoria, reduciendo el tiempo de base de datos entre un 60 y un 80%.
  • Habilite el almacenamiento en caché de página completa: utilice una caché de página a nivel de servidor (Nginx FastCGI Cache, Varnish) o una extensión como WP Super Cache. Esto sirve el HTML cacheado directamente sin tocar PHP en absoluto.
  • Audite las extensiones lentas: utilice la extensión Query Monitor para identificar qué extensiones están generando más consultas a la base de datos o consumiendo más tiempo de ejecución de PHP.
  • Optimice las consultas de WooCommerce: WooCommerce es conocido por sus lentas consultas de productos. Habilite la función de Almacenamiento de Pedidos de Alto Rendimiento (HPOS) y añada los índices de base de datos adecuados a la tabla wp_postmeta.

Caso de estudio: Un sitio de WordPress redujo la request duration de 800ms a 120ms implementando el almacenamiento en caché de objetos (Redis) y optimizando una lenta consulta de productos de WooCommerce que se ejecutaba en cada carga de página. La consulta de productos por sí sola representaba 450ms porque estaba realizando un escaneo completo de la tabla en 80.000 filas de postmeta sin un índice.

Node.js

Las aplicaciones Node.js suelen tener una request duration rápida por defecto, pero los problemas aparecen a escala o con operaciones bloqueantes:

  • Perfile con el inspector integrado: ejecute node --inspect app.js y conecte las Chrome DevTools para identificar las funciones con mucha carga de CPU. Busque operaciones síncronas que bloqueen el bucle de eventos (event loop).
  • Habilite el registro de consultas del ORM: si utiliza Sequelize, Prisma o TypeORM, habilite el registro de consultas para encontrar patrones N+1 y consultas lentas. En Sequelize: sequelize = new Sequelize({ logging: console.log }).
  • Utilice el pooling de conexiones: no cree una nueva conexión a la base de datos para cada solicitud. Utilice un pool de conexiones (integrado en la mayoría de los controladores de bases de datos de Node.js) para reutilizar las conexiones.
  • Implemente el almacenamiento en caché en memoria: para los datos a los que se accede con frecuencia y que no cambian a menudo, utilice una caché LRU para evitar consultar la base de datos en cada solicitud.

PHP (no WordPress)

Para Laravel, Symfony o aplicaciones PHP personalizadas:

  • Habilite OPcache: El OPcache de PHP compila los scripts PHP en bytecode y los almacena en la memoria compartida, eliminando la necesidad de analizarlos y compilarlos en cada solicitud. Esto por sí solo puede reducir la request duration entre un 30 y un 50%.
  • Utilice un pre-cargador de bytecode: PHP 8.0+ admite la precarga (disponible desde PHP 7.4), que carga los archivos del framework en memoria al arrancar el servidor para que no tengan que cargarse por solicitud.
  • Perfile con Xdebug o Blackfire: identifique las funciones específicas que consumen más tiempo de reloj.

Python (Django / Flask)

Las aplicaciones Python suelen tener una request duration base más alta en comparación con Node.js o PHP:

  • Utilice un framework asíncrono: si la espera de E/S es el cuello de botella, considere FastAPI o Django con ASGI para gestionar las consultas a la base de datos y las llamadas a APIs de forma concurrente.
  • Habilite el registro de consultas a la base de datos de Django: establezca LOGGING en la configuración para registrar todas las consultas SQL e identificar las lentas o redundantes.
  • Utilice select_related() y prefetch_related(): El ORM de Django generará con gusto consultas N+1 a menos que le indique explícitamente que una las tablas relacionadas.

Pooling de Conexiones a la Base de Datos

Abrir una nueva conexión a la base de datos para cada solicitud es una de las causas más comunes, y más evitables, de una request duration lenta. Cada nueva conexión requiere un handshake TCP, autenticación e inicialización de la sesión, lo que puede añadir entre 5 y 30ms por solicitud. Bajo carga, esto se vuelve catastrófico a medida que el servidor de la base de datos se queda sin conexiones disponibles.

El pooling de conexiones soluciona esto manteniendo un pool de conexiones abiertas que se reutilizan en todas las solicitudes. La aplicación toma prestada una conexión del pool, ejecuta sus consultas y devuelve la conexión cuando termina. Esto elimina por completo la sobrecarga de conexión por solicitud.

La mayoría de los controladores de bases de datos admiten el pooling de conexiones de forma nativa. En Node.js con pg (PostgreSQL), por ejemplo, configúrelo así:

const { Pool } = require('pg');

const pool = new Pool({
  host: 'localhost',
  database: 'myapp',
  max: 20,        \/\/ Máximo de conexiones en el pool
  idleTimeoutMillis: 30000,  \/\/ Cerrar conexiones inactivas tras 30s
  connectionTimeoutMillis: 2000  \/\/ Fallar rápido si no hay conexión disponible
});

\/\/ Utilizar pool.query() en lugar de crear nuevos clientes
const result = await pool.query('SELECT * FROM products WHERE id = $1', [id]);

Para las aplicaciones PHP detrás de PHP-FPM, considere el uso de conexiones persistentes (PDO::ATTR_PERSISTENT) o un pooler externo como PgBouncer para PostgreSQL o ProxySQL para MySQL.

Almacenamiento en Caché de Proxy Inverso

La respuesta más rápida es aquella que su aplicación nunca tiene que generar. Una caché de proxy inverso (Varnish, Nginx FastCGI Cache o una caché de borde de CDN) se sitúa delante de su servidor de aplicaciones y sirve las respuestas cacheadas directamente desde la memoria. Para las páginas que no cambian entre visitantes (lo que incluye la mayoría de las páginas de la mayoría de los sitios web), esto reduce la request duration a casi cero.

  • Varnish: una caché HTTP dedicada que puede servir miles de solicitudes por segundo desde la memoria. Configure las cabeceras Cache-Control en las respuestas de su aplicación y Varnish se encargará del resto.
  • Nginx FastCGI Cache: si ya utiliza Nginx como su servidor web, habilite su caché integrada para las respuestas de PHP-FPM. Esto evita añadir otra capa a su stack.
  • Caché de borde de CDN: servicios como Cloudflare, Fastly y Amazon CloudFront pueden cachear su HTML en ubicaciones de borde en todo el mundo, reduciendo simultáneamente la request duration y la latencia de red.

La clave para un almacenamiento en caché de proxy inverso eficaz son las cabeceras Cache-Control adecuadas. Establezca s-maxage para el TTL de la caché compartida y utilice stale-while-revalidate para servir contenido antiguo mientras la caché se refresca en segundo plano:

Cache-Control: public, s-maxage=3600, stale-while-revalidate=60

Edge Computing para la Request Duration

Las plataformas de edge computing como Cloudflare Workers y Vercel Edge Functions ejecutan su código del lado del servidor en ubicaciones de borde de CDN, físicamente cerca de sus usuarios. El edge computing no hará que su código sea más rápido, pero elimina la latencia de red entre el usuario y su servidor de origen. Esto es muy importante para los usuarios alejados de su centro de datos de origen.

Las funciones de borde funcionan mejor para:

  • Respuestas de API ligeras que no requieren un acceso intenso a la base de datos.
  • Lógica de personalización (pruebas A/B, contenido basado en la ubicación geográfica) aplicada en el borde antes de llegar a su origen.
  • Reescrituras de HTML y manipulación de cabeceras sin un viaje de ida y vuelta completo al origen.

Para las páginas que requieren consultas a bases de datos, el edge computing por sí solo no resolverá los problemas de request duration. La verdadera victoria es combinar las funciones de borde con una base de datos distribuida globalmente (PlanetScale, Neon, Turso) o el almacenamiento en caché en el lado del borde para mantener el ciclo de vida completo de la solicitud cerca del usuario.

Medición de la Request Duration con JavaScript

Puede medir la subparte request duration del TTFB directamente en el navegador utilizando la Navigation Timing API:

new PerformanceObserver((entryList) => {
  const [nav] = entryList.getEntriesByType('navigation');

  const requestDuration = nav.responseStart - nav.requestStart;

  console.log('Request Duration:', requestDuration.toFixed(0), 'ms');
  console.log('  Request start:', nav.requestStart.toFixed(0), 'ms');
  console.log('  Response start:', nav.responseStart.toFixed(0), 'ms');

  if (requestDuration > 200) {
    console.warn('Detectada request duration lenta. Compruebe el tiempo de procesamiento del servidor.');
  }
}).observe({
  type: 'navigation',
  buffered: true
});

La request duration se calcula como responseStart - requestStart. Un valor consistentemente por encima de 200ms indica que su servidor está dedicando demasiado tiempo a procesar la solicitud. Utilice la cabecera Server-Timing (descrita anteriormente) para identificar qué parte del procesamiento del servidor es la responsable.

Cómo identificar problemas de Request Duration con datos RUM

Para entender cómo afecta la request duration a sus usuarios reales, necesita una herramienta de Real User Monitoring (RUM) como CoreDash. Los datos RUM muestran el desglose real del TTFB que experimentan sus visitantes a través de páginas, dispositivos y ubicaciones. No son resultados de laboratorio.

En CoreDash, haga clic en "Desglose del Time to First Byte" para visualizar la parte de request duration del TTFB. Busque páginas donde la request duration esté consistentemente por encima de 200ms. Esos son sus objetivos de optimización.

Lo que muestran nuestros datos

A través de miles de sitios monitorizados por CoreDash, la request duration (tiempo de procesamiento del servidor) es la subparte del TTFB que más contribuye en la mayoría de los sitios de nuestro conjunto de datos, lo que hace que la optimización del servidor sea la mayor mejora individual del TTFB para la mayoría de los sitios web.

Los sitios con el almacenamiento en caché de página completa habilitado tienen una request duration mediana de aproximadamente 35ms. Los sitios sin ningún tipo de caché tienen una mediana de aproximadamente 320ms. Esa brecha (casi 10 veces) es el argumento más sólido que puedo dar para invertir en el almacenamiento en caché del lado del servidor antes que en cualquier otra cosa.

La request duration es parte del Time to First Byte, que es una métrica de diagnóstico para los Core Web Vitals. Para obtener una guía completa sobre cómo identificar y corregir problemas de TTFB, consulte nuestra guía para corregir e identificar el TTFB. También puede consultar la lista de verificación definitiva de los Core Web Vitals para obtener una visión general exhaustiva de la optimización.

Lecturas adicionales: Guías de Optimización

Para conocer técnicas de optimización relacionadas que complementan la optimización de la request duration, explore estas guías:

  • 103 Early Hints: envía sugerencias de recursos (preload, preconnect) al navegador mientras el servidor aún está procesando la solicitud, reduciendo el TTFB percibido.
  • Configurar Cloudflare para el Rendimiento: utilice el almacenamiento en caché de borde de CDN y configuraciones de servidor optimizadas para reducir la request duration a nivel global.

Subpartes del TTFB: Guías completas

La request duration es una de las cinco subpartes del TTFB. Explore las otras subpartes para comprender el panorama completo:

Performance degrades unless you guard it.

I do not just fix the metrics. I set up the monitoring, the budgets, and the processes so your team keeps them green after I leave.

Start the Engagement
TTFB Request Duration: Reducir el tiempo de procesamiento del servidorCore Web Vitals TTFB Request Duration: Reducir el tiempo de procesamiento del servidor