Ein Wiki privater Natur

Nextcloud performance

Nextcloud fühlte sich träge an. Nicht dauerhaft, aber das Wechseln zwischen Dashboard und einer anderen App dauerte regelmäßig drei bis zehn Sekunden. Danach lief es flüssig.

Diagnose

Zuerst Redis geprüft, weil der als Session- und File-Locking-Cache läuft:

redis-cli info stats | grep -E 'keyspace_hits|keyspace_misses'

Ergebnis: 4,6 Millionen Hits, 379.000 Misses, Trefferquote rund 92 %. Redis war in Ordnung.

Dann die PHP-FPM-Konfiguration:

grep -E 'pm\b|pm\.' /etc/php/8.3/fpm/pool.d/www.conf
pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3

Fünf Worker maximal, einer davon mindestens im Leerlauf. Bei einem Server mit 62 GB RAM und einem Nextcloud-Cronjob alle zehn Minuten ist das knapp.

Dann OPcache:

grep -E 'opcache.enable|opcache.memory_consumption' /etc/php/8.3/fpm/php.ini
;opcache.enable=1
;opcache.memory_consumption=128

Alles auskommentiert.
OPcache war komplett deaktiviert. Nextcloud hat bei jedem einzelnen Request alle PHP-Dateien neu geparst und kompiliert. Das war die Ursache.

Lösung

In /etc/php/8.3/fpm/php.ini:

opcache.enable=1
opcache.enable_cli=0
opcache.memory_consumption=256
opcache.interned_strings_buffer=32
opcache.max_accelerated_files=10000
opcache.revalidate_freq=60
opcache.save_comments=1

In /etc/php/8.3/fpm/pool.d/www.conf:

pm.max_children = 20
pm.start_servers = 5
pm.min_spare_servers = 4
pm.max_spare_servers = 10

Neu laden:

systemctl reload php8.3-fpm

Hintergrund

OPcache speichert kompilierte PHP-Bytecodes im Shared Memory. Ohne OPcache kompiliert PHP bei jedem Request neu, mit OPcache passiert das einmal und wird für alle Worker wiederverwendet. Für eine Anwendung wie Nextcloud mit hunderten PHP-Dateien macht das einen spürbaren Unterschied.

pm.min_spare_servers bestimmt, wie viele FPM-Worker im Leerlauf bereitstehen. Zu niedrige Werte bedeuten: kein freier Worker vorhanden, neuer muss gestartet werden, OPcache für den neuen Worker muss erst aufgewärmt werden. Der erste Request nach einer Pause zahlt dafür den Preis.

ISPConfig-Umgebungen

Wer ISPConfig einsetzt, hat zwei Stellen für PHP-Einstellungen:

  1. /etc/php/8.3/fpm/php.ini – globale Konfiguration, gilt für alle Sites ohne eigene Einstellungen
  2. ISPConfig-Webinterface pro Site unter "PHP-Optionen" – wird als php_admin_value in den FPM-Pool geschrieben und überschreibt die globale php.ini

Im konkreten Fall hatte ISPConfig für die Nextcloud-Site bereits OPcache-Parameter gesetzt (memory_consumption, interned_strings_buffer usw.), aber opcache.enable=1 fehlte. Das Ergebnis: OPcache war konfiguriert, aber nicht aktiv.

Die Korrektur in der globalen php.ini hat opcache.enable=1 gesetzt und damit OPcache für alle Sites auf dem Server aktiviert, die keine eigenen PHP-Optionen in ISPConfig haben.

Beim Debuggen von OPcache-Problemen immer beide Stellen prüfen. ISPConfig gewinnt im Zweifelsfall, weil es später in der Ladekette greift.