Vai al contenuto
EuroVPSEuroVPS

Collo di bottiglia nel server o nell'applicazione: come misurarlo

Il time to first byte a ogni hop, i contatori di margine sulla macchina e uno slow log ordinato per frame bloccante collocano un sito lento in un solo livello prima che qualcosa venga cambiato.

Di EuroVPS EngineeringLa sala macchine

7 min di lettura
In questo articolo 7 sezioni
In breve
  • Misurate il time to first byte a ogni hop: attraverso l'edge, direttamente sull'origin, e su localhost. Il divario più grande tra due numeri adiacenti è il livello a cui appartiene la latenza.
  • Leggete il margine della macchina mentre è lenta: CPU idle e steal, memoria disponibile, await e profondità di coda dei dischi. Margine ovunque sotto un sito lento significa che il vincolo sta sopra l'hardware.
  • Dentro il livello applicativo, aggregate: richieste per URL, richieste lente per frame bloccante, query per digest. Ognuno comprime migliaia di righe in una breve lista ordinata con uno o due nomi in cima.

Il time to first byte a ogni hop

Le teorie su un sito lento sono facili da formulare e difficili da chiudere. Tre misure le chiudono. Prendete il time to first byte attraverso l'edge pubblico, di nuovo direttamente contro l'origin con l'edge aggirato, e di nuovo sull'host dell'applicazione contro localhost. La differenza tra due letture adiacenti è il costo di quel livello.

TERMINAL
# through the edge
curl -s -o /dev/null -w 'dns=%{time_namelookup} tls=%{time_appconnect} ttfb=%{time_starttransfer}\n' https://site.example/

# direct to the origin, edge bypassed
curl -s -o /dev/null -w 'ttfb=%{time_starttransfer}\n' --resolve site.example:443:ORIGIN_IP https://site.example/

# on the host, nothing in front of the application
curl -s -o /dev/null -w 'ttfb=%{time_starttransfer}\n' http://127.0.0.1/

Ciò che resta su localhost è l'applicazione e i servizi che chiama. Il livello con il divario più grande è dove va il resto del lavoro.

Il margine mentre fa male

Leggete i contatori durante il periodo lento, non dopo.

TERMINAL
vmstat 1 5        # r (run queue), wa (I/O wait), st (steal), id (idle)
iostat -x 1 5     # await and aqu-sz per device
free -m           # the available column, not used

Una run queue lunga con poco idle è una macchina limitata dalla CPU. Un I/O wait alto con await alto sul dispositivo è lo storage. Lo steal è un vicino su un hypervisor condiviso che si prende cicli che il guest voleva. CPU idle, memoria disponibile e dispositivi con await basso sotto un sito lento significano che la macchina sta aspettando qualcosa che non le appartiene: una chiamata esterna, un lock, una query lenta per ragioni diverse dall'hardware. Aggiungere hardware a quel punto produce una macchina più scarica che è ancora lenta.

C'è una terza categoria tra le due, ed è comune: il pool. La pagina di stato di PHP-FPM mostra una listen queue; una coda di richieste in attesa con CPU idle significa che ogni worker è occupato, di solito bloccato sulla stessa chiamata lenta, e il sito è lento per un tetto di configurazione, non per un tetto di risorse. La stessa forma compare come un pool di connessioni al database saturo o una coda di backend HAProxy piena. La macchina è innocente e il codice non è ancora stato condannato; la dimensione del pool e la chiamata su cui sta aspettando sono le prossime due letture.

Leggete il traffico prima del codice

L'access log dice che tipo di problema è questo. Trovate prima il log per vhost; il log predefinito può contenere una piccola frazione del traffico reale, e un conteggio sul file sbagliato dà una risposta sbagliata con grande sicurezza.

TERMINAL
tail -n 100000 access.log | awk -F'"' '{print $2}' | sort | uniq -c | sort -rn | head

Poche URL ripetute migliaia di volte è il sito che chiama sé stesso, e la soluzione è una cache davanti a quelle URL. Richieste che marciano in ordine di sitemap sono un crawler, e la soluzione è un rate limit. Un aumento ampio e uniforme su molte URL è domanda, e la soluzione è capacità.

Comprimete lo slow log e il log delle query

Uno slow log è un mucchio di stack trace finché non viene indicizzato per chiave. Attivate lo slow log di PHP-FPM con una soglia che catturi le richieste di cui gli utenti si lamentano, poi indicizzate ogni traccia sul frame in cui era bloccata, la foglia, e contate. La lista ordinata è breve e in cima c'è di solito una chiamata esterna o una query.

Sul lato database, ordinate per digest, non per piano. Una parametrizzazione incoerente spezza una singola query logica in molti piani che sembrano ciascuno innocuo; sommati per digest, il vero proprietario del tempo del database si ricompone in una riga.

