TTFB Request Duration: Reducir el tiempo de procesamiento del servidor
El request duration es el tiempo que tu servidor dedica a procesar una solicitud. Es el mayor contribuyente al TTFB en la mayoría de los sitios. Aprende sobre Server-Timing, almacenamiento en caché, optimización de bases de datos y soluciones por plataforma.

Reducir la sub-parte Request Duration del Time to First Byte
Este artículo forma parte de nuestra guía sobre Time to First Byte (TTFB). El request duration es la quinta y última sub-parte del TTFB. Mide el tiempo que tu servidor dedica realmente a procesar una solicitud: recibirla, ejecutar la lógica de la aplicación, consultar bases de datos y generar la respuesta HTML. De todas las sub-partes del TTFB, el request duration es sobre la que tienes más control. En mi experiencia auditando sitios con CoreDash, es el mayor contribuyente individual a un TTFB lento en la mayoría de los sitios web.
El Time to First Byte (TTFB) se puede desglosar en las siguientes sub-partes:
- Waiting + Redirect (o waiting duration)
- Worker + Cache (o cache duration)
- DNS (o DNS duration)
- Connection (o connection duration)
- Request (o request duration)
¿Quieres optimizar el Time to First Byte? Este artículo ofrece un análisis en profundidad de la parte request duration del Time to First Byte. Si buscas entender o solucionar el Time to First Byte y no sabes qué significa request duration, lee qué es el Time to First Byte y cómo identificar y solucionar problemas de Time to First Byte antes de continuar con este artículo.
Table of Contents!
- Reducir la sub-parte Request Duration del Time to First Byte
- Qué ocurre durante el Request Duration
- Cómo medir el Request Duration con la API Server-Timing
- Cuellos de botella comunes del Request Duration
- Soluciones específicas por plataforma
- Connection Pooling de base de datos
- Caché de proxy inverso
- Edge Computing para el Request Duration
- Medir el Request Duration con JavaScript
- Cómo identificar problemas de Request Duration con datos RUM
- Lo que muestran nuestros datos
- Lectura adicional: Guías de optimización
- Sub-partes del TTFB: Artículos en profundidad
Qué ocurre durante el Request Duration
El 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 tu servidor hace en ese intervalo cuenta como request duration. En un sitio web dinámico típico, esto incluye:
- Enrutamiento de la solicitud: el servidor web (Nginx, Apache, IIS) recibe la solicitud y la dirige a la capa de aplicación.
- Arranque de la aplicación: el framework se inicializa. En WordPress esto significa cargar el núcleo, los plugins activos y el tema. En Node.js/Express esto significa la ejecución del middleware.
- Lógica de negocio: se ejecuta el código de tu aplicación: verificaciones de autenticación, validación de permisos, transformación de datos, selección de plantillas.
- Consultas a la base de datos: la aplicación consulta MySQL, PostgreSQL, MongoDB o cualquier almacén de datos que utilices. Este suele ser el paso más lento.
- 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 suma 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 juego.
Cómo medir el Request Duration con la API Server-Timing
La cabecera HTTP Server-Timing es la herramienta más potente para diagnosticar el request duration. Te permite enviar desgloses de tiempos desde el servidor directamente al navegador, donde aparecen en DevTools y son accesibles a través de la Performance API. Esto significa que puedes medir pasos individuales (consultas a la base de datos, renderizado de plantillas, búsquedas en caché) y ver exactamente dónde se está gastando el tiempo.
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 Chrome DevTools en la pestaña "Timing", proporcionándote una cascada del lado del servidor que se corresponde directamente con tu 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. Así es como instrumentar una aplicación PHP:
// Measure database query time with nanosecond precision
$dbStart = hrtime(true);
$result = $pdo->query('SELECT * FROM products WHERE active = 1');
$dbDuration = (hrtime(true) - $dbStart) / 1e6; // Convert to ms
// Measure template rendering
$tplStart = hrtime(true);
$html = renderTemplate('product-list', ['products' => $result]);
$tplDuration = (hrtime(true) - $tplStart) / 1e6;
// Send Server-Timing header to the browser
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, usa process.hrtime.bigint() para temporización de alta resolución. Un patrón de middleware te permite medir el tiempo total de procesamiento de la solicitud y las operaciones individuales:
// Express middleware for Server-Timing headers
app.use((req, res, next) => {
const start = process.hrtime.bigint();
const timings = [];
// Attach a helper to the response object
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}"`);
};
};
// Before sending the response, add the header
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();
});
// Usage in a route handler
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 del 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 un request duration lento, clasificadas 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 grandes. Esta es la causa número uno. Un solo índice faltante en una tabla de productos de WooCommerce puede añadir de 300 a 500ms por solicitud.
- Falta de caché de página: regenerar el mismo HTML para cada visitante cuando el contenido no ha cambiado. Esto es especialmente común en sitios WordPress sin un object cache o plugin de caché de página.
- Cálculos costosos: ejecutar cálculos complejos, procesamiento de imágenes o agregación de datos en cada solicitud en lugar de almacenar los resultados en caché.
- 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 usar algoritmos ineficientes para el procesamiento de datos.
- Arranques en frío: en plataformas serverless (AWS Lambda, Cloudflare Workers, Vercel Functions), la primera solicitud después de un período de inactividad conlleva una sobrecarga de inicialización del contenedor.
Soluciones específicas por plataforma
WordPress
Los sitios WordPress son particularmente vulnerables a un request duration lento porque cada carga de página arranca todo el núcleo de WordPress, todos los plugins activos y el tema. Esto es lo que marca la mayor diferencia:
- Instalar un object cache 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. Un object cache (a través de un plugin como Redis Object Cache) almacena estos resultados en memoria, reduciendo el tiempo de base de datos entre un 60 y un 80%.
- Habilitar caché de página completa: usa una caché de página a nivel de servidor (Nginx FastCGI Cache, Varnish) o un plugin como WP Super Cache. Esto sirve HTML en caché directamente sin tocar PHP en absoluto.
- Auditar plugins lentos: usa el plugin Query Monitor para identificar qué plugins están generando más consultas a la base de datos o consumiendo más tiempo de ejecución de PHP.
- Optimizar las consultas de WooCommerce: WooCommerce es conocido por sus consultas de productos lentas. Habilita la función High-Performance Order Storage (HPOS) y añade índices de base de datos adecuados a la tabla
wp_postmeta.
Caso de estudio: Un sitio WordPress redujo el request duration de 800ms a 120ms implementando object caching (Redis) y optimizando una consulta de producto WooCommerce lenta que se ejecutaba en cada carga de página. Solo la consulta de producto representaba 450ms porque estaba haciendo un escaneo completo de tabla en 80.000 filas de postmeta sin un índice.
Node.js
Las aplicaciones Node.js típicamente tienen un request duration rápido de serie, pero los problemas aparecen a escala o con operaciones bloqueantes:
- Perfilar con el inspector integrado: ejecuta
node --inspect app.jsy conecta Chrome DevTools para identificar funciones con uso intensivo de CPU. Busca operaciones síncronas que bloqueen el event loop. - Habilitar el registro de consultas del ORM: si usas Sequelize, Prisma o TypeORM, habilita el registro de consultas para encontrar patrones N+1 y consultas lentas. En Sequelize:
sequelize = new Sequelize({ logging: console.log }). - Usar connection pooling: no crees una nueva conexión a la base de datos para cada solicitud. Usa un pool de conexiones (incluido en la mayoría de los drivers de base de datos de Node.js) para reutilizar conexiones.
- Implementar caché en memoria: para datos de acceso frecuente que no cambian a menudo, usa una caché LRU para evitar consultar la base de datos en cada solicitud.
PHP (fuera de WordPress)
Para aplicaciones Laravel, Symfony o PHP personalizadas:
- Habilitar OPcache: OPcache de PHP compila los scripts PHP en bytecode y los almacena en memoria compartida, eliminando la necesidad de analizar y compilar en cada solicitud. Esto solo puede reducir el request duration entre un 30 y un 50%.
- Usar un precargador de bytecode: PHP 7.4+ soporta precarga, que carga archivos del framework en memoria al iniciar el servidor para que no necesiten cargarse en cada solicitud.
- Perfilar con Xdebug o Blackfire: identifica las funciones específicas que consumen más tiempo real de ejecución.
Python (Django / Flask)
Las aplicaciones Python suelen tener un request duration base más alto en comparación con Node.js o PHP:
- Usar un framework asíncrono: si la espera de I/O es el cuello de botella, considera FastAPI o Django con ASGI para manejar consultas a la base de datos y llamadas a APIs de forma concurrente.
- Habilitar el registro de consultas de Django: configura
LOGGINGen los ajustes para registrar todas las consultas SQL e identificar las lentas o redundantes. - Usar
select_related()yprefetch_related(): el ORM de Django generará encantado consultas N+1 a menos que le indiques explícitamente que haga join de las tablas relacionadas.
Connection Pooling de 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 un request duration lento. Cada nueva conexión requiere handshake TCP, autenticación e inicialización de sesión, lo que puede añadir de 5 a 30ms por solicitud. Bajo carga, esto se vuelve catastrófico a medida que el servidor de base de datos se queda sin conexiones disponibles.
El connection pooling resuelve esto manteniendo un pool de conexiones abiertas que se reutilizan entre 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 drivers de base de datos soportan connection pooling de forma nativa. En Node.js con pg (PostgreSQL), por ejemplo, configúralo así:
const { Pool } = require('pg');
const pool = new Pool({
host: 'localhost',
database: 'myapp',
max: 20, // Maximum connections in the pool
idleTimeoutMillis: 30000, // Close idle connections after 30s
connectionTimeoutMillis: 2000 // Fail fast if no connection available
});
// Use pool.query() instead of creating new clients
const result = await pool.query('SELECT * FROM products WHERE id = $1', [id]);
Para aplicaciones PHP detrás de PHP-FPM, considera usar conexiones persistentes (PDO::ATTR_PERSISTENT) o un pooler externo como PgBouncer para PostgreSQL o ProxySQL para MySQL.
Caché de proxy inverso
La respuesta más rápida es la que tu aplicación nunca tiene que generar. Una caché de proxy inverso (Varnish, Nginx FastCGI Cache o una caché en el edge de la CDN) se sitúa delante de tu servidor de aplicaciones y sirve respuestas en caché directamente desde memoria. Para las páginas que no cambian entre visitantes (lo que incluye la mayoría de las páginas en la mayoría de los sitios web), esto reduce el request duration casi a cero.
- Varnish: una caché HTTP dedicada que puede servir miles de solicitudes por segundo desde memoria. Configura las cabeceras
Cache-Controlen las respuestas de tu aplicación y Varnish se encarga del resto. - Nginx FastCGI Cache: si ya usas Nginx como tu servidor web, habilita su caché integrada para respuestas de PHP-FPM. Esto evita añadir otra capa a tu stack.
- Caché en el edge de la CDN: servicios como Cloudflare, Fastly y Amazon CloudFront pueden almacenar en caché tu HTML en ubicaciones edge en todo el mundo, reduciendo tanto el request duration como la latencia de red simultáneamente.
La clave para una caché de proxy inverso efectiva son las cabeceras Cache-Control adecuadas. Establece s-maxage para el TTL de la caché compartida y usa stale-while-revalidate para servir contenido obsoleto mientras la caché se actualiza en segundo plano:
Cache-Control: public, s-maxage=3600, stale-while-revalidate=60
Edge Computing para el Request Duration
Las plataformas de edge computing como Cloudflare Workers y Vercel Edge Functions ejecutan tu código del lado del servidor en ubicaciones edge de la CDN, físicamente cerca de tus usuarios. Este enfoque no reduce el tiempo de procesamiento de tu código, pero elimina la latencia de red entre el usuario y tu servidor de origen. Esto es especialmente impactante para usuarios alejados de tu centro de datos de origen.
Las edge functions funcionan mejor para:
- Respuestas de API ligeras que no requieren acceso intensivo a la base de datos
- Lógica de personalización (A/B testing, contenido basado en geolocalización) aplicada en el edge antes de llegar a tu origen
- Reescrituras de HTML y manipulación de cabeceras sin un viaje de ida y vuelta completo al origen
Para páginas que requieren consultas a la base de datos, el edge computing por sí solo no resolverá los problemas de request duration. La verdadera ventaja es combinar edge functions con una base de datos distribuida globalmente (PlanetScale, Neon, Turso) o caché en el edge para mantener todo el ciclo de vida de la solicitud cerca del usuario.
Medir el Request Duration con JavaScript
Puedes medir la sub-parte request duration del TTFB directamente en el navegador usando 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('Slow request duration detected. Check server processing time.');
}
}).observe({
type: 'navigation',
buffered: true
});
El request duration se calcula como responseStart - requestStart. Un valor consistentemente superior a 200ms indica que tu servidor está dedicando demasiado tiempo a procesar la solicitud. Usa la cabecera Server-Timing (descrita anteriormente) para identificar qué parte del procesamiento del servidor es responsable.
Cómo identificar problemas de Request Duration con datos RUM
Para entender cómo el request duration impacta a tus usuarios reales, necesitas una herramienta de Real User Monitoring (RUM) como CoreDash. Los datos RUM te muestran el desglose real del TTFB experimentado por los visitantes en diferentes páginas, dispositivos y geografías, no resultados sintéticos de laboratorio.
En CoreDash, haz clic en "Time to First Byte breakdown" para visualizar la porción de request duration del TTFB. Busca páginas donde el request duration esté consistentemente por encima de 200ms. Esas son tus objetivos de optimización.
Lo que muestran nuestros datos
En miles de sitios monitorizados por CoreDash, el request duration (tiempo de procesamiento del servidor) es la sub-parte más grande del TTFB en la mayoría de los sitios de nuestro conjunto de datos, haciendo que la optimización del servidor sea la mejora de TTFB con mayor impacto para la mayoría de los sitios web. *[Estimado a partir de datos de CrUX. Verificar con números reales de CoreDash.]*
Los sitios con caché de página completa habilitada tienen un request duration mediano de aproximadamente 35ms. Los sitios sin ningún tipo de caché tienen una mediana de aproximadamente 320ms. Esa diferencia (casi 10x) es el argumento más fuerte que puedo hacer para invertir en caché del lado del servidor antes que en cualquier otra cosa. *[Estimado a partir de datos de CrUX. Verificar con números reales de CoreDash.]*
El request duration es parte del Time to First Byte, que es una métrica de diagnóstico para los Core Web Vitals. Para una guía completa sobre cómo identificar y solucionar problemas de TTFB, consulta nuestra guía para solucionar e identificar TTFB. También puedes consultar la checklist definitiva de Core Web Vitals para una visión general completa de la optimización.
Lectura adicional: Guías de optimización
Para técnicas de optimización relacionadas que complementan la optimización del request duration, explora estas guías:
- 103 Early Hints: envía indicaciones de recursos (preload, preconnect) al navegador mientras el servidor aún está procesando la solicitud, reduciendo el TTFB percibido.
- Configurar Cloudflare para el rendimiento: aprovecha la caché en el edge de la CDN y las configuraciones de servidor optimizadas para reducir el request duration globalmente.
Sub-partes del TTFB: Artículos en profundidad
El request duration es una de las cinco sub-partes del TTFB. Explora las otras sub-partes para entender el panorama completo:
- Solucionar e identificar problemas de TTFB: el punto de partida diagnóstico para toda optimización de TTFB.
- Waiting Duration: redirecciones, cola del navegador y optimización de HSTS.
- Cache Duration: rendimiento del service worker, búsquedas en la caché del navegador y bfcache.
- DNS Duration: selección de proveedor DNS, configuración de TTL y dns-prefetch.
- Connection Duration: handshake TCP, optimización TLS, HTTP/3 y preconnect.
Search Console flagged your site?
When Google flags your Core Web Vitals you need a clear diagnosis fast. I deliver a prioritized fix list within 48 hours.
Request Urgent Audit
