Performance
Gepflegt von der BW-Tech GmbH.
Vergleichen Sie Messwerte vor und nach einer Änderung immer mit identischem Datenbestand, identischer Hardware und denselben Benchmark-Parametern. Einzelne Messwerte aus SQLite-Entwicklungsinstanzen sind keine Aussage über den Produktivbetrieb.
Stufenplan
- Ausgangswerte mit API-, WebDAV-, Upload- und Download-Messungen erfassen.
- PHP-FPM, OPcache, MariaDB, Redis-Locking, APCu, System-Cron und begrenzte Aufbewahrung (Retention) auf einer isolierten Staging-Instanz prüfen.
- Einen anonymisierten Produktionsdatenbestand mit mindestens einer Million
Filecache-Einträgen messen. Erst danach zusätzliche Indizes anhand von
EXPLAINund Slow-Query-Log bewerten. - Den Desktop-Sync mit unverändertem Testbestand profilieren. Server- und Client-Änderungen getrennt messen.
- Änderungen zuerst auf einer Canary-Instanz ausrollen und dabei Fehlerquote, Datenbanklatenz, Wartezeiten auf Sperren, Auslastung von PHP-FPM und Sync-Dauer überwachen.
Jede Stufe hat einen eigenen Vorher-Nachher-Vergleich und einen dokumentierten Weg zurück.
Referenzmessung
Die Stufen 1 bis 3 wurden mit PHP 8.4, nginx, PHP-FPM, MariaDB, Redis und APCu auf einer isolierten Instanz gemessen. Der Datensatz für Stufe 3 enthielt 1.000 Ordner mit jeweils 1.000 Dateien und damit mehr als eine Million Filecache-Einträge.
| Messung | SQLite/PHP-Server | MariaDB/Redis/nginx | Mit 1 Mio. Filecache-Einträgen |
|---|---|---|---|
| 100 kleine Uploads | 41,07 s | 7,53 s | 7,45 s |
| Upload 16 MiB | 26,12 MiB/s | 34,95 MiB/s | 33,99 MiB/s |
| Download 16 MiB | 42,83 MiB/s | 54,84 MiB/s | 44,62 MiB/s |
| PROPFIND p95 | 350,43 ms | 338,89 ms | 322,47 ms |
files:cleanup brauchte mit einer Million gültigen und 10.000 verwaisten
Einträgen zunächst 9,33 Sekunden. Seit der Befehl verwaiste Einträge je Speicher
löscht, dauert derselbe Lauf 0,81 Sekunden.
Die Messung rechtfertigt keine zusätzlichen Standardindizes:
(storage, path_hash)bedient die exakte Pfadauflösung.(parent, name)bedient Ordnerlisten einschließlich der Sortierung nach Namen.- Ein eigener Index nur auf
parentwäre überflüssig. - Die Sync-Abfragen des Kerns sortieren nicht global nach
mtime. Ein zusätzlichermtime-Index würde Schreibkosten erhöhen, ohne den gemessenen Sync-Pfad zu beschleunigen. - Suchen mit führendem Platzhalter wie
%begriff%können keinen normalen B-Tree-Index effizient nutzen. Eine Volltextsuche wäre eine eigene Funktion, die für alle unterstützten Datenbanken entwickelt werden müsste.
Empfohlene Produktionsbasis
- PHP 8.4 FPM mit aktiviertem OPcache
- MariaDB oder MySQL statt SQLite
- Redis für transaktionale Dateisperren
- APCu als lokaler Zwischenspeicher
- System-Cron statt AJAX- oder Webcron
- genug RAM für Datenbank und PHP-FPM, ohne dass das System auslagert
- niedrige Latenz zwischen Webserver, Datenbank, Redis und Speicher
Redis und PHP-Erweiterungen prüfen:
redis-cli ping
php8.4 -m | grep -E 'apcu|redis|Zend OPcache'
Konfiguration von owncloud.online prüfen:
sudo -u www-data php8.4 occ config:system:get dbtype
sudo -u www-data php8.4 occ config:system:get memcache.local
sudo -u www-data php8.4 occ config:system:get memcache.locking
sudo -u www-data php8.4 occ background:queue:status
OPcache-Dimensionierung
Der Standardwert opcache.max_accelerated_files=10000 reicht für
owncloud.online nicht. Das Release-Paket 11.0.25 bringt allein 5.878
PHP-Dateien mit, jede App aus dem Marktplatz weitere, einzelne Apps samt ihren
Bibliotheken über 1.000. Mit allen Apps sind es über 14.000. Wird das Limit
überschritten, verdrängt OPcache Einträge und kompiliert unter wechselnder Last
laufend Dateien neu. Zählen Sie die Dateien und setzen Sie das Limit darüber:
find /var/www/owncloud.online -name '*.php' | wc -l
Empfohlene Werte für php.ini bzw. den FPM-Pool:
opcache.enable=1
opcache.memory_consumption=256 ; MB, 512 bei sehr vielen Apps
opcache.interned_strings_buffer=32
opcache.max_accelerated_files=24000 ; muss die Dateizahl übersteigen
opcache.validate_timestamps=0 ; nur mit OPcache-Reset beim Update
opcache.enable_cli=0 ; CLI/Cron braucht keinen persistenten OPcache
Mit validate_timestamps=0 werden Code-Änderungen erst nach einem Neuladen von
PHP-FPM oder einem OPcache-Reset sichtbar. Laden Sie PHP-FPM deshalb nach jedem
Update neu (systemctl reload php8.4-fpm), sonst laufen alte Klassen weiter.
OPcache-Preloading (PHP 8.4)
Aufbauend auf der Dimensionierung oben kann OPcache den stabilen Server-Code
schon beim Start von PHP-FPM kompilieren und verlinken (Preloading). Die
Worker sparen sich damit das Verlinken der Klassen bei jeder Anfrage und die
Aufwärmphase nach jedem Neuladen. Das Skript build/preload.php lädt
lib/private, lib/public, core/ und die Composer-Bibliotheken unter
lib/composer. App-Verzeichnisse lädt es bewusst nicht, weil Apps im laufenden
Betrieb aktiviert, deaktiviert und aktualisiert werden.
Das Skript liegt im Quellcode-Repository, nicht im Release-Paket. Für eine
Installation aus dem Release-Paket legen Sie es passend zur installierten
Version unter build/ im Installationsverzeichnis ab. Es bestimmt das
Installationsverzeichnis über seinen eigenen Ablageort und muss deshalb genau
dort liegen:
sudo -u www-data mkdir -p /var/www/owncloud.online/build
sudo -u www-data curl -fLo /var/www/owncloud.online/build/preload.php \
https://raw.githubusercontent.com/BWTECH-github/owncloud.online/v11.0.25/build/preload.php
Von außen ist die Datei nicht abrufbar: Die .htaccess und die
nginx-Konfiguration aus der Installationsanleitung
sperren build/.
Aktivierung in der FPM-Pool-Konfiguration bzw. php.ini:
opcache.preload=/var/www/owncloud.online/build/preload.php
opcache.preload_user=www-data
Hinweise:
- Preloading setzt dieselbe Disziplin wie
validate_timestamps=0voraus: nach jedem Update PHP-FPM neu laden, sonst läuft alter Code weiter. - Ein Update ersetzt das Programmverzeichnis,
build/preload.phpfehlt danach. Legen Sie die Datei in der Version des neuen Release wieder ab, bevor PHP-FPM neu startet. Fehlt sie, bricht PHP schon beim Start mit „Failed opening required …“ ab. - Meldungen wie
Can't preload unlinked classbeim Start sind harmlos. Diese Klassen liegen unverlinkt im Zwischenspeicher und werden beim ersten Zugriff verlinkt. - Das Skript ist fehlertolerant: Einzelne Dateien, die sich nicht kompilieren
lassen, überspringt es, sie verhindern den Start von PHP-FPM nicht. Ins
Fehlerprotokoll von PHP schreibt es eine Zeile
owncloud.online preload: compiled N of M files. - Aktivieren Sie Preloading zuerst auf einer Staging-Instanz und prüfen Sie den
Start (
systemctl restart php8.4-fpm && systemctl status php8.4-fpm).
Frontend-Auslieferung
Die Weboberfläche lädt JavaScript und CSS als viele einzelne Dateien. Seit
11.0.12 sind die Dateien des Kerns und der mitgelieferten Apps minifiziert, und
unter Apache komprimiert die mitgelieferte .htaccess sie mit mod_brotli oder
mod_deflate. Gebündelt werden die Dateien nicht. Am TLS-Terminator senken
deshalb diese Punkte die Ladezeit am stärksten:
- HTTP/2 einschalten: Per Multiplexing laufen die vielen Einzeldateien gleichzeitig über eine Verbindung, statt nacheinander auf Antworten zu warten
- Keepalive zum PHP-FPM-Upstream
- gzip oder brotli für
text/*,application/javascriptundapplication/json, wenn die Dateien nicht von Apache mit der mitgelieferten.htaccessausgeliefert werden
Grenzen einzelner Server-Optimierungen
Auf einer Instanz mit warmem OPcache bewegt der kompilierte Routen-Cache
(route.cache) die Antwortzeit nicht messbar: OPcache hält die Routen-Dateien
bereits vor, und der Router baut ohnehin nur die Routen bereits geladener Apps.
Der Routen-Cache hilft vor allem bei kaltem oder abgeschaltetem OPcache und
frisch gestarteten FPM-Workern.
Den größten Teil der Kosten einer angemeldeten Anfrage verursachen das wiederholte Passwort-Hashing (bcrypt) und der Aufbau von Sitzung und Dateisystem. Ein Client, der sein Sitzungs-Cookie über mehrere Anfragen hält, ist um ein Vielfaches schneller als einer, der sich bei jeder Anfrage erneut per HTTP-Basic anmeldet. Sync- und API-Clients sollten das Sitzungs-Cookie deshalb wiederverwenden.
Für Desktop- und Mobil-Client ist das bcrypt-Problem bereits gelöst: Sie melden
sich mit einem Geräte-Token an (oc_authtoken, App-Passwort), nicht mit dem
Passwort des Kontos. OC\User\Session::checkTokenCredentials() prüft bcrypt
nur, wenn die Spalte last_check des Tokens älter als last_check_timeout
(Vorgabe 5 Minuten) ist, nicht bei jeder Anfrage. Einen Zwischenspeicher für
Passwortprüfungen, der auf dem Klartext-Passwort beruht, legt owncloud.online
bewusst nicht an: Er müsste Passwortdaten speichern und würde die Bremse gegen
Passwort-Raten, die Begrenzung der Anfragerate und den Widerruf von Tokens
aushebeln. Das verbleibende bcrypt pro Anfrage betrifft nur Clients ohne Token,
die das Passwort des Kontos ohne dauerhafte Sitzung senden (etwa fremde
WebDAV-Integrationen).
Aufbewahrung (Retention)
Alte Aktivitäten, Objekte im Papierkorb und Versionen erhöhen auf Dauer die Last für Datenbank und Speicher. Die folgenden Werte sind ein Ausgangspunkt für Installationen ohne abweichende Aufbewahrungspflichten:
sudo -u www-data php8.4 occ config:system:set \
activity_expire_days --type integer --value 64
sudo -u www-data php8.4 occ config:system:set \
trashbin_retention_obligation --value 'auto, 30'
sudo -u www-data php8.4 occ config:system:set \
versions_retention_obligation --value 'auto, 30'
Prüfen Sie vorher vertragliche und gesetzliche Aufbewahrungsregeln. Die Befehle löschen nichts sofort. Die Bereinigung übernehmen die Hintergrund-Jobs.
Zurück zur Standardautomatik:
sudo -u www-data php8.4 occ config:system:delete activity_expire_days
sudo -u www-data php8.4 occ config:system:set \
trashbin_retention_obligation --value auto
sudo -u www-data php8.4 occ config:system:set \
versions_retention_obligation --value auto
Filecache-Wartung
Sichern Sie vor Wartungsbefehlen Datenbank und Datenverzeichnis, siehe Backups und Updates.
sudo -u www-data php8.4 occ files:cleanup
files:cleanup entfernt ausschließlich Filecache-Einträge, deren Speicher
nicht mehr existiert. Es ersetzt keine Bereinigung von Papierkorb oder
Versionen.
Tabellengrößen beobachten:
SELECT COUNT(*) FROM oc_filecache;
SELECT COUNT(*) FROM oc_activity;
SELECT COUNT(*) FROM oc_file_locks;
Legen Sie zusätzliche Indizes nicht blind an. Messen Sie vorher und nachher
EXPLAIN, Schreiblast, Speicherverbrauch und einen echten Desktop-Sync. Der
vorhandene Index auf (parent, name) bedient reine parent-Abfragen bereits.
Reproduzierbarer Benchmark
Der Benchmark liegt im Quellcode-Repository, nicht im Release-Paket:
tests/performance/benchmark.py
Er braucht nur Python 3 ohne weitere Pakete. Er legt im Konto einen eigenen
Ordner an und löscht ihn nach der Messung wieder (außer mit --keep-data).
Beispiel:
export OC_BASE_URL=https://staging.example.com
export OC_USERNAME=performance
export OC_PASSWORD='lokales-testpasswort'
python3 tests/performance/benchmark.py \
--latency-requests 50 \
--small-files 10000 \
--large-size 536870912 \
--concurrency 8 \
--output build/performance/staging.json
Das Testkonto darf keine produktiven Daten enthalten. Für einen Vorher-Nachher-Vergleich müssen Datenmenge, App-Liste, Netzwerklatenz, Parallelität und Serverkonfiguration unverändert bleiben.