Nachdem der Webserver nginx mit php-fpm läuft ist es Zeit für etwas Feintuning.
Ausgangspunkt ist ein Single-Core-Server mit nur 250MB RAM. Dieser wird als Statistikserver (PIWIK etwa 10 Webseiten) und als Testumgebung (WordPress) genutzt. Der Trafic hält sich somit in Grenzen.
Nginx Gundkonfiguration
Als erstes habe ich die Anzahl der nginx-Worker begrenzt. Optimaler Weise sollte die Anzahl der Worker = CPU Cores entsprechen. Die Anzahl der Verbindungen pro Worker kann über worker_connections =xxxx; eingestellt werden. In meinem Beispiel sind es 768.
Die Anzahl gleichzeitiger Verbindungen ergibt sich dann aus:
Anzahl der Worker * Worker-Connections = max. mögliche gleichzeitige Verbindungen
In meinem Beispiel sind es 768 Verbindungen, völlig ausreichend für eine low-trafic-Seite.
Ein weiterer wichtiger Punkt ist Keep-Alive. Dieser Wert sollte so klein wie möglich gewählt werden, aber mindestens so groß wie die Ladezeit der Webseite. 6 Sekunden sollte in meinem Fall ein guter Kompromiss sein.
/etc/nginx/nginx.conf
worker_processes 1;
events {worker_connections 768; }
keepalive_timeout 6;
Cache Steuerung
Um Bandbreite zu sparen und die Reaktionszeit der Webseiten zu verbessern ist eine vernünftige Cache-Vorgabe unabdingbar. Sämtlicher statischer Inhalt soll vom Browser für 30 Tage gecacht werden:
/etc/nginx/sites-available/webseite
location ~* \.(jpg|jpeg|gif|png|css|js|ico|xml)$ {
access_log off;
log_not_found off;
expires 30d;
}
Für diese Requests lasse ich auch keine Logs schreiben.
Diese Werte sind für jeden V-Host einzeln zu setzten.
Rewrite für WordPress
Nun noch eine Besonderheit für WordPress. Um die Funktion Permalinks zu nutzen benötigen wir eine einfache Rewrite-Regel. Beachtet aber das das Rootverzeichniss von WordPress (da wo die index.php zu finden ist) auch das root des V-Host sein muss.
if (!-e $request_filename) {
rewrite /(.+)/$ /index.php?q=$1 last;
rewrite ^/(.+)$ /index.php?q=$1 last;
}
ausleiten von PHP an fastcgi (PHP-FPM):
location ~ \.php$
{
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
Benchmark mit ApacheBench:
nun machen wir mal eine Bestandsaufnahme um bei weiteren Optimierungen den Erfolg prüfen zu können.
Dafür lasse ich mir mal den Text einer 591byte großen Datei ausgeben.
Server Software: nginx/1.0.10
Server Hostname: piwik.gettoweb.de
Server Port: 80
Document Path: /hello.txt
Document Length: 591 bytes
Concurrency Level: 20
Time taken for tests: 0.462 seconds
Complete requests: 2000
Failed requests: 0
Write errors: 0
Total transferred: 1606000 bytes
HTML transferred: 1182000 bytes
Requests per second: 4328.36 [#/sec] (mean)
Time per request: 4.621 [ms] (mean)
Time per request: 0.231 [ms] (mean, across all concurrent requests)
Transfer rate: 3394.21 [Kbytes/sec] received
und jetzt das Gleiche, nur über PHP mit xcache geparst:
Server Software: nginx/1.0.10
Server Hostname: piwik.gettoweb.de
Server Port: 80
Document Path: /hello.php
Document Length: 591 bytes
Concurrency Level: 20
Time taken for tests: 7.999 seconds
Complete requests: 2000
Failed requests: 0
Write errors: 0
Total transferred: 1498000 bytes
HTML transferred: 1182000 bytes
Requests per second: 250.04 [#/sec] (mean)
Time per request: 79.987 [ms] (mean)
Time per request: 3.999 [ms] (mean, across all concurrent requests)
Transfer rate: 182.89 [Kbytes/sec] received
und jetzt noch einmal das ganze über PHP mit APC:
Server Software: nginx/1.0.10
Server Hostname: piwik.gettoweb.de
Server Port: 80
Document Path: /hello.php
Document Length: 591 bytes
Concurrency Level: 20
Time taken for tests: 3.256 seconds
Complete requests: 2000
Failed requests: 0
Write errors: 0
Total transferred: 1528000 bytes
HTML transferred: 1182000 bytes
Requests per second: 614.31 [#/sec] (mean)
Time per request: 32.557 [ms] (mean)
Time per request: 1.628 [ms] (mean, across all concurrent requests)
Transfer rate: 458.34 [Kbytes/sec] received
Wahnsinn: 4328Req/sek (txt) ,250Req/sek (php-xcache) zu 614Req/sek (php-apc)
Mit solch einem gewaltigen Unterschied hätte ich jetzt nicht gerechnet.
Jetzt habe ich das ganze mal mit einer echten WordPress-Seite (10412 bytes) getestet:
PHP-xcache: Requests per second: 1.39 [#/sec]
PHP-APC: Requests per second: 1.27 [#/sec]
PHP-APC (apc.stat = Off) :Requests per second: 1.46 [#/sec]
Mit dem PHP muss ich mich also noch einmal genauer beschäftigen!
Vor allem bei nginx tritt der Unterschied doch etwas mehr zu Tage. Gutes Beispiel für wie lahm PHP doch eigentlich ist ;-)
Was mich an dem Benchmark noch interessieren würde, wäre einmal ohne OPCode Cacher. Also nginx mit „purem“ php dahinter.
Das Problem an PHP, du kannst es einfach nicht schneller machen, außer du spawnst mehr Prozesse… Ähnlich wie mysql ab einer gewissen Größe/Belastung hilft dann nur noch horizontales skalieren und kein tunen.
Gruß, Paul
@Paul: ein Test X-Cache gegen APC und ohne Beschleuniger werde ich demnächst mit einer WordPress-Installation durchführen. Dieser Test findet jedoch auf einen anderen Server statt, da der ursprüngliche Server wegen Hardwaredefekt getauscht wurde.
Eventuell vergleiche ich das ganze auch noch einmal kurz gegen den Apache2. Mal sehen wie ich die Zeit dazu finde.