In diesem Leitfaden werden Optimierungen für Cloud Run-Dienste beschrieben, die in der Programmiersprache Python geschrieben sind. Außerdem finden Sie hier Hintergrundinformationen, damit Sie die Vor- und Nachteile einiger Optimierungen nachvollziehen können. Die Informationen auf dieser Seite ergänzen die allgemeinen Optimierungstipps, die auch für Python gelten.
Viele der Best Practices und Optimierungen in dieser herkömmlichen webbasierten Python-Anwendung beziehen sich auf folgende Probleme:
- Verarbeiten gleichzeitiger Anfragen (sowohl thread-basierter als auch nicht blockierender E/A-Vorgänge)
- Reduzieren der Antwortlatenz durch Verbindungspooling und Stapelverarbeitung nicht kritischer Funktionen, wie z. B. das Senden von Traces und Messwerten an Hintergrundaufgaben.
Container-Image optimieren
Durch die Optimierung des Container-Images können Sie die Lade- und Startzeiten reduzieren. Sie können das Image so optimieren:
- Nur in den Container einfügen, was Ihre Anwendung zur Laufzeit benötigt
- WSGI-Server optimieren
Nur in den Container einfügen, was Ihre Anwendung zur Laufzeit benötigt
Überlegen Sie, welche Komponenten im Container enthalten sind und ob sie für die Ausführung des Dienstes erforderlich sind. Es gibt mehrere Möglichkeiten, das Container-Image zu minimieren:
- Kleineres Basis-Image verwenden
- Große Dateien aus dem Container heraus verschieben
Kleineres Basis-Image verwenden
Docker Hub bietet eine Reihe von offiziellen Python-Basis-Images, die Sie verwenden können, wenn Sie Python nicht aus der Quelle in Ihren Containern installieren möchten. Diese basieren auf dem Debian-Betriebssystem.
Wenn Sie das python
-Image von Docker Hub verwenden, sollten Sie die slim
-Version verwenden.
Diese Images sind kleiner, da sie nicht eine Reihe von Paketen enthalten, die zum Erstellen von Wheels verwendet werden, die für Ihre Anwendung vielleicht nicht erforderlich sind. Das Python-Image enthält beispielsweise den GNU-C-Compiler, den Präprozessor und Kerndienstprogramme.
Zum Ermitteln der zehn größten Pakete in einem Basis-Image können Sie den folgenden Befehl ausführen:
DOCKER_IMAGE=python # or python:slim
docker run --rm ${DOCKER_IMAGE} dpkg-query -Wf '${Installed-Size}\t${Package}\t${Description}\n' | sort -n | tail -n10 | column -t -s $'\t'
Da weniger dieser untergeordneten Pakete vorhanden sind, bieten die slim
-basierten Images auch weniger Angriffsfläche für potenzielle Sicherheitslücken. Beachten Sie, dass diese Images möglicherweise nicht die Elemente enthalten, die zur Erstellung von Wheels aus der Quelle erforderlich sind.
Sie können bestimmte Pakete wieder hinzufügen, indem Sie dem Dockerfile eine Zeile RUN apt install
hinzufügen. Weitere Informationen zur Verwendung vonSystempaketen in Cloud Run
Es sind auch Optionen für Container verfügbar, die nicht auf Debian basieren. Die Option python:alpine
kann zu einem wesentlich kleineren Container führen. Viele Python-Pakete haben jedoch möglicherweise keine vorkompilierten Wheels, die Alpine-basierte Systeme unterstützen. Die Unterstützung wird verbessert (siehe PEP-656), ist aber immer noch unterschiedlich. Sie können auch das distroless base image
verwenden, das keine Paketmanager, Shells oder sonstigen Programme enthält.
Große Dateien aus dem Container heraus verschieben
Große Dateien wie Medien-Assets müssen nicht im Basiscontainer enthalten sein.
Google Cloud bietet mehrere Hostingoptionen wie Cloud Storage zum Speichern dieser großen Elemente. Verschieben Sie große Assets in diese Dienste und verweisen Sie dann zur Laufzeit von der Anwendung aus darauf.
WSGI-Server optimieren
Python hat die Art und Weise, wie Anwendungen mit Webservern interagieren können, durch Implementierung des WSGI-Standards PEP-3333 standardisiert. Einer der gängigsten WSGI-Server ist gunicorn
, der in einem Großteil der Beispieldokumentation verwendet wird.
gunicorn optimieren
Fügen Sie dem Dockerfile
Folgendes hinzu CMD
, um den Aufruf von gunicorn
zu optimieren:
CMD exec gunicorn --bind :$PORT --workers 1 --threads 8 --timeout 0 main:app
Wenn Sie diese Einstellungen ändern möchten, passen Sie die Anzahl der Worker und Threads pro Anwendung an. Versuchen Sie beispielsweise, eine Anzahl von Workern zu verwenden, die den verfügbaren Kernen entspricht, vergewissern Sie sich, dass es eine Leistungsverbesserung gibt, und passen Sie dann die Anzahl der Threads an. Das Festlegen von zu vielen Workern oder Threads kann sich negativ auf die Kaltstartlatenz, den verbrauchten Arbeitsspeicher, die Anfragen pro Sekunde usw. auswirken.
Standardmäßig startet gunicorn
beim Starten Worker und wartet auf den angegebenen Port, noch bevor der Anwendungscode ausgewertet wird. In diesem Fall sollten Sie benutzerdefinierte Startprüfungen für Ihren Dienst einrichten, da die Standardstartprüfung von Cloud Run eine Containerinstanz sofort als fehlerfrei kennzeichnet, sobald sie $PORT
überwacht.
Wenn Sie dieses Verhalten ändern möchten, können Sie gunicorn
mit der Einstellung --preload
aufrufen, um Ihren Anwendungscode vor der Überwachung zu prüfen. Das kann helfen bei:
- Schweregrad der Laufzeitfehler bei der Bereitstellung ermitteln
- Speicherressourcen sparen
Sie sollten überlegen, was Ihre Anwendung vorab lädt, bevor Sie dies hinzufügen.
Andere WSGI-Server
Sie sind nicht auf die Verwendung von gunicorn
zum Ausführen von Python in Containern beschränkt.
Sie können einen beliebigen WSGI- oder ASGI-Webserver verwenden, solange der Container den HTTP-Port $PORT
gemäß dem Containerlaufzeitvertrag überwacht.
Gängige Alternativen sind uwsgi
, uvicorn
und waitress
.
Bei der folgenden Datei namens main.py
mit dem app
-Objekt würden die folgenden Aufrufe einen WSGI-Server starten:
# uwsgi: pip install pyuwsgi
uwsgi --http :$PORT -s /tmp/app.sock --manage-script-name --mount /app=main:app
# uvicorn: pip install uvicorn
uvicorn --port $PORT --host 0.0.0.0 main:app
# waitress: pip install waitress
waitress-serve --port $PORT main:app
Diese können entweder als CMD exec
-Zeile in einem Dockerfile
oder als web:
-Eintrag in Procfile
hinzugefügt werden, wenn Google Cloud Buildpacks verwendet wird.
Anwendungen optimieren
In Ihrem Cloud Run-Dienstcode können Sie auch die Startzeiten und die Arbeitsspeichernutzung optimieren.
Threads reduzieren
Sie können den Arbeitsspeicher optimieren, indem Sie die Anzahl der Threads reduzieren, indem Sie nicht blockierende reaktive Strategien verwenden und Hintergrundaktivitäten vermeiden. Vermeiden Sie außerdem das Schreiben in das Dateisystem, wie auf der Seite Allgemeine Tipps beschrieben.
Wenn Sie Hintergrundaktivitäten in Ihrem Cloud Run-Dienst unterstützen möchten, legen Sie die CPU des Cloud Run-Dienstes so fest, dass sie immer zugewiesen wird. Dadurch können Sie Hintergrundaktivitäten außerhalb von Anfragen ausführen und dennoch Zugriff auf die CPU haben.
Startaufgaben reduzieren
Webbasierte Python-Anwendungen können während des Startvorgangs viele Aufgaben ausführen, z. B. Daten vorab laden, Cache vorbereiten, Verbindungspools einrichten usw. Diese Aufgaben können, wenn sie nacheinander ausgeführt werden, langsam sein. Wenn sie jedoch parallel ausgeführt werden sollen, sollten Sie die Anzahl der CPU-Kerne erhöhen.
Cloud Run sendet derzeit eine echte Nutzeranfrage, um eine Kaltstartinstanz auszulösen. Bei Nutzern, bei denen eine Anfrage einer neu gestarteten Instanz zugewiesen wurde, kann es zu langen Verzögerungen kommen. Cloud Run verfügt derzeit über keine Bereitschaftsprüfung, um zu verhindern, dass Anfragen an nicht bereite Anwendungen gesendet werden.
Nächste Schritte
Weitere Tipps finden Sie unter