Ottimizzazione delle prestazioni di un server Apache ad alto carico


12

Sto cercando di capire alcuni problemi di prestazioni del server che sto vedendo con un (per noi) server Web pesantemente caricato. L'ambiente è il seguente:

  • Debian Lenny (tutti i pacchetti stabili + patchato agli aggiornamenti di sicurezza)
  • Apache 2.2.9
  • PHP 5.2.6
  • Grande istanza di Amazon EC2

Il comportamento che stiamo riscontrando è che il Web in genere sembra reattivo, ma con un leggero ritardo per iniziare a gestire una richiesta, a volte una frazione di secondo, a volte 2-3 secondi nei nostri periodi di picco di utilizzo. Il carico effettivo sul server viene segnalato come molto elevato, spesso 10.xx o 20.xx come riportato da top. Inoltre, l'esecuzione di altre cose sul server durante questi periodi (anche vi) è molto lenta, quindi il carico è decisamente lassù. Stranamente Apache rimane molto reattivo, a parte quel ritardo iniziale.

Abbiamo Apache configurato come segue, usando prefork:

StartServers          5
MinSpareServers       5
MaxSpareServers      10
MaxClients          150
MaxRequestsPerChild   0

E KeepAlive come:

KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout 5

Guardando la pagina dello stato del server, anche in questi periodi di carico pesante raramente stiamo colpendo il limite del client, di solito servendo tra 80-100 richieste e molte di quelle nello stato keepalive. Questo mi dice di escludere la lentezza della richiesta iniziale come "attesa di un gestore", ma potrei sbagliarmi.

Il monitoraggio di Amazon CloudWatch mi dice che anche quando il nostro sistema operativo riporta un carico> 15, l'utilizzo della CPU dell'istanza è compreso tra il 75 e l'80%.

Esempio di output da top:

top - 15:47:06 up 31 days,  1:38,  8 users,  load average: 11.46, 7.10, 6.56
Tasks: 221 total,  28 running, 193 sleeping,   0 stopped,   0 zombie
Cpu(s): 66.9%us, 22.1%sy,  0.0%ni,  2.6%id,  3.1%wa,  0.0%hi,  0.7%si,  4.5%st
Mem:   7871900k total,  7850624k used,    21276k free,    68728k buffers
Swap:        0k total,        0k used,        0k free,  3750664k cached

La maggior parte dei processi assomiglia a:

24720 www-data  15   0  202m  26m 4412 S    9  0.3   0:02.97 apache2                                                                       
24530 www-data  15   0  212m  35m 4544 S    7  0.5   0:03.05 apache2                                                                       
24846 www-data  15   0  209m  33m 4420 S    7  0.4   0:01.03 apache2                                                                       
24083 www-data  15   0  211m  35m 4484 S    7  0.5   0:07.14 apache2                                                                       
24615 www-data  15   0  212m  35m 4404 S    7  0.5   0:02.89 apache2            

Esempio di output vmstatcontemporaneamente a quanto sopra:

procs -----------memory---------- ---swap-- -----io---- -system-- ----cpu----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa
 8  0      0 215084  68908 3774864    0    0   154   228    5    7 32 12 42  9
 6 21      0 198948  68936 3775740    0    0   676  2363 4022 1047 56 16  9 15
23  0      0 169460  68936 3776356    0    0   432  1372 3762  835 76 21  0  0
23  1      0 140412  68936 3776648    0    0   280     0 3157  827 70 25  0  0
20  1      0 115892  68936 3776792    0    0   188     8 2802  532 68 24  0  0
 6  1      0 133368  68936 3777780    0    0   752    71 3501  878 67 29  0  1
 0  1      0 146656  68944 3778064    0    0   308  2052 3312  850 38 17 19 24
 2  0      0 202104  68952 3778140    0    0    28    90 2617  700 44 13 33  5
 9  0      0 188960  68956 3778200    0    0     8     0 2226  475 59 17  6  2
 3  0      0 166364  68956 3778252    0    0     0    21 2288  386 65 19  1  0

E infine, l'output di Apache server-status:

Server uptime: 31 days 2 hours 18 minutes 31 seconds
Total accesses: 60102946 - Total Traffic: 974.5 GB
CPU Usage: u209.62 s75.19 cu0 cs0 - .0106% CPU load
22.4 requests/sec - 380.3 kB/second - 17.0 kB/request
107 requests currently being processed, 6 idle workers

C.KKKW..KWWKKWKW.KKKCKK..KKK.KKKK.KK._WK.K.K.KKKKK.K.R.KK..C.C.K
K.C.K..WK_K..KKW_CK.WK..W.KKKWKCKCKW.W_KKKKK.KKWKKKW._KKK.CKK...
KK_KWKKKWKCKCWKK.KKKCK..........................................
................................................................

