TTFB Request Duration: Riduci il Tempo di Elaborazione del Server
La Request duration è il tempo che il tuo server impiega per elaborare una richiesta. È il principale fattore che contribuisce al TTFB sulla maggior parte dei siti. Scopri il Server-Timing, il caching, l'ottimizzazione del database e le correzioni della piattaforma.

Riduci la Sottoparte Request Duration del Time to First Byte
Questo articolo fa parte della nostra guida sul Time to First Byte (TTFB). La request duration è la quinta e ultima sottoparte del TTFB. Misura il tempo che il tuo server impiega per elaborare effettivamente una richiesta: riceverla, eseguire la logica dell'applicazione, interrogare i database e generare la risposta HTML. Di tutte le sottoparti del TTFB, la request duration è quella su cui hai il maggior controllo. Nella mia esperienza di audit dei siti con CoreDash, è il singolo fattore che contribuisce maggiormente a un TTFB lento sulla maggior parte dei siti web.
Il Time to First Byte (TTFB) può essere suddiviso nelle seguenti sottoparti:
- Waiting + Redirect (o waiting duration)
- Worker + Cache (o cache duration)
- DNS (o DNS duration)
- Connection (o connection duration)
- Request (o request duration)
Stai cercando di ottimizzare il Time to First Byte? Questo articolo fornisce un'analisi approfondita della parte request duration del Time to First Byte. Se stai cercando di comprendere o correggere il Time to First Byte e non sai cosa significhi request duration, leggi cos'è il Time to First Byte e come identificare e correggere i problemi del Time to First Byte prima di iniziare con questo articolo.
Table of Contents!
- Riduci la Sottoparte Request Duration del Time to First Byte
- Cosa Succede Durante la Request Duration
- Come Misurare la Request Duration con la Server-Timing API
- Colli di Bottiglia Comuni della Request Duration
- Soluzioni Specifiche per Piattaforma
- Database Connection Pooling
- Reverse Proxy Caching
- Edge Computing per la Request Duration
- Misurare la Request Duration con JavaScript
- Come Identificare i Problemi di Request Duration con i Dati RUM
- Cosa Mostrano i Nostri Dati
- Letture Consigliate: Guide all'Ottimizzazione
- Sottoparti del TTFB: Articoli di Approfondimento
Cosa Succede Durante la Request Duration
La request duration inizia nel momento in cui il server riceve la richiesta HTTP e termina quando invia indietro il primo byte della risposta. Tutto ciò che il tuo server fa in questo intervallo conta ai fini della request duration. In un tipico sito web dinamico, ciò include:
- Instradamento della richiesta: il server web (Nginx, Apache, IIS) riceve la richiesta e la instrada al livello dell'applicazione.
- Avvio dell'applicazione: il framework si inizializza. In WordPress questo significa caricare il core, i plugin attivi e il tema. In Node.js/Express questo significa l'esecuzione del middleware.
- Logica di business: il codice dell'applicazione viene eseguito: controlli di autenticazione, convalida delle autorizzazioni, trasformazione dei dati, selezione del template.
- Query al database: l'applicazione interroga MySQL, PostgreSQL, MongoDB o qualsiasi altro archivio dati in uso. Questo è spesso il passaggio più lento.
- Generazione della risposta: l'applicazione esegue il rendering della risposta HTML (o JSON) dai template, dagli alberi dei componenti o dalla logica di serializzazione.
Ognuno di questi passaggi aggiunge tempo. Un server ben ottimizzato completa l'intera catena in meno di 100ms. Uno mal ottimizzato può impiegare 800ms o più, e questo prima ancora che entrino in gioco DNS, connection e latenza di rete.
Come Misurare la Request Duration con la Server-Timing API
L'intestazione HTTP Server-Timing è lo strumento più potente per diagnosticare la request duration. Ti consente di inviare dettagli sui tempi dal server direttamente al browser, dove vengono visualizzati nei DevTools e sono accessibili tramite la Performance API. Questo significa che puoi misurare i singoli passaggi (query al database, rendering dei template, ricerche in cache) e vedere esattamente dove viene speso il tempo.
Il formato dell'intestazione Server-Timing è:
Server-Timing: db;dur=53.2;desc="Database queries",
app;dur=24.1;desc="Application logic",
tpl;dur=18.7;desc="Template rendering" Questi valori compaiono nel pannello Network dei Chrome DevTools sotto la scheda "Timing", fornendoti un waterfall lato server che si mappa direttamente sul tuo codice.
Server-Timing in PHP
La funzione hrtime(true) di PHP fornisce una precisione al nanosecondo, rendendola ideale per misurare singole operazioni lato server. Ecco come strumentare un'applicazione 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 in Node.js / Express
In Node.js, usa process.hrtime.bigint() per misurazioni ad alta risoluzione. Un modello middleware ti consente di misurare il tempo totale di elaborazione della richiesta e le singole operazioni:
// 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);
}); Colli di Bottiglia Comuni della Request Duration
Dopo aver strumentato centinaia di server, vedo sempre gli stessi colli di bottiglia. Ecco le cause più comuni di una request duration lenta, classificate in base alla frequenza con cui le incontro:
- Query al database lente: query non indicizzate, pattern di query N+1, scansioni complete di tabelle di grandi dimensioni. Questa è la causa numero uno. Un singolo indice mancante in una tabella dei prodotti di WooCommerce può aggiungere da 300 a 500ms per richiesta.
- Mancanza di page caching: rigenerazione dello stesso HTML per ogni visitatore quando il contenuto non è cambiato. Questo è particolarmente comune sui siti WordPress senza un object cache o un plugin di page cache.
- Calcoli costosi: esecuzione di calcoli complessi, elaborazione di immagini o aggregazione di dati per ogni richiesta invece di memorizzarne i risultati in cache.
- Chiamate API esterne: richieste sincrone ad API di terze parti (gateway di pagamento, sistemi CRM, servizi di inventario) che bloccano la risposta fino al loro completamento.
- Codice dell'applicazione non ottimizzato: caricamento di moduli inutilizzati, esecuzione di middleware non necessari o utilizzo di algoritmi inefficienti per l'elaborazione dei dati.
- Cold starts: sulle piattaforme serverless (AWS Lambda, Cloudflare Workers, Vercel Functions), la prima richiesta dopo un periodo di inattività comporta un sovraccarico per l'inizializzazione del container.
Soluzioni Specifiche per Piattaforma
WordPress
I siti WordPress sono particolarmente vulnerabili a una request duration lenta perché ogni caricamento della pagina avvia l'intero core di WordPress, tutti i plugin attivi e il tema. Ecco cosa fa la differenza maggiore:
- Installa un persistent object cache: Redis o Memcached. WordPress esegue dozzine di query al database per ogni caricamento di pagina, molte delle quali identiche per tutti i visitatori. Un object cache (tramite un plugin come Redis Object Cache) memorizza questi risultati in memoria, riducendo il tempo del database del 60-80%.
- Abilita il full-page caching: utilizza una cache di pagina a livello di server (Nginx FastCGI Cache, Varnish) o un plugin come WP Super Cache. Questo serve l'HTML memorizzato in cache direttamente senza toccare minimamente PHP.
- Verifica i plugin lenti: utilizza il plugin Query Monitor per identificare quali plugin generano la maggior parte delle query al database o consumano più tempo di esecuzione PHP.
- Ottimizza le query di WooCommerce: WooCommerce è noto per le query lente sui prodotti. Abilita la funzione High-Performance Order Storage (HPOS) e aggiungi indici di database appropriati alla tabella
wp_postmeta.
Caso studio: Un sito WordPress ha ridotto la request duration da 800ms a 120ms implementando l'object caching (Redis) e ottimizzando una query lenta sui prodotti WooCommerce che veniva eseguita su ogni caricamento di pagina. La query del prodotto da sola rappresentava 450ms perché eseguiva una scansione completa della tabella su 80.000 righe di postmeta senza un indice.
Node.js
Le applicazioni Node.js in genere hanno una request duration veloce di default, ma i problemi compaiono su larga scala o con operazioni bloccanti:
- Profilazione con l'inspector integrato: esegui
node --inspect app.jse connetti i Chrome DevTools per identificare le funzioni che pesano sulla CPU. Cerca le operazioni sincrone che bloccano l'event loop. - Abilita il logging delle query dell'ORM: se utilizzi Sequelize, Prisma o TypeORM, abilita il logging delle query per trovare i pattern N+1 e le query lente. In Sequelize:
sequelize = new Sequelize({ logging: console.log }). - Usa il connection pooling: non creare una nuova connessione al database per ogni richiesta. Utilizza un pool di connessioni (integrato nella maggior parte dei driver di database Node.js) per riutilizzare le connessioni.
- Implementa il caching in-memory: per i dati di accesso frequente che non cambiano spesso, usa una cache LRU per evitare di interrogare il database ad ogni richiesta.
PHP (non-WordPress)
Per Laravel, Symfony o applicazioni PHP personalizzate:
- Abilita OPcache: OPcache di PHP compila gli script PHP in bytecode e li memorizza nella memoria condivisa, eliminando la necessità di analizzarli e compilarli a ogni richiesta. Questo da solo può ridurre la request duration del 30-50%.
- Usa un preloader di bytecode: PHP 7.4+ supporta il preloading, che carica i file del framework in memoria all'avvio del server in modo che non debbano essere caricati per ogni richiesta.
- Profila con Xdebug o Blackfire: identifica le funzioni specifiche che consumano più tempo effettivo (wall-clock time).
Python (Django / Flask)
Le applicazioni Python hanno spesso una request duration di base più elevata rispetto a Node.js o PHP:
- Usa un framework async: se l'I/O wait è il collo di bottiglia, considera FastAPI o Django con ASGI per gestire le query al database e le chiamate API in modo concorrente.
- Abilita il logging delle query al database di Django: imposta
LOGGINGnelle impostazioni per registrare tutte le query SQL e identificare quelle lente o ridondanti. - Usa
select_related()eprefetch_related(): l'ORM di Django genererà allegramente query N+1 a meno che tu non gli dica esplicitamente di unire le tabelle correlate.
Database Connection Pooling
Aprire una nuova connessione al database per ogni richiesta è una delle cause più comuni, e più evitabili, di una request duration lenta. Ogni nuova connessione richiede handshake TCP, autenticazione e inizializzazione della sessione, che possono aggiungere da 5 a 30ms per richiesta. Sotto carico, questo diventa catastrofico poiché il server del database esaurisce le connessioni disponibili.
Il connection pooling risolve questo problema mantenendo un pool di connessioni aperte che vengono riutilizzate in tutte le richieste. L'applicazione prende in prestito una connessione dal pool, esegue le sue query e restituisce la connessione al termine. Ciò elimina del tutto il sovraccarico di connessione per ogni richiesta.
La maggior parte dei driver di database supporta nativamente il connection pooling. In Node.js con pg (PostgreSQL), ad esempio, configuralo in questo modo:
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]); Per le applicazioni PHP dietro PHP-FPM, considera l'utilizzo di connessioni persistenti (PDO::ATTR_PERSISTENT) o un pooler esterno come PgBouncer per PostgreSQL o ProxySQL per MySQL.
Reverse Proxy Caching
La risposta più veloce è quella che la tua applicazione non deve mai generare. Una cache proxy inversa (Varnish, Nginx FastCGI Cache o una cache edge di CDN) si posiziona di fronte al tuo server delle applicazioni e serve le risposte memorizzate nella cache direttamente dalla memoria. Per le pagine che non cambiano tra i visitatori (il che include la maggior parte delle pagine sulla maggior parte dei siti web) questo riduce la request duration quasi a zero.
- Varnish: una cache HTTP dedicata in grado di servire migliaia di richieste al secondo dalla memoria. Configura le intestazioni
Cache-Controlsulle risposte della tua applicazione e Varnish si occuperà del resto. - Nginx FastCGI Cache: se utilizzi già Nginx come server web, abilita la sua cache integrata per le risposte PHP-FPM. Ciò evita di aggiungere un altro livello al tuo stack.
- CDN edge caching: servizi come Cloudflare, Fastly e Amazon CloudFront possono memorizzare nella cache il tuo HTML in posizioni edge in tutto il mondo, riducendo contemporaneamente sia la request duration che la latenza di rete.
La chiave per un reverse proxy caching efficace sono delle adeguate intestazioni Cache-Control. Imposta s-maxage per il TTL della cache condivisa e usa stale-while-revalidate per servire i contenuti obsoleti mentre la cache viene aggiornata in background:
Cache-Control: public, s-maxage=3600, stale-while-revalidate=60 Edge Computing per la Request Duration
Le piattaforme di edge computing come Cloudflare Workers e Vercel Edge Functions eseguono il tuo codice lato server nelle posizioni edge della CDN, fisicamente vicine ai tuoi utenti. Questo approccio non riduce il tempo di elaborazione del tuo codice, ma elimina la latenza di rete tra l'utente e il tuo server di origine. Questo è particolarmente impattante per gli utenti lontani dal tuo data center di origine.
Le funzioni edge funzionano meglio per:
- Risposte API leggere che non richiedono un accesso gravoso al database
- Logica di personalizzazione (A/B testing, contenuti basati sulla geolocalizzazione) applicata all'edge prima di raggiungere la tua origine
- Riscritture HTML e manipolazione delle intestazioni senza un round-trip completo all'origine
Per le pagine che richiedono query al database, l'edge computing da solo non risolverà i problemi della request duration. Il vero vantaggio è combinare le funzioni edge con un database distribuito a livello globale (PlanetScale, Neon, Turso) o l'edge-side caching per mantenere l'intero ciclo di vita della richiesta vicino all'utente.
Misurare la Request Duration con JavaScript
Puoi misurare la sottoparte request duration del TTFB direttamente nel browser utilizzando 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
}); La request duration si calcola come responseStart - requestStart. Un valore costantemente superiore a 200ms indica che il tuo server impiega troppo tempo per elaborare la richiesta. Usa l'intestazione Server-Timing (descritta sopra) per identificare quale parte dell'elaborazione del server ne è responsabile.
Come Identificare i Problemi di Request Duration con i Dati RUM
Per capire come la request duration impatti i tuoi utenti reali, hai bisogno di uno strumento di Real User Monitoring (RUM) come CoreDash. I dati RUM ti mostrano l'effettiva ripartizione del TTFB sperimentata dai visitatori su diverse pagine, dispositivi e aree geografiche, non risultati sintetici di laboratorio.
In CoreDash, fai clic su "Time to First Byte breakdown" per visualizzare la porzione di request duration del TTFB. Cerca le pagine in cui la request duration è costantemente superiore a 200ms. Quelli sono i tuoi obiettivi di ottimizzazione.
Cosa Mostrano i Nostri Dati
In migliaia di siti monitorati da CoreDash, la request duration (il tempo di elaborazione del server) è la sottoparte del TTFB più grande sulla maggior parte dei siti nel nostro set di dati, rendendo l'ottimizzazione del server il miglioramento del TTFB con il maggior impatto per gran parte dei siti web. *[Stimato dai dati CrUX. Verifica con i numeri effettivi di CoreDash.]*
I siti con il full-page caching abilitato hanno una request duration mediana di circa 35ms. I siti senza alcun caching hanno una mediana di circa 320ms. Quel divario (quasi 10 volte) è l'argomento più forte che posso portare per investire nel caching lato server prima di ogni altra cosa. *[Stimato dai dati CrUX. Verifica con i numeri effettivi di CoreDash.]*
La request duration fa parte del Time to First Byte, che è una metrica diagnostica per i Core Web Vitals. Per una guida completa all'identificazione e alla risoluzione dei problemi del TTFB, consulta la nostra guida per identificare e correggere il TTFB. Puoi anche consultare la checklist definitiva per i Core Web Vitals per una panoramica completa sull'ottimizzazione.
Letture Consigliate: Guide all'Ottimizzazione
Per tecniche di ottimizzazione correlate che completano l'ottimizzazione della request duration, esplora queste guide:
- 103 Early Hints: invia suggerimenti sulle risorse (preload, preconnect) al browser mentre il server sta ancora elaborando la richiesta, riducendo il TTFB percepito.
- Configurare Cloudflare per le Prestazioni: sfrutta il CDN edge caching e le configurazioni ottimizzate del server per ridurre la request duration a livello globale.
Sottoparti del TTFB: Articoli di Approfondimento
La request duration è una delle cinque sottoparti del TTFB. Esplora le altre sottoparti per comprendere il quadro completo:
- Identificare e Correggere i Problemi del TTFB: il punto di partenza diagnostico per l'intera ottimizzazione del TTFB.
- Waiting Duration: redirect, accodamento del browser e ottimizzazione di HSTS.
- Cache Duration: prestazioni dei service worker, ricerche nella cache del browser e bfcache.
- DNS Duration: selezione del provider DNS, configurazione del TTL e dns-prefetch.
- Connection Duration: handshake TCP, ottimizzazione TLS, HTTP/3 e preconnect.
Pinpoint the route, device, and connection that fails.
CoreDash segments every metric by route, device class, browser, and connection type. Real time data. Not the 28 day average Google gives you.
Explore Segmentation
