Immer mal wieder höre oder lese ich, dass man mit PHP keine performaten Webprojekte umsetzen könne. Satt aber nun einen weiteren PHP vs. Sprache-X Artikel zu verfassen habe ich mir überlegt stattdessen ein paar Tipps zu geben wie man meiner Meinung nach die Performance von PHP-Projekten optimieren kann. Da dies ein sehr umfangreiches Thema ist werde ich das Ganze in mehrere Artikel aufteilen. Anfangen werde ich in diesem ersten Beitrag mit ein paar Tipps zum Webserver.
Lighttpd mit PHP-FPM
Die meisten Root- oder V-Server werden in der Standard-Konfiguration ganz ohne Webserver oder mit Apache2 ausgeliefert. Mein Tipp hier: Alternativen testen! Lighttpd oder Nginx sind in vielen Fällen schneller und benötigen weniger Ressourcen. Jeder Webserver hat seine Vor- und Nachteile, es kann also nicht schaden die Alternativen einmal zu testen. Ich persönlich verwende schon seit längerem Lighttpd und bin sehr zufrieden damit. Die Konfiguration der verschieden Webserver sollte Dank zahlreicher Tutorials die im Netz verfügbar sind kein Problem darstellen. Desweiteren empfehle ich dringen statt des "üblichen" PHP-Moduls (mod_php) PHP-FPM zu verwenden. Zusammen mit Lighttpd oder Nginx schafft ein Server so nicht selten wesentlich mehr Requests/Sec abzuarbeiten. Darüber hinaus bietet PHP-FPM einige sehr nützliche Features wie z.b. das Anlegen verschiedener Pools. Damit ist es möglich verschiedenen PHP-Prozesse mit verschiedenen Benutzern zu starten. Das bringt Sicherheits-Vorteile mit sich und lässt Schreibrechte-Probleme der Vergangenheit angehören. Zum Thema Lighttpd und PHP-FPM habe ich hier auch schon andere Beiträge verfasst.
Opcode Caching mit XCache
Da PHP keinen eigenen Opcode-Cache mit sich bringt fehlt dieser häufig auf Webserver. Ein Opcode oder Bytecode-Cache sorgt dafür, dass PHP-Scripte nicht bei jedem Aufruf neu in Bytecode übersetzt werden müssen. Besonders bei vielen gleichzeitigen Anfragen an den Webserver kann ein solcher Cache die CPU-Last erheblich verringern. Neben dem Zend-Optimizer, eAccelerator und APC gibt es hier noch meinen persönlichen Favoriten XCache. Installation und Konfiguration sollten keine Probleme bereiten, da es für quasi jede Linux-Distribution bereits fertige Pakete gibt. Hinweisen möchte ich jedoch noch auf das XCache-Admin Feature denn hier kann man gut sehen ob und wie gut der Opcode-Cache tatsächlich arbeitet. Die obere "Total" Zeile zeigt an wie viele der Requests aus dem Cache (hits) ausgeliefert werden konnten und wie viele nicht (misses). Ausserdem kann man sehen wie viel der zur Verfügung stehen Speichers aktuell benutzt wird. Sollte der Wert der Misses im Verhältnis zu den Hits sehr hoch sein, ist es ggf. sinnvoll XCache etwas mehr Speicher zu Verfügung zu stellen.
Requests begrenzen - mod_evasive und mod_status
Über Sinn oder Unsinn von Modulen wie mod_evasive kann man sich selbstverständlich streiten und mir ist klar, dass keines dieser Module einem richtigen DDoS Angriff entgegenwirken kann, das liegt in der Natur der Sachen. Dennoch halte ich den Einsatz für sinnvoll, denn vielen "Script-Kiddy"-, Spam-, Brutforce- und sonstigen Attacken kann man damit einen Riegel vorschieben. Mod_evasive mach im Prinzip nichts weiter als die Requets pro IP auf den Webserver zu limitieren. Eine gute Übersicht über die Requests die Lighttp aktuell verabeitet liefert das Modul mod_status.
Lasttest Nachdem man nun alle (oder einen Teil) dieser Optimierungen vorgenommen hat. Sollte man seinen Webserver mit einem simplen Lasttest durchführen um zu sehen ob der Webserver wirklich durchhält wenn er ein paar parallele Requests abzuarbeiten hat. Tools für diese Aufgabe sind zum Beispiel Apache Benchmark oder LoadUI. Am besten startet man mit einigen wenigen Anfragen pro Sekunde und schaut auf der Konsole des Server wie sich da auf die Last auswirkt. Da man bei solchen Lasttests in der Regel nur von einer IP aus testet kann man hier auch direkt prüfen ob mod_evasive korrekt funktioniert. Ist das der Falls sollte man die Anfragen pro Sekunde im Lasttest-Tools quasi beliebig nach oben schrauben können ohne das die Serverlast merklich steigt. Wie viele Requests/Sec ein Server verträgt hängt natürlich start von der Hardware und dem aufgerufenen Script ab. Neben den Requests pro Sekunde sollte man auch noch darauf achten ob alle Anfragen nach einer bestimmten Zeit wieder geschlossen werden. Hierzu kann an einen Blick auf die mod_status Weboberfläche werden. Normalerweise sollten allen Verbindungen nach einer kurzen Zeit wieder geschlossen werden. Wenn Verbindungen für eine sehr lange Zeit offen bleiben oder gar nicht geschlossen werden, sollten die entsprechenden Parameter in der Konfiguration noch einmal überprüft werden.
Ich hoffe ich konnte in diesem kurzen Anriss zum Thema Webserver-Konfiguration auf die häufigsten Performance-Bremsen eingehen und ein paar nützliche Tipps geben. Anregungen natürlich wie immer hin den Kommentaren.
Im zweiten Teil der "Performance-Reihe" wird es dann um Datenbank-Abfragen gehen, bzw. darum wie man hier optimieren kann.