Blog
Wie Sie die PHP-Leistung auf Google Cloud Run optimieren

Ich musste kürzlich die Leistung einer PHP-basierten API auf Cloud Run optimieren. Nach einem Leistungstest stellten wir fest, dass die API sehr langsam wurde, wenn wir sie stark belasteten (mit Antwortzeiten von über 10 Sekunden). In diesem Beitrag erfahren Sie, welche Änderungen ich vorgenommen habe, um diese Zeit auf stabile 100 ms zu senken.
Die API verwendet PHP 7.4, Laravel 8.0 und MySQL auf Cloud SQL (die verwaltete Datenbank auf Google Cloud). Die API muss mindestens 10.000 gleichzeitige Benutzer verarbeiten können. Das Container-Image, das wir auf Cloud Run bereitstellen, verfügt über nginx und PHP-FPM.
Das habe ich getan, um die Antwortzeiten zu verbessern. (Machen Sie sich keine Sorgen, wenn hier nicht alles Sinn macht, ich werde alles erklären).
- Anpassung der Anzahl der PHP-FPM-Worker an die Einstellung für die maximale Gleichzeitigkeit in Cloud Run.
- Konfigurieren von OPcache (kompiliert und cached PHP-Skripte)
- Verbesserung der Einstellungen für das automatische Laden des Composers
- Laravel-spezifische Optimierungen, einschließlich Caching von Routen, Ansichten, Ereignissen und der Verwendung von API-Ressourcen
Abgleich von Gleichzeitigkeit und Arbeitern
Die Anwendung verwendet nginx und PHP-FPM, einen Prozessmanager für PHP. PHP ist Single-Thread-fähig, d.h. ein Prozess kann eine (genau eine) Anfrage zur gleichen Zeit bearbeiten. PHP-FPM hält einen Pool von PHP-Workern (ein Worker ist ein Prozess) bereit, um Anfragen zu bedienen, und fügt weitere hinzu, wenn die Nachfrage steigt. Es ist eine gute Praxis, die maximale Größe des PHP-FPM-Worker-Pools zu begrenzen, um sicherzustellen, dass Ihre Ressourcennutzung (CPU und Speicher) vorhersehbar ist.
Um PHP-FPM für maximale Leistung zu konfigurieren, habe ich zunächst den Prozessmanagertyp für PHP-FPM auf statisch gesetzt, so dass die angegebene Anzahl von Workern jederzeit läuft und darauf wartet, Anfragen zu bearbeiten. Dazu habe ich eine benutzerdefinierte Konfigurationsdatei in den Container der Anwendung kopiert und die Umgebung so konfiguriert, dass diese Optionen von PHP-FPM übernommen werden (Sie müssen die Konfiguration dorthin kopieren, wo sie erwartet wird, in meinem Fall nach /usr/local/etc/php-fpm.d/). Die von mir benötigten Einstellungen sind:
pm = static
pm.max_children = 10
Wenn Sie jedoch ein Limit festlegen und mehr Anfragen auf einem Server eingehen, als der Pool bewältigen kann, beginnen die Anfragen sich in der Warteschlange anzustellen, wodurch sich die Antwortzeit dieser Anfragen erhöht:
Begrenzung gleichzeitiger Anfragen bei Cloud Run
Um die Warteschlangenbildung in Nginx zu vermeiden, müssen Sie die Anzahl der Anfragen, die Cloud Run gleichzeitig an Ihren Container sendet, begrenzen.
Cloud Run verwendet anforderungsbasierte Autoskalierung. Das bedeutet, dass es die Anzahl der gleichzeitigen Anfragen an einen Container begrenzt und weitere Container hinzufügt, wenn alle Container ihr Limit erreicht haben. Sie können diese Grenze mit der

