Ich betreibe eine Website mit relativ geringem Datenverkehr, bei der nach einer Aktualisierung der Website einmal pro Woche ein hoher Besucheranstieg zu verzeichnen ist. Während dieses Anstiegs ist die Leistung der Website im Vergleich zum Rest der Woche extrem schlecht. Die tatsächliche Auslastung der Server bleibt sehr gering, zuverlässig unter 10% CPU und unter 30% RAM (die Hardware sollte für das, was wir tatsächlich tun, völlig überfordert sein), aber aus irgendeinem Grund scheint Apache nicht in der Lage zu sein, mit der Menge fertig zu werden von Anfragen. Wir führen Apache 2.2.3 auf RHEL 5.7, Kernel 2.6.18-274.7.1.el5, x86_64 aus.
Beim Versuch, dieses Verhalten außerhalb der Geschäftszeiten mit ab zu reproduzieren, ist bei mehr als 256 Benutzern ein erheblicher Leistungseinbruch zu verzeichnen. Die Ausführung des Tests mit dem kleinstmöglichen Anwendungsfall (Abrufen einer statischen Textdatei mit insgesamt 223 Byte) ist bei 245 gleichzeitigen Anforderungen durchweg normal:
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)
Sobald ich jedoch bis zu 265 Anfragen gleichzeitig bearbeitet habe, nimmt sich eine Teilmenge der Anfragen absurd viel Zeit:
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)
Diese Ergebnisse sind über mehrere Läufe hinweg sehr konsistent. Da zu dieser Box noch weiterer Datenverkehr führt, bin ich mir nicht sicher, wo genau die harte Grenze liegen würde, wenn es eine gibt, aber sie scheint verdächtig nahe bei 256 zu liegen.
Natürlich habe ich angenommen, dass dies durch das Thread-Limit in prefork verursacht wurde. Deshalb habe ich die Konfiguration angepasst, um die Anzahl der verfügbaren Threads zu verdoppeln und zu verhindern, dass der Thread-Pool unnötig wächst und schrumpft:
<IfModule prefork.c>
StartServers 512
MinSpareServers 512
MaxSpareServers 512
ServerLimit 512
MaxClients 512
MaxRequestsPerChild 5000
</IfModule>
mod_status bestätigt, dass ich jetzt mit 512 verfügbaren Threads arbeite
8 requests currently being processed, 504 idle workers
Der Versuch, 265 gleichzeitige Anfragen zu stellen, führt jedoch immer noch zu nahezu identischen Ergebnissen wie zuvor
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)
Nach dem Durchsuchen der Dokumentation (und des Stapelaustauschs) kann ich keine weiteren Konfigurationseinstellungen vornehmen, um diesen Engpass zu beheben. Fehlt mir etwas? Soll ich nach Antworten außerhalb von Apache suchen? Hat jemand anderes dieses Verhalten gesehen? Jede Hilfe wäre sehr dankbar.
BEARBEITEN:
Gemäß Ladadadadas Rat bin ich gegen Apache vorgegangen. Ich habe es ein paar Mal mit -tt und -T versucht und konnte nichts Außergewöhnliches finden. Ich habe dann versucht, strace -c für alle derzeit ausgeführten Apache-Prozesse auszuführen und habe Folgendes erhalten:
% 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
(... gekürzt)
Wenn ich dies richtig lese (und mit mir ertrage, da ich strace nicht sehr oft verwende), kann keiner der Systemaufrufe die Zeit berücksichtigen, die diese Anforderungen in Anspruch nehmen. Es sieht fast so aus, als ob der Engpass auftritt, bevor die Anforderungen überhaupt an die Worker-Threads gelangen.
EDIT 2:
Wie von mehreren Personen vorgeschlagen, habe ich den Test erneut auf dem Webserver selbst ausgeführt (zuvor wurde der Test von einem neutralen Internetstandort aus ausgeführt). Die Ergebnisse waren überraschend:
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)
Die Endzeit ähnelt dem internetbasierten Test, scheint jedoch bei lokaler Ausführung durchweg etwas schlechter zu sein . Interessanterweise hat sich das Profil dramatisch geändert. Während zuvor der Großteil der Zeit der lang laufenden Anfragen für "Verbinden" aufgewendet wurde, scheint der Engpass in der Verarbeitung oder im Warten zu liegen. Ich muss vermuten, dass dies tatsächlich ein separates Problem ist, das zuvor durch Netzwerkeinschränkungen maskiert war.
Beim erneuten Ausführen des Tests von einem anderen Computer im selben lokalen Netzwerk wie der Apache-Host werden viel vernünftigere Ergebnisse angezeigt:
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)
Diese beiden Tests werfen zusammen eine Reihe von Fragen auf, aber unabhängig davon gibt es jetzt einen zwingenden Grund, warum unter einer bestimmten Last ein schwerwiegender Netzwerkengpass auftritt. Ich denke, dass die nächsten Schritte die Netzwerkschicht separat untersuchen werden.