PHP-FPM Einstellungen optimieren

Heute geht es darum den unter PHP Nutzern bekannten FastCGI Process Manager (FPM) richtig zu konfigurieren und zu optimieren. (https://php-fpm.org/)

Die meisten PHP Anwendungen verwenden Heutzutage den PHP-FPM um Ihre PHP Anwendungen auszuliefern. In Kombination mit NGINX als Webserver ist dies mit einer der effektivsten Methoden eine Webanwendung mit PHP im Produktiveinsatz laufen zu lassen.

Der Teufel steckt im Detail

Bei FPM reichen schon ein paar falsch gesetzte Werte und schon startet der FPM Prozess nicht mehr oder der Speicher des Servers läuft voll oder oder oder ... die Liste ist lang ;)

Häufige Fehler die auftreten können:
  • FPM Master Prozess startet nicht mehr
  • RAM des Servers läuft voll
  • "server reached max_children"

Prüfen ob PHP-FPM Prozess läuft

Das Beispiel zeigt die PHP-FPM Prozesse und für welche pool Konfiguration / User diese ist, in dem Falle zu sehen "web1" da unter ISPConfig der erste angelegt Host "web1" ist.
ps aux | grep fpm

PHP-FPM Konfiguration anpassen

In diesem Beispiel hier zeige ich euch wie Ihr die Konfiguration anpasst anhand einer ISPConfig Standard Installation mit einer angelegten Webseite. Dazu bearbeiten wir die Datei:

nano /etc/php/7.0/fpm/pool.d/web1.conf

Der Inhalt der Datei sieht dann so aus (kann je nach Installation abweichen):

[web1]

listen = /var/lib/php7.0-fpm/web1.sock
listen.owner = web1
listen.group = www-data
listen.mode = 0660

user = web1
group = www-data

pm = dynamic
pm.max_children = 50
pm.start_servers = 12
pm.min_spare_servers = 8
pm.max_spare_servers = 24
pm.max_requests = 1000

....
....

Ich werde jetzt die wichtigsten Einstellung im Detail erklären und euch gegebenenfalls Hinweise dazu geben. Aber fangen wir direkt an mit der wohl wichtigsten Einstellung "pm.max_children".

Wichtigste PHP-FPM Einstellungen einfach erklärt

  • pm (string)
    • es gibt 3 mögliche Einstellungen, dynamic ist meistens die beste Wahl
      • static - Anzahl der Kindprozesse ist fest (pm.max_children)
      • ondemand - Kindprozess wird erst erstellt wenn er benötigt wird (pm.start_servers)
      • dynamic - dynamische Einstellung der Kindprozesse (benötigt folgenden Einstellungen: pm.max_children, pm.start_servers, pm.min_spare_servers, pm.max_spare_servers)
  • pm.max_children (int)
    • Anzahl der Kindprozesse die erstellt werden wenn pm = static oder die maximale Anzahl der Kindprozesse wenn pm = dynamic. Einstellung ist notwendig!
  • pm.start_servers (int)
    • Anzahl an Kindprozessen, die beim Start erstellt werden. Wird nur verwendet, wenn pm auf dynamic gesetzt ist. Standardwert: min_spare_servers + (max_spare_servers - min_spare_servers) / 2.
  • pm.min_spare_servers (int)
    • gewünschte Mindestanzahl an Prozessen. Wird nur genutzt, wenn pm auf dynamic gesetzt ist. Zwingend notwendig!
  • pm.max_spare_servers (int)
    • gewünschte Maximalanzahl an Prozessen. Wird nur genutzt, wenn pm auf dynamic gesetzt ist. Zwingend notwendig!
  • pm.max_requests (int)
    • Anzahl der Requests bis der FPM Prozess neustartet, hilft Memory Leaks in einigen PHP Libs zu fixen
Noch viele weitere und detailliertere Beschreibungen könnt Ihr in der Dokumentation von PHP finden.

Optimalen Wert für "pm.max_children" bestimmen

Um den perfekten Wert für pm.max_children zu finden muss man zuerst herausfinden wieviel Speicher ein FPM Prozess mit der aktuellen Anwendung verbraucht. Dazu können wir auf 2 verschiedenen Befehle zurück greifen.

ps -ylC php-fpm7.0 --sort:rss

Das sollte dann in etwa so bei euch aussehen:
Für uns von Bedeutung ist die Spalte "RSS" diese gibt den Speicherverbrauch des Prozesses in Kilobyte an. Also wären 43868 rund ~ 43MB für diesen Prozess. Um das ganze etwas zu vereinfachen können wir aber einfach den Befehl ausführen und erhalten den Durchschnitt.

ps --no-headers -o "rss,cmd" -C php-fpm7.0 | awk '{ sum+=$1 } END { printf ("%d%s\n", sum/NR/1024,"Mb") }'

// Output
34Mb

Mit diesem Verbrauchswert können wir nun den passenden Wert für pm.max_children berechnen. Dazu nehme ich einfach mal ein Beispiel (einen VPS der 2GB RAM hat).
  • VPS mit 2 GB RAM
    • wir ziehen 256 MB ab da noch andere Dienste auf dem VPS laufen
    • uns bleiben 1792 MB Ram
      • Formel: max_children = Free RAM VPS / RAM pro Prozess
      • max_children = 1792 / 34
      • = 52,7 = ~ 52
Der Ideale Wert für diesen VPS wäre also pm.max_children = 52. Natürlich sollte man diesen Wert nicht einfach Blind übernehmen! Ändert eure Einstellungen und dann testet wie sich euer Server verhält. Wenn Ihr eure Konfiguration angepasst habt, startet Ihr am besten euer FPM neu. Dies könnt Ihr mit folgendem Befehl machen:

sudo /etc/init.d/php7.0-fpm restart

Resümee

Ein optimal Konfigurierter PHP-FPM Service erspart euch auf eurem Produktivsystem eine Menge ärger. Denn niemand möchte einen überlaufenden Speicher oder eine langsame PHP Anwendung nur weil der FPM Dienst falsch konfiguriert ist. Nehmt euch die Zeit ermittelt die optimalen Werte und setzt diese dann um. Oft hilft es auch die Logs regelmäßig zu checken um sehen ob alles ohne Probleme funktioniert und ob nicht doch der Server bald an seine Grenzen kommt. 

Ich hoffe ich konnte dem ein oder anderem das Mysterium PHP-FPM näher bringen und wünsche euch viel Erfolg beim optimieren eurer Einstellungen.

Kommentar veröffentlichen