Angeregt durch die Schlammschlacht auf Plasmas Blog, habe ich die letzte Stunde damit verbracht WordPress bzw. unsere PHP-Installation allgemein ein bisschen zu beschleunigen.
Ergebnis: Statt über einer ganzen Sekunde braucht eine Seite im Durchschnitt nur noch 200 Millisekunden bis sie angezeigt wird (auf einem AMD Duron 1300 MHz mit 512 MB RAM, Apache 2.x, PHP 4.3.x, MySQL 4.x unter Linux mit einem 2.4-er Kernel). Und das – wohl gemerkt – ohne die Benutzung eines Caches, der die Ausgaben von WordPress zwischenspeichert (wie es z.B. das mitgelieferte Staticize Plugin macht)
MySQL
WordPress baut alle Seiten dynamisch aus einer Datenbank auf. Von daher liegt es nahe hier zuerst anzusetzen. MySQL hat ab Version 4.0.1 einen Querycache eingebaut, der nicht aktiviert war. Um ihn zu aktivieren einfach folgendes in die Datei /etc/my.cnf in die Sektion „mysqld“ eintragen:
[mysqld]
…
query_cache_limit = 2M
query_cache_type = 1
query_cache_size = 32M
…
Das und ein Neustart der Datenbank bewirken, dass Anfragen die ein Ergebnis haben, das kleiner als 2 MB groß ist, in einem Cache von 32 MB gespeichert werden.
Das wirkte schon mal Wunder. Um die Zeit weiter zu drücken, sollte man in den WordPress Optionen einstellen, dass eine bestimmte Anzahl von Artikeln angezeigt werden soll und nicht ein Zeitraum. Das senkte die Zeit die die Abfragen benötigten von ca. 300 ms auf nun ca. 30 ms. Da der Löwenanteil der Zeit aber offensichtlich wo anders verbraten wird wurde, muss noch mehr optimiert werden.
PHP
Wenn nur ein Drittel der Zeit für die Datenbank abfragen draufgehen, dann scheint wohl PHP den Rest zu verschlingen. Also habe ich erstmal den Zend Optimizer installiert. Dieser soll den Code optimieren und so für eine schnellere Ausführzeit sorgen. Tat er auch, aber das war mir nicht genug.
WordPress besteht aus einigen 100 KB PHP-Code. Nicht alles wird bei jedem Seitenaufruf geladen, aber es ist doch eine beträchtliche Menge, die da jedes mal interpretiert/kompiliert wird. Auf meiner Suche nach weiteren Verbesserungen bin ich dann beim Turck MMCache hängengeblieben. Damit läuft die Ausführung von PHP-skripten ähnlich ab wie etwa bei JSP. Der Code wird beim ersten Ausführen (nach einer Änderung an der Datei) einmal kompiliert und danach nur noch das Kompilat, welches im RAM liegt, ausgeführt. Das hat die Zeit dann fast halbiert. Prima!
Doch WordPress nahm sich immer noch fast 400 ms an Zeit :-(
WordPress
Oben habe ich ja bereits auf eine Einstellungsmöglichkeit hingewiesen um die Datenbank etwas weniger zu belasten. Hier nun ein weiterer Tipp.
WordPress ist ziemlich langsam, wenn man eine andere Sprache als den Standard (Englisch) einstellt. Zum Test habe ich die entsprechende Zeile aus der Datei wp-config.php entfernt und siehe da, es lief doch deutlich schneller.
Im WordPress Supportforum habe ich dann auch schnell eine Lösung dafür gefunden. Scheinbar wird in der Version 1.5 eine ältere Version von PHP gettext verwendet. Folgt man der Anleitung aus dem Forum (neue Version drüber installieren und eine Änderung an wp-includes\wp-l10n.php) wird WordPress auch in Deutscher Sprache schneller. Besagte 200 ms waren erreicht :-)
Fazit
Durch einige wenige Ein- und Umstellungen kann man eine PHP-Anwendung – und diesem Fall alle auf diesem Server laufende – deutlich beschleunigen, ohne dass man darauf achten muss, was die Anwendungen speziell so machen.
P.S.: Am Ende hat mich doch interessiert wieviel das oben genannte Staticize Plugin noch herausholen kann. Nach Aktivierung wurden die Seiten in ungefähr 30-150 ms ausgeliefert (siehe HTML-Kommentar am Ende des Quelltextes). Damit kann man ruhig auch mal auf Slashdot.org verlinkt werden ohne dass der Server in die Knie geht :twisted:
Update:
Mit Staticize Reloaded konnte man leider keine Kommentare mehr zu einem Artikel hinzufügen, da der verwendete Spamfilter (WP-Hashcash) nicht damit kompatibel ist. Auf der Homepage des Plugins steht zwar eine Anleitung wie man es trotzdem anstellen kann, dass beides miteinander funktioniert, aber die funktioniert nicht. Vorerst ist also der zusätzliche Spamschutz ausgeschaltet. Mal sehen wie sich WordPress ohne macht :-)
Kommentare
5 Antworten zu „Schnelleres PHP (und auch WordPress)“
Interessante Sache. Aber grade diese PHP-Caches funktionieren leider nicht in einer suPHP-Umgebung mit PHP-CGI. Dafür soll FastCGI Abhilfe schaffen, ausprobiert habe ich es noch nicht.
Ich hab mal deinen MySQL-Tipp ausprobiert grade: „query_cache_size = 32M“ – genau diese Zeile funktioniert irgendwie nicht bei mir. Wenn ich den MySQLd neustarte, ist diese Variable auf 0 gesetzt. Ich kann sie zwar zur Laufzeit ändern, was sich der Server wohl auch merkt, aber automatisch geht das nicht. Was mache ich falsch? ;)
Ja stimmt, geht (natürlich?) nicht wenn PHP als CGI läuft.
Bei den genannten Zeilen sind alle wichtig. Der query_cache_type muss auf 1 stehen damit der Cache aktiviert ist. Auf 0 ist es deaktiviert und auf 2 „on demand“, d.h. man muss bei der SELECT-Anweisung angeben, dass gecached werden soll.
Wenn der Cache funktioniert werden die Statusvariablen, die mit „qcache“ anfangen, zum Leben erweckt. Passiert da was bei dir, wenn du die Variable zur Laufzeit änderst?
Sehr geiler Artikel! Hab sogar ich verstanden :)
Jetzt noch in englisch übersetzen und ins WordPress-Forum posten, dann hast du den Schockwellenreiter locker überholt. Sebbi: Respekt!!!
Danke. Ich weiß ja wie geil ihr auf solche Howtos seid (siehe Intranet-Wiki) … ist aber ziemlich aufwendig und nachdem man schon mühselig rumgebastelt hat, will man (=ich) nicht auch noch alles aufschreiben müssen (siehe Intranet-Wiki) … hat keine Zukunft mit solchen Artikeln zu glänzen :-)
So, auch wieder da… blöd wenn’s keine Benachrichtigung gibt.
MySQL tut jetzt, was es soll. Lag daran, dass die my.cnf im falschen Verzeichnis lag und da niemanden interessiert hat. Und im richtigen Verzeichnis ging sie nicht, weil die total verwurmt war. Jetzt hab ich ne neue geschrieben und es tut.
Als nächstes ist dann FastCGI dran. Warum es mit CGI nicht geht, weiß ich nicht. Erzählt immer nur jeder, inkl den Entwicklern.