Dalla mia esperienza limitata traggo le seguenti conclusioni / domande:

  • Potremmo consentire troppe KeepAliverichieste

  • Vedo un po 'di tempo trascorso in attesa di IO in vmstat anche se non in modo coerente e non molto (penso?), Quindi non sono sicuro che questa sia una grande preoccupazione o no, ho meno esperienza con vmstat

  • Anche in vmstat, vedo in alcune iterazioni una serie di processi in attesa di essere serviti, che è ciò a cui sto attribuendo il ritardo di caricamento della pagina iniziale sul nostro server web, possibilmente erroneamente

  • Forniamo una miscela di contenuto statico (75% o superiore) e contenuto dello script, e il contenuto dello script è spesso abbastanza laborioso, quindi è importante trovare il giusto equilibrio tra i due; a lungo termine vogliamo spostare la statistica altrove per ottimizzare entrambi i server, ma il nostro software non è pronto per questo oggi

Sono felice di fornire ulteriori informazioni se qualcuno ha qualche idea, l'altra nota è che si tratta di un'installazione di produzione ad alta disponibilità, quindi sono cauto di apportare modifiche dopo modifica, ed è per questo che non ho giocato con cose come il KeepAlivevalore me stesso ancora.


+1 Grande domanda insanguinata, ben formulata e pensata. Spero che tu abbia la risposta che merita!
Dave Rix,

Risposte:


7

Inizierò ammettendo che non ho molto a che fare con roba nei cloud, ma in base alla mia esperienza altrove, direi che questa configurazione del server web riflette un volume di traffico piuttosto basso. Il fatto che il runqueue sia così grande suggerisce che non ci sia abbastanza CPU disponibile per gestirlo. Cos'altro c'è nel runqueue?

Potremmo consentire troppe richieste KeepAlive

No: keeplive migliora ancora le prestazioni, i browser moderni sono molto intelligenti nel sapere quando eseguire il pipeline e quando eseguire le richieste in parallelo, anche se un timeout di 5 secondi è ancora piuttosto elevato e hai un sacco di server in attesa, a meno che tu ' ho enormi problemi di latenza che consiglierei di portare a 2-3. Questo dovrebbe accorciare un po 'il runqueue.

Se non hai già installato mod_deflate sul server web - ti consiglio di farlo - e aggiungi ob_gzhandler () ai tuoi script PHP. Puoi farlo come prepagamento automatico:

if(!ob_start("ob_gzhandler")) ob_start();

(sì, la copressione utilizza più CPU, ma dovresti risparmiare CPU nel complesso portando i server fuori dalla pista più veloce / gestendo meno pacchetti TCP - e come bonus, il tuo sito è anche più veloce).

Consiglierei di impostare un limite massimo per MaxRequestsPerChild - diciamo qualcosa come 500. Ciò consente solo un po 'di turnover sui processi nel caso in cui tu abbia una perdita di memoria da qualche parte. I tuoi processi httpd sembrano ENORMI: assicurati di aver rimosso tutti i moduli apache che non ti servono e assicurati di pubblicare contenuti statici con buone informazioni di memorizzazione nella cache.

Se continui a riscontrare problemi, il problema è probabilmente all'interno del codice PHP (se passi all'uso di fastCGI, questo dovrebbe essere evidente senza alcuna grave penalizzazione delle prestazioni).

aggiornare

Se il contenuto statico non varia molto tra le pagine, potrebbe anche valere la pena sperimentare:

if (count($_COOKIE)) {
    header('Connection: close');
}

anche sugli script PHP.


Tra una varietà di buone risposte lo segnerò come quello accettato perché hai chiaramente affermato che si trattava di un problema legato alla CPU (in gran parte a causa della scarsa applicazione che stiamo eseguendo) e che certamente era il caso. Ho ridistribuito tutto su istanze EC2 2xlarge (su da grandi) e la maggior parte dei problemi è andata via, sebbene molte delle altre caratteristiche prestazionali siano ancora presenti. Abbiamo solo la singola app in esecuzione su questi server ed è semplicemente brutta.
futuristico

4

Si consiglia di installare un proxy inverso asincrono, poiché anche un certo numero di processi in stato W è piuttosto elevato. I tuoi processi Apache sembrano impiegare molto tempo a inviare contenuti a client lenti su rete bloccandoli. Nginx o lighttpd come frontend per il tuo server Apache può ridurre drasticamente una serie di processi nello stato W. E sì, dovresti limitare un numero di richieste keepalive. Probabilmente vale la pena provare a disattivare keepalive.

