Das freie Shopsystem Magento bietet viele Features und lässt sich mit eigenem PHP-Code erweitern. Wer zudem Wert auf bestmögliche Performance legt, betreibt die Open-Source-Software mit dem kleinen Webserver Nginx und dem schnellen Prozessmanager PHP-FPM.
Der Open-Source-Webshop Magento [1] ist aus gutem Grund beliebt: Die freie E-Commerce-Software besitzt einen großen Fundus an Plugins und lässt sich elegant durch selbst geschriebene PHP-Klassen anpassen und erweitern. Wer sie aber mit dem weitverbreiteten Apache-Webserver betreibt, holt aus seinem Shopsystem nicht die optimale Performance heraus. Dieser Webserver deckt mit seinen zahlreichen Modulen zwar verschiedenste Anforderungen an eine Webhosting-Umgebung ab, entstand aber zu Beginn der 90er Jahre mit wenig Augenmerk auf seine Performance.
Der Bedarf an performanten und skalierbaren Hostinglösungen ist mit zunehmender Popularität des WWW immer weiter gestiegen, was zur Entwicklung schlanker Webserver wie Lighttpd und Nginx [2] führte. Diese bieten ganz bewusst nicht den großen Funktionsumfang von Apache. Dafür sind die unterstützten Features aber im Hinblick auf Performance und optimale Ausnutzung vorhandener Ressourcen implementiert. Nginx-Freunde etwa sagen gerne, ihr Lieblingsserver mache nur einen Bruchteil dessen, was Apache kann – dafür aber um ein Vielfaches schneller.
Klein und flink
Seine Stärken kann Nginx besonders beim Verarbeiten vieler parallel eingehender HTTP-Requests ausspielen. Das zeigt unter anderem ein Benchmark, den der Hoster Webfaction ausgeführt hat [3]. Er kontrastiert die Performance von Nginx mit einer Apache-Installation mit dem Multi-Processing-Modul (MPM) Worker, das am ehesten vergleichbar ist.
Während Nginx es auch noch bei knapp 4000 gleichzeitigen Verbindungen schafft, eine kleine statische Datei etwa 10000-mal pro Sekunde auszuliefern, sinkt die Apache-Performance bereits bei ungefähr 500 gleichzeitigen Verbindungen deutlich. Der betagte Webserver schafft hier nur noch 6000 Anfragen, mit zunehmender Anzahl der parallelen HTTP-Requests sinkt der Wert auf etwa 2500 Antworten in der Sekunde. Zweifelsohne noch immer ein beeindruckender Wert, aber doch nur ein Viertel der von Nginx gezeigten Leistung.
Daneben macht der konstante Speicherbedarf Nginx als Server auch für kleine Shops mit begrenzten Ressourcen interessant. Er arbeitet – wie Node.js auch – Event-basiert und startet für neue Requests keine neuen Prozesse oder Threads. Im zitierten Benchmark bleibt sein Speicherbedarf bei etwa 2,5 MByte, während Apache nahezu linear mit der Anzahl gleichzeitiger Verbindungen immer speicherhungriger wird und schließlich mit 40 MByte ungefähr das 16-fache belegt. Ein Test gegen Ende dieses Artikels wird zeigen, dass sich Nginx auch als Server für Magento bestens schlägt.
PHP-FPM
Die zweite wichtige Komponente für Ressourcen-schonendes Magento-Hosting heißt PHP-FPM [4]. Diese Abkürzung bezeichnet einen “Fast CGI Process Manager” für PHP. Es handelt sich um eine PHP-spezifische Umsetzung des Fast-CGI-Prinzips [5]. Um die Latenz bis zur Beantwortung einer eingehenden HTTP-Anfrage zu verkürzen, hält der Prozessmanager persistente PHP-Interpreter-Prozesse bereit.
Geht eine Anfrage bei Nginx ein, die ein PHP-Skript bearbeiten muss, reicht PHP-FPM sie an einen dieser bereits laufenden Interpreter weiter. Da die Laufzeitumgebung bereits initialisiert ist, muss die Anfrage nur noch die PHP-Anwendung durchlaufen. Nginx erhält das Ergebnis und sendet es an den Browser (siehe Abbildung 1).
Da nicht immer wieder ein neuer PHP-Interpreter startet, verringert dieses Verfahren die Latenz gegenüber dem herkömmlichen CGI-Ansatz deutlich. Ein zusätzlicher Pluspunkt von PHP-FPM: Die Trennung von Webserver und PHP-Interpreter macht die Hostingumgebung leichter skalierbar: Bei Bedarf lassen sich PHP-FPM und Nginx einfach auf separaten Systemen betreiben.
Grundinstallation
Die Installation von PHP-FPM hat sich bedeutend vereinfacht, seit der Prozessmanager in die PHP-Version 5.3.3 eingegangen ist. Das Einspielen als separates Patch gehört damit der Vergangenheit an. Da die meisten Distributionen bereits entsprechende Binärpakete bereithalten, entfällt auch das Kompilieren von PHP. Unter Debian oder Ubuntu installiert das folgende Kommando die benötigten Komponenten:
sudo apt-get install php5-fpm nginxmysql-server php5-mysql php5-gd php5-curl
Debian und Ubuntu richten dabei bereits passende Initskripte ein und starten die Dienste. Wer sie von Hand neu hochfahren muss, verwendet folgende Befehle:
sudo /etc/init.d/nginx restart sudo /etc/init.d/php5-fpm restart sudo /etc/init.d/mysql restart
Empfehlenswert sind zudem das PHP-Hardening-Patch Suhosin [6] und der Cache APC [7].
Ob Nginx korrekt gestartet ist, lässt sich mit einem Aufruf der Serveradresse im Webbrowser testen. Erscheint dort die Seite “Welcome to Nginx”, war die Installation erfolgreich.
Die Basiskonfiguration unter Debian und Ubuntu ist für den produktiven Magento-Betrieb nicht optimal. Daher empfiehlt es sich, die Konfiguration in der Datei »/etc/nginx/nginx.conf« an die eigenen Rahmenbedingungen anzupassen.
Nginx-Optimierung
Listing 1 zeigt einen Auszug aus der Konfigurationsdatei. Von besonderem Interesse ist die Option »worker_processes« . Ein guter Richtwert für diese Prozesse liegt zwischen 1 und der Anzahl der CPU-Kerne des jeweiligen Systems. Wenn auf dem System noch weitere Anwendungen neben Nginx laufen, etwa PHP-FPM und MySQL, sollte es weniger Worker-Prozesse geben, als CPU-Kerne im System vorhanden sind.
Listing 1
Auszug aus nginx.conf
01 user www-data;
02 worker_processes 2;
03 pid /var/run/nginx.pid;
04
05 events {
06 worker_connections 48;
07 }
Die Direktive »worker_connections« legt fest, wie viele parallele Verbindungen ein Worker-Prozess annehmen darf. Im Beispiel oben sind dies 48, was bei zwei Worker-Prozessen insgesamt 96 gleichzeitige Verbindungen ermöglicht. Das sind relativ wenige im Vergleich zu der Standardkonfigurati-on, die 1024 Verbindungen pro Worker-Prozess erlaubt.
Das liegt daran, dass Nginx in der Regel nur statische Dateien ausliefert oder als Reverse Proxy und Loadbalancer eingesetzt wird. Der Engpass ist hier nämlich nicht Nginx, sondern der Speicherbedarf der PHP-Interpreter. Magento benötigt aufgrund seiner Komplexität vergleichsweise viel Speicher. Die Limitierung der Nginx-Verbindungen orientiert sich daher an den maximal verfügbaren PHP-Ressourcen.
Die auf PHP bezogenen Konfigurationsdateien liegen unter Debian und Ubuntu im Verzeichnis »/etc/php5/fpm« . Relevant ist dort zunächst die Datei »php.ini« , die Einstellungen für den PHP-Interpreter enthält. Da Magento relativ hungrig nach Arbeitsspeicher ist, sollte der Admin den Wert für das »memory_limit« auf »128M« erhöhen. Zusätzlich empfehlenswert ist es, die Option »expose_php« auf »off« zu setzen, damit die verwendete PHP-Version nicht öffentlich gemacht wird.
Resource Pools
Danach gilt es, die PHP-FPM-Konfiguration an die Hosting-Umgebung anzupassen. Die PHP-Interpreter, die Nginx zur Verfügung stehen, sind in einem Ressource Pool zusammengefasst. Die Konfiguration dieses Pools bestimmt unter anderem, wie viele Prozesse starten und auf welchem Port PHP-FPM auf Verbindungen wartet. Je nachdem, über welchen Port Nginx mit PHP-FPM kommuniziert, lassen sich auf diese Weise unterschiedliche Pools ansprechen. Das spielt für diesen Artikel aber keine Rolle, da nur ein Pool für den Magento-Shop anzulegen ist. Wer mehrere Websites auf demselben System betreibt, kann diesen aber jeweils einen eigenen Ressource Pool zuweisen.
Debian und Ubuntu speichern die Konfigurationen für Resource Pools im Verzeichnis »/etc/php5/fpm/pool.d/« . PHP-FPM liest bei einem Neustart alle Dateien darin, die auf ».conf« enden, und stellt die entsprechenden Ressourcen bereit. Listing 2 zeigt die Konfiguration für den Pool »magento« .
Listing 2
Ressource-Pool-Konfiguration
01 [magento] 02 ; IP und Port für den Ressource Pool 03 listen = 127.0.0.1:9000 04 05 ; Systembenutzer und Gruppe 06 user = www-data 07 group = www-data 08 09 ; dynamische Prozessanzahl 10 pm = dynamic 11 12 ; maximale Anzahl PHP Interpreter 13 ; und maximale Anzahl gleichzeitiger Requests 14 pm.max_children = 96 15 16 ; initiale Anzahl der PHP Interpreter 17 pm.start_servers = 16 18 pm.min_spare_servers = 10 19 pm.max_spare_servers = 70
Dem Beispielserver für diesen Artikel stehen 16 GByte Arbeitsspeicher zur Verfügung. Die Angabe »pm.max_children« definiert, wie viele PHP-Interpreter maximal laufen dürfen (Zeile 14). Ähnlich wie bei einem Apache-Webserver, der mit Prefork-MPM arbeitet, ist dies auch die maximal mögliche Anzahl gleichzeitiger Verbindungen. Das auf 128 MByte gesetzte »memory_limit« sorgt dafür, dass PHP-Prozesse maximal 96 * 128 MByte Arbeitsspeicher belegen, in Summe also rund 12 GByte. Somit bleiben 4 GByte für andere Prozesse auf dem System übrig.
Nginx-Host definieren
Die Konfigurationsdateien für Nginx-Sites liegen bei Debian und Ubuntu im Verzeichnis »/etc/nginx/sites-available/« . Dort befindet sich nach der Installation bereits die Datei »default« , sie dient als Grundlage für die Konfiguration des Magento-Shops. Nach einigen Anpassungen sieht sie aus wie in Listing 3, das die Einträge in den Kommentarzeilen erläutert.
Listing 3
Host-Konfiguration für Nginx
01 server {
02 listen 80;
03 server_name localhost;
04 root /var/www/html/;
05 autoindex off;
06
07 # Gzip-Komprimierung
08 gzip on;
09 gzip_min_length 1100;
10 gzip_buffers 4 8k;
11 gzip_proxied any;
12 gzip_types text/plain text/css application/x-javascript text/javascript application/json;
13
14 location / {
15 index index.php;
16 try_files $uri $uri/ @handler;
17 expires 30d;
18 }
19
20
21 # .htaccess-Schutz ersetzen
22 location ~ (/(app/|includes/|lib/|/pkginfo/|var/|report/config.xml)|/\.svn/|/.hta.+) {
23 deny all;
24 }
25
26 # statische Dateien direkt ausliefern
27 location ~* ^.+.(jpg|jpeg|gif|css|png|js|ico|xml)$ {
28 access_log off;
29 expires 30d;
30 root /var/www/html/;
31 }
32
33 # / an den Magento-Frontcontroller weiterleiten
34 location @handler {
35 rewrite / /index.php;
36 }
37
38 # PHP an PHP-FPM weiterreichen
39 location ~ \.php$ {
40 if (!-e $request_filename) { rewrite / /index.php last; }
41
42 expires off;
43 fastcgi_pass 127.0.0.1:9000;
44 fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
45 include /etc/nginx/fastcgi_params;
46 }
47 }
Dateien schützen
Von besonderer Relevanz ist der Abschnitt für den Zugriffsschutz (Zeilen 22 bis 24). Nginx kennt im Unterschied zu Apache keine ».htaccess« -Dateien. Die vergleichbare Funktionalität steckt in der Konfigurationsdatei der Site. Auch dies ist das Ergebnis einer bewussten Designentscheidung der Nginx-Entwickler: Die Flexibilität einer Konfiguration on the Fly mittels ».htaccess« -Dateien geht zu Lasten der Performance, denn bei jeder HTTP-Anfrage prüft der Server die Existenz dieser Dateien und wertet sie gegebenenfalls aus, bevor er die Anfrage bearbeitet.
Die Konfiguration in Listing 3 stellt jedoch sicher, dass spezielle Verzeichnisse und Dateien, die Magento ansonsten per ».htaccess« -Regeln vor dem Zugriff schützt, nicht über das Web erreichbar sind. Das sind zum Beispiel Konfigurationsdateien, in denen das Passwort und der Benutzername für die Datenbankverbindung hinterlegt sind.
Nach einem Neustart der beteiligten Dienste ist die neue Konfiguration aktiv. Um die PHP-Abarbeitung zu testen, kann der Admin eine PHP-Datei im Verzeichnis »/var/www/html« ablegen und sie mit dem Inhalt
<?php phpinfo(); ?>
füllen. Ruft er anschließend die Serveradresse inklusive des Dateipfads im Browser auf – etwa mit »http://localhost/info.php« –, ist bei erfolgreicher Einrichtung eine Infoseite mit allerhand Interessantem über die Serverumgebung zu sehen (Abbildung 2).
Als abschließender Schritt fehlt jetzt noch die Magento-Installation selbst, die unter anderem im Magento-Wiki beschrieben ist. Hier muss der Anwender nichts gesondert beachten, da mit Nginx und PHP-FPM eine vollständige Hostingumgebung für die Ansprüche der Software bereitsteht. Danach ist der Shop bereit für einen kleinen Benchmark, den der Kasten “Performance-Zahlen” beschreibt. Im Vergleich zu Apache mit »mod_php« schneidet die Nginx-Konfiguration aus diesem Artikel blendend ab: Sie bedient rund eineinhalbmal so viele Anfragen pro Sekunde wie die Konkurrenz.
Performance-Zahlen
Ein einfacher Performance-Test vergleicht eine Magento-Installation mit Nginx und PHP-FPM mit der Kombination aus Apache und »mod_php« . Als Testsystem dient ein Rechner mit dem Quadcore-Prozessor Phenom II von AMD mit 3,2 GHz sowie mit 8 GByte RAM. Als Betriebssystem kommt Ubuntu 11.10 zum Einsatz.
Das Apache-Benchmark-Tool »ab« [8] ruft die Startseite des Magento-Shops auf. Das geschieht einmal mit 150 gleichzeitigen Anfragen, einmal mit 200. Abbildung 3 zeigt, dass die Nginx-Konfiguration mit durchschnittlich 4,88 Anfragen pro Sekunde rund eineinhalbmal so viele beantwortet wie Apache (3,39). Bei 200 parallelen Requests fällt der Unterschied mit 4,76 gegenüber 2,96 Anfragen sogar noch deutlicher aus.
Ausblick
Eine sinnvolle Erweiterung der hier beschriebenen Konfiguration für den produktiven Betrieb ist SSL-Verschlüsselung, um die Daten der Kunden zu schützen. Das lässt sich aber ohne Schwierigkeiten mit Hilfe der offiziellen Dokumentation einrichten. Für stärker frequentierte Magento-Installationen ist zudem das Nginx-Modul »upstream« interessant. Damit lassen sich Nginx und PHP getrennt und auf unterschiedlichen Systemen betreiben, was die Skalierung von Webprojekten sehr vereinfacht.
Der Autor dieses Beitrags hat in mehreren Magento-Projekten, bei denen er auch die Einrichtung der Hostingumgebung betreut hat, durchweg positive Erfahrungen mit Nginx gemacht. Speziell bei kleineren Shops, denen nur begrenzte Ressourcen zur Verfügung standen, erzielte er dank des geringeren Speicherbedarfs sehr gute Ergebnisse.
Wer derzeit noch einen Apache-Webserver mit »mod_php« betreibt, kann bei Interesse Nginx und PHP-FPM parallel konfigurieren und nach erfolgreicher Einrichtung im produktiven Betrieb ausprobieren. Bei Bedarf lässt sich dann jederzeit wieder die bewährte Apache-Variante in Betrieb nehmen. (mhu)
Infos
- Magento Commerce: http://www.magentocommerce.com
- Nginx: http://www.nginx.org
- “10.000 Requests per Second with Nginx”: http://blog.webfaction.com/a-little-holiday-present
- PHP-FPM: http://php-fpm.org
- Fast-CGI-Ansatz: http://de.wikipedia.org/wiki/FastCGI
- PHP-Hardening mit Suhosin: http://www.hardened-php.net/suhosin/
- PHP-Accelerator APC: http://pecl.php.net/package/APC
- Apache-HTTP-Server-Benchmarking-Tool: http://httpd.apache.org/docs/2.2/programs/ab.html








