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.