TERMINAL
-- MySQL and Percona: by statement digest
SELECT digest_text, count_star, sum_timer_wait
FROM performance_schema.events_statements_summary_by_digest
ORDER BY sum_timer_wait DESC
LIMIT 10;

-- SQL Server: by query hash
SELECT query_hash, COUNT(*) AS plans, SUM(total_worker_time) AS cpu
FROM sys.dm_exec_query_stats
GROUP BY query_hash
ORDER BY cpu DESC;

Prima di scrivere qualsiasi indice, verificate il numero reale di righe e gli indici già esistenti. Un indice su una tabella che non ne ha bisogno è un percorso di scrittura più lento.

Leggete la fonte primaria, non una storia plausibile

La storiaLa fonte che la chiude
È andato in crash, ha finito la memoriadmesg, journalctl --list-boots, last -x reboot: ha fatto reboot, e perché
Il database è corrottol'error log del database stesso, cercando i messaggi di crash e di corruzione
Un processo impazzito sta mangiando la CPUps --forest e /proc/<pid>/cmdline: la sua vera identità e il suo padre, non un nome plausibile
Vediamo errori di integritàethtool -S sull'interfaccia: zero errori sul cavo significa che il problema sta sopra il cavo
SELinux lo sta bloccandoausearch -m avc -ts recent passato a audit2why: il diniego, nominato, con il modulo di policy che lo risolve

Ogni riga sostituisce una teoria con una lettura. L'ultima conta su un sistema in enforcing: l'audit log risponde alla domanda senza cambiare la postura di sicurezza per porla.

Dimostratelo, poi verificate con la stessa misura

La correlazione dà un sospetto. Una piccola perturbazione reversibile lo condanna: fermate le query sospette per qualche secondo e guardate se il carico si riempie di nuovo. Se si riempie subito, il traffico live è il motore e la correzione va all'edge, davanti alle richieste che non dovrebbero raggiungere affatto il database. Finché la causa non è nota, il sistema è in sola lettura. Quando la correzione è in produzione, si verifica con la misura che ha trovato il problema: se il time to first byte per hop lo ha localizzato, il time to first byte per hop conferma che è sparito.

Cosa sistemiamo noi e cosa vi restituiamo

All'edge, lo stesso giornoNel vostro codice, con la modifica esatta
Micro-caching con collapsing delle richieste davanti alle URL caldeSpostare la chiamata sincrona a terze parti in un job in background con un timeout e un fallback
Pool di worker e di buffer dimensionati sul carico misuratoRimuovere il ciclo di rendering o il ciclo di retry
Un indice covering aggiunto onlineFar scadere i dati applicativi che crescono senza limite
Retry e timeout di HAProxy ottimizzati, un contesto SELinux correttoRidurre il payload e gli script spediti al browser

Non modifichiamo il vostro codice. Nominiamo la riga, mostriamo la misura che la indica e teniamo su il sito mentre la sistemate.

Risposte dirette

Come faccio a sapere se è il mio server o la mia applicazione a essere lenta?+

Leggete il margine durante il periodo lento: CPU idle e steal, memoria disponibile, await dei dischi. Se tutti e tre hanno spazio, il vincolo sta sopra l'hardware, nell'applicazione o in un servizio che chiama. Il time to first byte su localhost confrontato con l'edge conferma quale livello.

Come trovate una query lenta nel database?+

Ordinando per digest, non per plan handle, così che una singola query logica con molte parametrizzazioni mostri il suo costo totale in una riga. Poi verifichiamo i conteggi delle righe e gli indici esistenti prima di scrivere qualsiasi DDL.

Sapete distinguere un bot da un picco di traffico reale?+

Dall'access log, per frequenza delle URL. Una manciata di URL ripetute migliaia di volte è il sito che chiama sé stesso, l'ordine di sitemap è un crawler, un aumento ampio è domanda. Ciascuno ha una correzione diversa.

Modificate il mio codice?+

No. Tutto ciò che sta sul lato infrastruttura lo sistemiamo all'edge lo stesso giorno, in modo reversibile. Tutto ciò che sta nel vostro codice ve lo restituiamo come modifica esatta, con la misura che la giustifica.

Il vostro sito è lento e nessuno è d'accordo sul perché.

Parlate con un ingegnere che misura ogni hop prima di toccare qualsiasi cosa.

Parla con un ingegnere

Siete arrivati alla fine.

Mettete la lettura al lavoro

Cosa fate girare?

Raccontateci il carico di lavoro, il traffico e i requisiti di ripristino. Partite dal configuratore di server, oppure discutete i dettagli con un ingegnere.

Scritto dagli ingegneri che costruiscono e gestiscono l'infrastruttura che descrive.
Parla con un ingegnere
XIn

7 min rimasti