Leistungsoptimierung eines Apache-Servers mit hoher Auslastung

12

Ich möchte einige Serverleistungsprobleme verstehen, die bei einem (für uns) stark ausgelasteten Webserver auftreten. Die Umgebung ist wie folgt:

  • Debian Lenny (alle stabilen Pakete + auf Sicherheitsupdates gepatcht)
  • Apache 2.2.9
  • PHP 5.2.6
  • Große Amazon EC2-Instanz

Das Verhalten, das wir beobachten, ist, dass sich das Web in der Regel reaktionsschnell anfühlt, jedoch mit einer leichten Verzögerung, um eine Anfrage zu bearbeiten - manchmal in Bruchteilen von Sekunden, manchmal 2-3 Sekunden in unseren Hauptnutzungszeiten. Die tatsächliche Auslastung des Servers wird als sehr hoch gemeldet - häufig als 10.xx oder 20.xx, wie von gemeldet top. Außerdem ist das Ausführen anderer Dinge auf dem Server während dieser (geraden vi) Zeiten sehr langsam, sodass die Last auf jeden Fall dort oben ist. Seltsamerweise bleibt Apache sehr reaktionsschnell, abgesehen von dieser anfänglichen Verzögerung.

Wir haben Apache unter Verwendung von Prefork wie folgt konfiguriert:

StartServers          5
MinSpareServers       5
MaxSpareServers      10
MaxClients          150
MaxRequestsPerChild   0

Und KeepAlive als:

KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout 5

Wenn wir uns die Serverstatus-Seite ansehen, treffen wir selbst in Zeiten hoher Auslastung selten die Client-Obergrenze. In der Regel werden zwischen 80 und 100 Anfragen und viele Anfragen im Keepalive-Status bearbeitet. Das sagt mir, dass ich die anfängliche Langsamkeit der Anfrage als "Warten auf einen Handler" ausschließen soll, aber ich kann mich irren.

Die CloudWatch-Überwachung von Amazon zeigt mir, dass die CPU-Auslastung unserer Instanz auch bei einem Betriebssystem mit einer Auslastung von> 15 zwischen 75 und 80% liegt.

Beispielausgabe von 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

Die Mehrzahl der Prozesse sieht folgendermaßen aus:

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            

Beispielausgabe vmstatzur gleichen Zeit wie oben:

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

Und schließlich die Ausgabe von 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..........................................
................................................................

Aus meiner begrenzten Erfahrung ziehe ich folgende Schlussfolgerungen / Fragen:

  • Möglicherweise lassen wir viel zu viele KeepAliveAnfragen zu

  • Ich sehe einige Zeit damit zugebracht, auf E / A in der vmstat zu warten, obwohl dies nicht konsequent und nicht sehr häufig ist (glaube ich?), Daher bin ich mir nicht sicher, ob dies ein großes Problem ist oder nicht. Ich habe weniger Erfahrung mit vmstat

  • Außerdem sehe ich in vmstat in einigen Iterationen eine Reihe von Prozessen, die darauf warten, bedient zu werden, was ich der anfänglichen Verzögerung beim Laden der Seite auf unserem Webserver zuschreibe, möglicherweise fälschlicherweise

  • Wir stellen eine Mischung aus statischem Inhalt (75% oder höher) und Skriptinhalt bereit. Der Skriptinhalt ist häufig recht rechenintensiv. Daher ist es wichtig, die richtige Balance zwischen beiden zu finden. Langfristig wollen wir die Statik an einen anderen Ort verschieben, um beide Server zu optimieren, aber unsere Software ist heute noch nicht dazu bereit

Wenn jemand eine Idee hat, gebe ich gerne zusätzliche Informationen. Der andere Hinweis ist, dass es sich um eine Produktionsinstallation mit hoher Verfügbarkeit handelt. Daher bin ich vorsichtig, wenn ich nach und nach Änderungen vornehme, und deswegen habe ich selbst nicht mit Dingen wie dem KeepAliveWert gespielt noch.

futureal
quelle
+1 Verdammt gute Frage, gut formuliert und durchdacht. Hoffe du hast die Antwort, die es verdient!
Dave Rix

Antworten:

7

Ich gebe zunächst zu, dass ich nicht viel damit zu tun habe, Dinge in Clouds laufen zu lassen. Aufgrund meiner Erfahrungen an anderen Orten würde ich jedoch sagen, dass diese Webserverkonfiguration ein relativ geringes Verkehrsaufkommen widerspiegelt. Die Runqueue ist so groß, dass einfach nicht genug CPU zur Verfügung steht, um damit umzugehen. Was ist sonst noch in der Warteschlange?