A proposito, 107 processi Apache sono troppo alti per 22 rps, sono stato in grado di servire 100-120 rps usando solo 5 processi Apache. Probabilmente, il prossimo passo è profilare la tua applicazione.


Sì, sono decisamente d'accordo sul fatto che l'applicazione rappresenti gran parte del problema. È stato esternalizzato e da allora è stato soggetto a molte patch e quant'altro che ha appena peggiorato la situazione e uno sforzo di riprogettazione è in corso. Stasera ho provato a disattivare KeepAlive senza alcun effetto reale, e il mio prossimo passo è provare quel proxy inverso, probabilmente con nginx basato su tutto ciò che ho letto da allora.
futuristico

Per dare seguito, ho iniziato a sperimentare il proxy inverso e probabilmente lo implementerò in produzione nel prossimo futuro. Grazie (e gli altri che l'hanno suggerito) per l'idea, non è qualcosa con cui avessi mai armeggiato prima, ma penso che avrà un impatto fino a quando non potremo fare una riprogettazione a tutti gli effetti.
futuristico

1

Hai due righe nel tuo vmstat che mostrano che il tempo di attesa della tua CPU è abbastanza alto, e intorno a queste, fai un discreto numero di scritture (io - bo) e cambio di contesto. Guarderei cosa scrivono i blocchi e come eliminare quell'attesa. Penso che si possa trovare il massimo miglioramento nel miglioramento dell'IO del disco. Controlla syslog: impostalo per scrivere in modo asincrono. Assicurati che la cache di scrittura del controller funzioni (controlla: potresti avere una batteria scarica).

Keepalive non sta causando il tuo problema perf, ti fa risparmiare tempo sulla configurazione della connessione se non stai eseguendo una cache di fronte. Potresti aumentare un po 'MaxSpareServers in modo che in uno scricchiolio non aspetti tutte le forcelle.


Non ho abbastanza familiarità con syslog per sapere come impostarlo per le scritture asincrone sotto Apache, anche se certamente cercherò e cercherò quello. Stasera ho apportato alcune modifiche relative a KeepAlive e MaxSpareServers senza alcun effetto reale, concordo sul fatto di lasciare più pezzi di ricambio, mi ero perso. Una (scarsa) qualità della nostra applicazione è che scrive pesantemente nei file di sessione dell'utente (sì, file) che è dove sto cominciando a pensare che stiamo soffrendo. Ho la possibilità di spostare la gestione delle sessioni nel database, che probabilmente proverò dopo.
futuristico

Sì, concordo sul fatto che le scritture di sessione sono la fonte del problema. Se si utilizzano sessioni php, è possibile perdere le scritture del disco di sessione: installare memcache e impostare session.save_handler di PHP su memcache e session.save_path su tcp : //127.0.0.1: 11211 (o ovunque imposti memcache). La registrazione di Apache è asincrona per impostazione predefinita, ma a volte le app Web possono utilizzare syslog o syslog può essere chiacchierone e sta eseguendo una sincronizzazione per ogni linea. Dopo tutto, non sembra che sarebbe il problema nel tuo caso. È possibile aggiungere il prefisso alle righe di immissione dei file con '-' in syslog.conf per omettere la sincronizzazione.
fagioli

0

dovresti considerare di disattivare Keepalive come primo tentativo ...

con 107 richieste elaborate, tenerei MaxSpareServers più alto di quello che hai impostato ...

IMHO nel nginx a lungo termine come proxy inverso per il contenuto statico dovrebbe essere preso in considerazione


0

Primo suggerimento: disabilitare keepalives. Ne ho sempre avuto bisogno solo quando sono riuscito a identificare una situazione specifica in cui le prestazioni sono aumentate, ma in generale le richieste al secondo sono diminuite con Keepalive abilitato.

Secondo suggerimento: impostare un MaxRequestsPerChild. Ripeto echo symcbean qui, aiuterà nel rollover del processo in caso di perdita di memoria. 500 è un buon punto di partenza.

Terzo suggerimento: aumentare MaxClients. Un calcolo a sfera per questo è (memoria fisica - memoria utilizzata da un processo non httpd) / dimensione di ogni processo httpd. A seconda di come è stato compilato httpd, questo numero è massimo di 255. Uso 250 per i miei server pubblici per gestire google / yahoo / MS che eseguono la scansione dei sistemi.

Suggerimento Forth: aumentare MaxSpareServers: qualcosa come 4-5x MinSpareServers.

Escludendo quei suggerimenti che falliscono, osserverei il bilanciamento del carico con reverse-proxy o memcache per DB.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.