Le prestazioni di Apache si riducono notevolmente al di sopra di ~ 256 richieste simultanee


14

Sto gestendo un sito a traffico relativamente basso che subisce un forte picco di visitatori una volta alla settimana a seguito di un aggiornamento del sito. Durante questo picco, le prestazioni del sito sono estremamente scarse rispetto al resto della settimana. Il carico effettivo sui server rimane molto basso, affidabile sotto il 10% di CPU e sotto il 30% di RAM (l'hardware dovrebbe essere un overkill completo per quello che stiamo effettivamente facendo), ma per qualche ragione Apache sembra non essere in grado di far fronte alla quantità di richieste. Stiamo eseguendo apache 2.2.3 su RHEL 5.7, kernel 2.6.18-274.7.1.el5, x86_64.

Tentando di riprodurre questo comportamento durante le ore di inattività con ab, sto riscontrando un calo significativo delle prestazioni quando si superano circa 256 utenti. Eseguendo il test con il più piccolo caso d'uso che ho potuto trovare (il file di testo statico viene recuperato, 223 byte in totale) le prestazioni sono costantemente normali con 245 richieste simultanee:

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:       15   25   5.8     24      37
Processing:    15   65  22.9     76      96
Waiting:       15   64  23.0     76      96
Total:         30   90  27.4    100     125

Percentage of the requests served within a certain time (ms)
  50%    100
  66%    108
  75%    111
  80%    113
  90%    118
  95%    120
  98%    122
  99%    123
 100%    125 (longest request)

Ma non appena eseguo il cricchetto di un massimo di 265 richieste simultanee, un sottoinsieme di esse inizia a richiedere un tempo assurdo per il completamento:

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:       13  195 692.6     26    3028
Processing:    15   65  21.3     72     100
Waiting:       15   65  21.3     71      99
Total:         32  260 681.7    101    3058

Percentage of the requests served within a certain time (ms)
  50%    101
  66%    108
  75%    112
  80%    116
  90%    121
  95%   3028
  98%   3040
  99%   3044
 100%   3058 (longest request)

Questi risultati sono molto coerenti su più corse. Dato che c'è altro traffico diretto verso quella casella, non sono sicuro di dove si troverebbe il limite massimo, se ce n'è uno, ma sembra essere sospettosamente vicino a 256.

Naturalmente, supponevo che ciò fosse causato dal limite di thread in prefork, quindi sono andato avanti e ho regolato la configurazione per raddoppiare il numero di thread disponibili e per impedire che il pool di thread si espandesse e si restringesse inutilmente:

<IfModule prefork.c>
StartServers     512
MinSpareServers  512
MaxSpareServers  512
ServerLimit      512
MaxClients       512
MaxRequestsPerChild  5000
</IfModule>

mod_status conferma che ora sto correndo con 512 thread disponibili

8 requests currently being processed, 504 idle workers

Tuttavia, tentare 265 richieste simultanee produce ancora risultati quasi identici a prima

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:       25  211 714.7     31    3034
Processing:    17   94  28.6    103     138
Waiting:       17   93  28.5    103     138
Total:         57  306 700.8    138    3071

Percentage of the requests served within a certain time (ms)
  50%    138
  66%    145
  75%    150
  80%    161
  90%    167
  95%   3066
  98%   3068
  99%   3068
 100%   3071 (longest request)

Dopo aver analizzato la documentazione (e Stack Exchange) non riesco a trovare ulteriori impostazioni di configurazione per tentare di risolvere questo collo di bottiglia. C'è qualcosa che mi manca? Dovrei iniziare a cercare risposte al di fuori di Apache? Qualcun altro ha visto questo comportamento? Qualsiasi aiuto sarebbe molto apprezzato.

MODIFICARE:

Secondo il consiglio di Ladadadada, ho corso contro Apache. Ho provato con -tt e -T alcune volte e non sono riuscito a trovare nulla di straordinario. Ho quindi provato a eseguire strace -c su tutti i processi apache attualmente in esecuzione e ho ottenuto questo:

% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 22.09    0.317836           5     62128      4833 open
 19.91    0.286388           4     65374      1896 lstat
 13.06    0.187854           0    407433           pread
 10.70    0.153862           6     27076           semop
  7.88    0.113343           3     38598           poll
  6.86    0.098694           1    100954     14380 read

(... abdridged)

Se sto leggendo questo diritto (e sopporto con me, poiché non uso molto spesso lo strace) nessuna delle chiamate di sistema può tenere conto del tempo impiegato da queste richieste. Sembra quasi che il collo di bottiglia si verifichi prima ancora che le richieste arrivino ai thread di lavoro.

MODIFICA 2:

Come suggerito da diverse persone, ho eseguito nuovamente il test sul server Web stesso (in precedenza il test veniva eseguito da una posizione Internet neutrale). I risultati sono stati sorprendenti:

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0   11   6.6     12      21
Processing:     5  247 971.0     10    4204
Waiting:        3  245 971.3      7    4204
Total:         16  259 973.3     21    4225

Percentage of the requests served within a certain time (ms)
  50%     21
  66%     23
  75%     24
  80%     24
  90%     26
  95%   4225
  98%   4225
  99%   4225
 100%   4225 (longest request)

Il tempo di chiusura è simile al test basato su Internet, ma sembra essere costantemente un po ' peggio quando eseguito localmente. Ancora più interessante, il profilo è cambiato radicalmente. Considerando che prima che la maggior parte delle richieste di lunga durata fosse trascorsa in "connessione" ora il collo di bottiglia sembra essere in elaborazione o in attesa. Sono lasciato a sospettare che questo potrebbe effettivamente essere un problema separato che era precedentemente mascherato da limitazioni della rete.

Eseguendo nuovamente il test da un'altra macchina sulla stessa rete locale dell'host Apache, vedo risultati molto più ragionevoli:

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        1    2   0.8      2       4
Processing:    13  118  99.8    205     222
Waiting:       13  118  99.7    204     222
Total:         15  121  99.7    207     225

Percentage of the requests served within a certain time (ms)
  50%    207
  66%    219
  75%    220
  80%    221
  90%    222
  95%    224
  98%    224
  99%    225
 100%    225 (longest request)

Questi due test insieme sollevano una serie di domande, ma separatamente da quello, ora c'è un caso convincente da fare per un qualche tipo di grave collo di bottiglia della rete che si verifica sotto un certo carico. Penso che i prossimi passi riguarderanno il livello di rete separatamente.


Opzioni da considerare: CloudFlare, drupal.org/project/boost , CDN, Varnish cache.
Ceejayoz,

Non ci stai dicendo nulla su ciò che questo server sta facendo (nel mondo reale) oltre a servire le richieste HTTP. Esiste un database (o qualche altra risorsa comune che potrebbe soffrire di contese di blocco)? Se il problema si verifica improvvisamente a ESATTAMENTE 256 richieste (OK a 255), è probabile che alcune risorse esterne vengano sommerse. (Anche il tuo salto in una pagina statica è decisamente anormale - vedi la risposta di Ladadadada per alcuni suggerimenti di debug)
voretaq7

ceejayoz: apprezzo i suggerimenti, ma fondamentalmente credo che Apache non dovrebbe essere così lento. Ci sono molte cose che possiamo fare per mitigare l'effetto del problema, ma preferirei molto risolvere o almeno capirlo.
cmckendry,

voretaq7: inizialmente stavo pensando su queste stesse linee, poiché una richiesta tipica avrebbe coinvolto anche php / mysql, ma il problema persiste alla stessa soglia anche quando si tratta di contenuti completamente statici.
cmckendry,

1
È un vero server o una macchina virtuale? Fai il test da localhost, rete locale o Internet? Tempi di risposta minimi in un intervallo di 100 ms suggeriscono test da Internet. Prova a provare da localhost - forse il tuo provider ti sta limitando.
Tometzky,

Risposte:


4

Quello che vorrei fare in questa situazione è eseguito

strace -f -p <PID> -tt -T -s 500 -o trace.txt

su uno dei processi Apache durante il test ab fino a quando non acquisisci una delle risposte lente. Quindi dai un'occhiata trace.txt.

Le opzioni -tte -Tforniscono timestamp di inizio e durata di ciascuna chiamata di sistema per aiutare a identificare quelle lente.

Potresti trovare una singola chiamata di sistema lenta come open()o stat()o potresti trovare una chiamata rapida con (possibilmente più) poll()chiamate direttamente dopo di essa. Se ne trovi uno che funziona su un file o su una connessione di rete (molto probabilmente) guarda indietro attraverso la traccia fino a trovare quel file o l'handle di connessione. Le chiamate precedenti su quello stesso handle dovrebbero darti un'idea di ciò che poll()stava aspettando.


Buona idea guardando l' -copzione. Ti sei assicurato che il bambino Apache che stavi tracciando avesse servito almeno una delle richieste lente in quel periodo? (Non sono nemmeno sicuro di come lo faresti oltre a correre stracecontemporaneamente su tutti i bambini.)

Sfortunatamente, stracenon ci fornisce il quadro completo di ciò che sta facendo un programma in esecuzione. Tiene traccia solo delle chiamate di sistema. Molto può accadere all'interno di un programma che non richiede di chiedere nulla al kernel. Per capire se questo sta accadendo, puoi guardare i timestamp dell'inizio di ogni chiamata di sistema. Se vedi lacune significative, è lì che sta andando il tempo. Questo non è facilmente intercettabile e ci sono sempre piccoli spazi tra le chiamate di sistema.

Dal momento che hai detto che l'utilizzo della CPU rimane basso, probabilmente non si verificano eventi eccessivi tra le chiamate di sistema, ma vale la pena verificarlo.


Osservando più da vicino l'output di ab:

L'improvviso salto nei tempi di risposta (sembra che non ci siano tempi di risposta compresi tra 150 e 3000 ms) suggerisce che si sta verificando un timeout specifico da qualche parte che viene attivato sopra circa 256 connessioni simultanee. Ci si aspetterebbe un degrado più regolare se si esaurissero i normali cicli di RAM o CPU.

In secondo luogo, la abrisposta lenta mostra che i 3000ms sono stati spesi nella connectfase. Quasi tutti hanno impiegato circa 30 ms, ma il 5% ha impiegato 3000 ms. Ciò suggerisce che la rete è il problema.

Da dove vieni ab? Puoi provarlo dalla stessa rete della macchina Apache?

Per ulteriori dati, prova a eseguire tcpdumpsu entrambe le estremità della connessione (preferibilmente con l' ntpesecuzione su entrambe le estremità in modo da poter sincronizzare le due acquisizioni) e cercare eventuali ritrasmissioni tcp. Wireshark è particolarmente utile per analizzare le discariche poiché evidenzia le ritrasmissioni di TC in un colore diverso, rendendole facili da trovare.

Potrebbe anche valere la pena esaminare i registri di tutti i dispositivi di rete a cui hai accesso. Di recente ho riscontrato un problema con uno dei nostri firewall in cui poteva gestire la larghezza di banda in termini di kb / s ma non riusciva a gestire il numero di pacchetti al secondo che riceveva. Ha superato 140.000 pacchetti al secondo. Alcuni rapidi calcoli sulla tua abcorsa mi portano a credere che avresti visto circa 13.000 pacchetti al secondo (ignorando il 5% delle richieste lente). Forse questo è il collo di bottiglia che hai raggiunto. Il fatto che ciò accada intorno a 256 potrebbe essere puramente una coincidenza.

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.