Möglicherweise lassen wir zu viele KeepAlive-Anfragen zu

No - keeplive verbessert immer noch die Leistung. Moderne Browser wissen sehr genau, wann eine Pipeline erstellt werden muss und wann Anforderungen parallel ausgeführt werden müssen, obwohl ein Timeout von 5 Sekunden immer noch recht hoch ist und Sie eine Menge Server warten müssen - es sei denn, Sie Ich würde empfehlen, diese Einstellung auf 2-3 zu reduzieren. Dies sollte die Runqueue etwas verkürzen.

Wenn Sie mod_deflate noch nicht auf dem Webserver installiert haben - dann empfehle ich Ihnen dies - und fügen Sie den ob_gzhandler () zu Ihren PHP-Skripten hinzu. Sie können dies als automatisches Präpendieren ausführen:

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

(Ja, Copression verbraucht mehr CPU - aber Sie sollten insgesamt CPU sparen, indem Sie Server schneller aus der Warteschlange holen / weniger TCP-Pakete verarbeiten - und als Bonus ist Ihre Site auch schneller).

Ich würde empfehlen, eine Obergrenze für MaxRequestsPerChild festzulegen - sagen wir etwa 500. Dies ermöglicht nur einen gewissen Umsatz bei Prozessen, falls irgendwo ein Speicherverlust auftritt. Ihre httpd-Prozesse sehen RIESIG aus - stellen Sie sicher, dass Sie alle Apache-Module entfernt haben, die Sie nicht benötigen, und stellen Sie sicher, dass Sie statischen Inhalt mit guten Caching-Informationen bereitstellen.

Wenn immer noch Probleme auftreten, liegt das Problem wahrscheinlich im PHP-Code (wenn Sie auf fastCGI umsteigen, sollte dies ohne größere Leistungseinbußen offensichtlich sein).

aktualisieren

Wenn der statische Inhalt nicht sehr stark von Seite zu Seite variiert, lohnt es sich möglicherweise auch, mit den folgenden Elementen zu experimentieren:

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

auch auf die PHP-Skripte.

symcbean
quelle
Unter einer Vielzahl von guten Antworten bezeichne ich dies als die akzeptierte, da Sie eindeutig angegeben haben, dass es sich um ein CPU-gebundenes Problem handelt (hauptsächlich aufgrund der schlechten Anwendung, die wir ausführen) und dies sicherlich der Fall war. Ich habe alles auf 2xlarge EC2-Instanzen (von Large) neu implementiert, und die meisten Probleme sind behoben, obwohl viele der anderen Leistungsmerkmale noch vorhanden sind. Wir haben nur die einzige App auf diesen Servern und sie ist einfach hässlich.
futureal
4

Sie sollten die Installation eines asynchronen Reverse-Proxys in Betracht ziehen, da eine Reihe von Prozessen im W-Status ebenfalls recht hoch ist. Ihre Apache-Prozesse scheinen viel Zeit mit dem Senden von Inhalten an langsame Clients über das Netzwerk zu verbringen, da diese blockiert werden. Nginx oder lighttpd als Frontend für Ihren Apache-Server können eine Reihe von Prozessen im W-Status drastisch reduzieren. Und ja, Sie sollten eine Reihe von Keepalive-Anforderungen einschränken. Wahrscheinlich lohnt es sich, Keepalive auszuschalten.

Übrigens: 107 Apache-Prozesse sind für 22 U / min zu hoch. Ich konnte 100-120 U / min mit nur 5 Apache-Prozessen bedienen. Wahrscheinlich besteht der nächste Schritt darin, Ihre Anwendung zu profilieren.

Alex
quelle
Ja, auf jeden Fall einverstanden, dass die Anwendung ein großer Teil des Problems ist. Es wurde ausgelagert und ist seitdem einer Reihe von Patches und so weiter ausgesetzt, die es nur noch schlimmer gemacht haben, und es wird derzeit an einer Neugestaltung gearbeitet. Ich habe heute Abend versucht, KeepAlive ohne wirklichen Effekt auszuschalten, und mein nächster Schritt ist, diesen Reverse-Proxy zu testen, wahrscheinlich mit Nginx, basierend auf allem, was ich seitdem gelesen habe.
Futureal
Als Nächstes habe ich begonnen, mit dem Reverse-Proxy zu experimentieren, und ich werde ihn wahrscheinlich in naher Zukunft in der Produktion bereitstellen. Vielen Dank (und den anderen, die es vorgeschlagen haben) für die Idee, es ist nicht etwas, an dem ich jemals zuvor herumgebastelt habe, aber ich denke, es wird Auswirkungen haben, bis wir ein vollwertiges Redesign machen können.
futureal
1