Achten Sie unbedingt darauf, dass die Gleichzeitigkeitseinstellung von Cloud Run mit der maximalen Anzahl von PHP-FPM-Arbeitern übereinstimmt! Wenn Cloud Run beispielsweise 100 gleichzeitige Anfragen an einen Container sendet, bevor Sie weitere Container hinzufügen, und Sie Ihren PHP-FPM so konfiguriert haben, dass er nur 10 Worker startet, werden Sie eine Menge Anfragen in der Warteschlange sehen.
Wenn diese Optimierungen nicht ausreichen, um die gewünschte Leistung zu erreichen, überprüfen Sie die Cloud Run-Metriken, um zu sehen, wie hoch der tatsächliche Nutzungsgrad ist. Möglicherweise müssen Sie die Menge an Arbeitsspeicher und vCPUs ändern, die dem Container zur Verfügung stehen. Der Nachteil dieser Optimierung ist, dass aufgrund der geringeren Gleichzeitigkeit mehr Container ausgeführt werden, was zu höheren Kosten führt. Außerdem habe ich beim Starten neuer Instanzen vorübergehende Verzögerungen festgestellt, die sich jedoch mit der Zeit normalisieren.
OPCache konfigurieren
OPCache ist eine Standard-PHP-Erweiterung, die die kompilierten Skripte im Speicher zwischenspeichert und so die Antwortzeiten erheblich verbessert. Ich habe die OPCache-Einstellungen aktiviert und angepasst, indem ich die Optionen der Erweiterung zu einer benutzerdefinierten php.ini Datei hinzugefügt habe (in meinem Fall habe ich sie in das Verzeichnis /usr/local/etc/php/conf.d/ gelegt). Im Folgenden finden Sie eine allgemeine Konfiguration, die Sie leicht wiederverwenden können. Die Einzelheiten zu den einzelnen Optionen entnehmen Sie bitte der Dokumentation.
opcache.enable=1
opcache.memory_consumption=128
opcache.interned_strings_buffer=64
opcache.max_accelerated_files=32531
opcache.validate_timestamps=0
opcache.save_comments=1
opcache.fast_shutdown=0
Composer optimieren
Composer ist ein Abhängigkeitsmanager für PHP. Mit ihm können Sie die Bibliotheken angeben, die Ihre Anwendung benötigt, und er lädt sie für Sie in ein Verzeichnis herunter. Außerdem generiert er eine Autoload-Konfigurationsdatei, die Importpfade auf Dateien abbildet.
Sie können den Autoloader von Composer optimieren, indem Sie das Flag --optimize-autoloader wie folgt übergeben:
composer install --optimize-autoloader --no-dev
Laravel-spezifische Optimierungen
Die Anwendung, die ich optimiert habe, wurde mit Laravel erstellt, das eine Reihe von Tools bietet, mit denen die Leistung der API verbessert werden kann. Hier sehen Sie, was ich zusätzlich zu den anderen Optimierungen getan habe, um die Antwortzeiten unter 100 ms zu bringen.
-
Ich habe die in Laravel integrierten Caching-Funktionen während der Builds genutzt, um die Startzeiten zu verkürzen. Diese Änderungen haben keine Nachteile, außer dass Sie keine Closure-definierten Routen verwenden können (sie können nicht gecached werden). Sie können Ansichten, Ereignisse und Routen mit diesen Befehlen zwischenspeichern:
php artisan view:cache php artisan event:cache php artisan route:cacheVermeiden Sie die Ausführung von
php artisan config:cache, da Laravel Umgebungsvariablen ignoriert, wenn Sie die Konfiguration zwischenspeichern. -
Die Verwendung von Laravel API-Ressourcen verbessert die Antwortzeiten Ihrer Anwendung weiter. Dies hat sich als viel schneller erwiesen, als wenn das Framework einzelne Objekte und Sammlungen automatisch in JSON konvertiert.
Zusammenfassung
In diesem Blog habe ich mit Ihnen geteilt, was ich bei der Optimierung der Leistung einer PHP-basierten API auf Cloud Run gelernt habe. Alle Optimierungen zusammen haben dazu beigetragen, die Antwortzeiten auf ein Zehntel des ursprünglichen Ergebnisses zu reduzieren. Ich denke, dass die größte Wirkung durch die Anpassung der Gleichzeitigkeit und der PHP-FPM-Worker erzielt wurde (wenn Sie es eilig haben, tun Sie nur dies). Die Beobachtung der Anwendungsmetriken war während der gesamten Leistungstestphase von grundlegender Bedeutung, ebenso wie die Prüfung der Cloud Run-Protokolle nach jeder Änderung.
Wenn Ihre Anwendung nach diesen Änderungen immer noch eine schlechte Leistung aufweist, können Sie weitere Optimierungen vornehmen, um die Antwortzeiten zu verbessern, auf die ich hier nicht eingegangen bin.
- Erhöhen Sie bei Bedarf die PHP-Speichergrenzen
- Prüfen Sie MySQL auf langsame Abfragen (oft aufgrund fehlender Indizes)
- Zwischenspeichern der Antworten mit einem CDN
- Migrieren Sie auf PHP 8.0 (bis zu 3x schneller)
Möchten Sie mehr über Google Cloud Run erfahren? Schauen Sie sich dieses Buch von unserem Mitarbeiter Wietse Venema an.
Credits: Kopfzeilenbild von Serey Kim auf Unsplash
Verfasst von
Luca Cavallin
Luca is a Software Engineer and Trainer with full-stack experience ranging from distributed systems to cross-platform apps. He is currently interested in building modern, serverless solutions on Google Cloud using Golang, Rust and React and leveraging SRE and Agile practices. Luca holds 3 Google Cloud certifications, he is part of the Google Developers Experts community and he is the co-organizer of the Google Cloud User Group that Binx.io holds with Google.
Unsere Ideen
Weitere Blogs
Contact



