Die Apache-Leistung verschlechtert sich dramatisch über 256 gleichzeitige Anforderungen

14

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.

cmckendry
quelle
Zu berücksichtigende Optionen: CloudFlare, drupal.org/project/boost , CDN, Lackcache .
Ceejayoz
Sie sagen uns nichts darüber, was dieser Server (in der Realität) tut, außer HTTP-Anfragen zu bearbeiten. Handelt es sich um eine Datenbank (oder eine andere allgemeine Ressource, die unter Sperrenkonflikten leiden könnte)? Wenn das Problem plötzlich bei GENAU 256 Anforderungen auftritt (OK bei 255), wird wahrscheinlich eine externe Ressource überlastet. (Ihr Sprung, der eine statische Seite bedient, ist definitiv auch abnormal - siehe Ladadadadas Antwort für einige Debugging-Tipps dort)
voretaq7
ceejayoz: Ich schätze die Vorschläge, aber grundsätzlich glaube ich, dass Apache nicht so langsam sein sollte. Es gibt eine Menge Dinge, die wir tun können, um die Auswirkungen des Problems abzuschwächen, aber ich würde es viel lieber beheben oder zumindest verstehen.
Cmckendry
voretaq7: Ich habe anfangs in die gleiche Richtung gedacht, da eine typische Anfrage auch PHP / MySQL beinhalten würde, aber das Problem bleibt auf der gleichen Schwelle, auch wenn vollständig statische Inhalte bereitgestellt werden.
Cmckendry
1
Ist das ein echter Server oder eine VM? Führen Sie Ihren Test von einem lokalen Host, einem lokalen Netzwerk oder dem Internet aus durch? Minimale Reaktionszeiten im Bereich von 100 ms lassen auf Tests aus dem Internet schließen. Versuchen Sie, von localhost aus zu testen - möglicherweise drosselt Ihr Provider Sie nur.
Tometzky

Antworten:

4

Was ich in dieser Situation tun würde, wird ausgeführt

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

auf einen Ihrer Apache-Prozesse während des ab-Tests, bis Sie eine der langsamen Antworten erfassen. Dann schau doch mal rein trace.txt.

Die -ttund -TOptionen geben Sie Zeitstempel von Beginn und Dauer der einzelnen Systemaufruf , um die langsamen zu identifizieren.

Möglicherweise finden Sie einen einzelnen langsamen Systemaufruf wie open()oder, stat()oder Sie finden einen Schnellaufruf mit (möglicherweise mehreren) poll()Aufrufen direkt danach. Wenn Sie eine finden, die mit einer Datei oder Netzwerkverbindung arbeitet (sehr wahrscheinlich), blättern Sie in der Ablaufverfolgung rückwärts, bis Sie diese Datei oder Verbindungskennung finden. Die früheren Aufrufe desselben Handles sollten Ihnen eine Vorstellung davon geben, worauf sie poll()gewartet haben.


Gute Idee, die -cOption in Betracht zu ziehen . Haben Sie sichergestellt, dass das von Ihnen verfolgte Apache-Kind mindestens eine der langsamen Anforderungen in dieser Zeit bedient hat? (Ich bin mir nicht mal sicher, wie Sie das machen würden, wenn Sie nicht stracebei allen Kindern gleichzeitig laufen würden .)

Leider stracegibt uns nicht das vollständige Bild, was ein laufendes Programm tut. Es werden nur Systemaufrufe verfolgt. In einem Programm kann viel passieren, ohne dass der Kernel nach irgendetwas gefragt werden muss. Um herauszufinden, ob dies geschieht, können Sie die Zeitstempel des Starts jedes Systemaufrufs anzeigen. Wenn Sie erhebliche Lücken sehen, ist dies der Zeitpunkt, an dem die Zeit vergeht. Dies ist nicht einfach zu verstehen und es gibt ohnehin immer kleine Lücken zwischen den Systemaufrufen.

Da Sie sagten, dass die CPU-Auslastung niedrig bleibt, ist es wahrscheinlich nicht übermäßig, was zwischen den Systemaufrufen passiert, aber es lohnt sich, dies zu überprüfen.


Betrachten Sie die Ausgabe von ab:

Der plötzliche Sprung der Antwortzeiten (es sieht so aus, als gäbe es keine Antwortzeiten zwischen 150 ms und 3000 ms) deutet darauf hin, dass irgendwo oberhalb von 256 gleichzeitigen Verbindungen eine bestimmte Zeitüberschreitung auftritt. Eine gleichmäßigere Verschlechterung ist zu erwarten, wenn der Arbeitsspeicher oder die CPU-Zyklen für normale E / A-Vorgänge knapp werden.

Zweitens zeigt die langsame abReaktion, dass die 3000 ms in der connectPhase verbracht wurden . Fast alle brauchten ungefähr 30 ms, aber 5% 3000 ms. Dies deutet darauf hin, dass das Netzwerk das Problem ist.

Woher rennst du ab? Können Sie es über dasselbe Netzwerk wie den Apache-Rechner ausprobieren?

Versuchen Sie für weitere Daten, tcpdumpan beiden Enden der Verbindung zu arbeiten (vorzugsweise ntpan beiden Enden, damit Sie die beiden Erfassungen synchronisieren können.) Und suchen Sie nach erneuten TCP-Übertragungen. Wireshark ist besonders gut für die Analyse von Speicherauszügen geeignet, da es TCP-Neuübertragungen in einer anderen Farbe hervorhebt, sodass sie leicht zu finden sind.

Es kann sich auch lohnen, die Protokolle aller Netzwerkgeräte zu lesen, auf die Sie Zugriff haben. Ich bin kürzlich auf ein Problem mit einer unserer Firewalls gestoßen, bei der die Bandbreite in KBit / s verarbeitet werden konnte, die Anzahl der empfangenen Pakete pro Sekunde jedoch nicht. Es lag bei 140.000 Paketen pro Sekunde. Einige schnelle Berechnungen auf Ihrem abLauf lassen mich glauben, dass Sie ungefähr 13.000 Pakete pro Sekunde gesehen hätten (ohne die 5% der langsamen Anfragen). Vielleicht ist dies der Engpass, den Sie erreicht haben. Die Tatsache, dass dies um 256 geschieht, ist möglicherweise ein reiner Zufall.

Ladadadada
quelle