Sie haben zwei Zeilen in Ihrem vmstat, die anzeigen, dass Ihre CPU-Wartezeit ziemlich hoch ist, und um diese herum führen Sie eine angemessene Anzahl von Schreibvorgängen (io-bo) und Kontextwechseln durch. Ich würde mir ansehen, was Schreibblöcke sind und wie man diese Wartezeit eliminiert. Ich denke, die größte Verbesserung könnte in der Verbesserung Ihrer Festplatten-E / A liegen. Überprüfen Sie das Syslog - stellen Sie es so ein, dass es asynchron schreibt. Vergewissern Sie sich, dass der Schreibcache Ihres Controllers funktioniert (überprüfen Sie ihn - Sie haben möglicherweise eine schlechte Batterie).

Keepalive verursacht kein Perf-Problem. Es spart Zeit beim Verbindungsaufbau, wenn Sie keinen Cache vor sich haben. Sie könnten die MaxSpareServers ein wenig anstoßen, damit Sie in einer Krise nicht auf alle Gabeln warten.

Bohnen
quelle
Ich bin mit Syslog nicht vertraut genug, um zu wissen, wie man es für asynchrone Schreibvorgänge unter Apache einstellt, obwohl ich das mit Sicherheit suchen und herausfinden werde. Ich habe heute Abend einige Änderungen in Bezug auf KeepAlive und MaxSpareServers ohne wirklichen Effekt vorgenommen. Ich bin damit einverstanden, dass mehr Ersatzteile übrig bleiben, das hatte ich verpasst. Eine (schlechte) Qualität unserer Anwendung besteht darin, dass sie stark in Benutzersitzungsdateien (ja, Dateien) geschrieben wird, unter denen ich allmählich zu leiden beginne. Ich habe die Möglichkeit, die Sitzungsverwaltung in die Datenbank zu verschieben, die ich wahrscheinlich als Nächstes versuchen werde.
Futureal
Ja, ich stimme zu, dass Ihre Session-Schreibvorgänge die Ursache des Problems sind. Sie können die Session-Schreibvorgänge verlieren, wenn Sie PHP-Sitzungen verwenden - installieren Sie memcache und setzen Sie den session.save_handler von PHP auf memcache und den session.save_path auf tcp : //127.0.0.1: 11211 (oder wo immer Sie den Memcache einrichten). Die Apache-Protokollierung ist standardmäßig asynchron, aber manchmal können Webanwendungen Syslog verwenden, oder Syslog kann gesprächig sein, und es wird für jede Zeile eine Synchronisierung durchgeführt. Es hört sich schließlich nicht so an, als wäre es das Problem in Ihrem Fall. Sie können Dateieingabezeilen in der Datei syslog.conf das Präfix '-' voranstellen, um die Synchronisierung zu unterlassen.
Bohnen
0

Sie sollten in Betracht ziehen, Keepalive als ersten Versuch auszuschalten ...

Mit 107 bearbeiteten Anfragen würde ich MaxSpareServers höher halten als du eingestellt hast ...

IMHO im langfristigen Nginx als Reverse Proxy für statische Inhalte sollte berücksichtigt werden

evcz
quelle
0

Erster Vorschlag: Keepalives deaktivieren. Ich habe es immer nur benötigt, wenn ich eine bestimmte Situation feststellen konnte, in der die Leistung zunahm, bei aktivierter Keepalive-Funktion jedoch im Allgemeinen die Anforderungen pro Sekunde abnahmen.

Zweiter Vorschlag: Legen Sie ein MaxRequestsPerChild fest. Wenn ich hier symcbean wiedergebe, hilft es beim Prozess-Rollover im Falle eines Speicherverlusts. 500 ist ein guter Ausgangspunkt.

Dritter Vorschlag: MaxClients erhöhen. Eine Standardberechnung hierfür ist (physischer Speicher - Speicher, der von Nicht-httpd-Prozessen verwendet wird) / Größe jedes httpd-Prozesses. Abhängig davon, wie httpd kompiliert wurde, liegt die maximale Anzahl bei 255. Ich verwende 250 für meine öffentlichen Server, um mit dem Crawlen der Systeme durch Google / Yahoo / MS umzugehen.

Vierter Vorschlag: Erhöhen Sie die Anzahl der MaxSpareServer: ungefähr das 4-5-fache der MinSpareServer.

Wenn diese Vorschläge fehlschlagen, würde ich mir den Lastausgleich mit Reverse-Proxy oder Memcache für DB ansehen.

Paul S
quelle