Catch up on highlights from Firebase at Google I/O 2023. Learn more

Tipps

Dieses Dokument beschreibt Best Practices für das Entwerfen, Implementieren, Testen und Bereitstellen von Cloud Functions.

Richtigkeit

In diesem Abschnitt werden allgemeine Best Practices für das Entwerfen und Implementieren von Cloud Functions beschrieben.

Schreiben Sie idempotente Funktionen

Ihre Funktionen sollten das gleiche Ergebnis liefern, auch wenn sie mehrmals aufgerufen werden. Auf diese Weise können Sie einen Aufruf wiederholen, wenn der vorherige Aufruf während Ihres Codes fehlschlägt. Weitere Informationen finden Sie unter Wiederholung ereignisgesteuerter Funktionen .

Starten Sie keine Hintergrundaktivitäten

Hintergrundaktivität ist alles, was passiert, nachdem Ihre Funktion beendet wurde. Ein Funktionsaufruf wird beendet, sobald die Funktion zurückkehrt oder anderweitig den Abschluss signalisiert, z. B. durch Aufrufen des callback in den ereignisgesteuerten Funktionen von Node.js. Jeglicher Code, der nach einer ordnungsgemäßen Beendigung ausgeführt wird, kann nicht auf die CPU zugreifen und macht keinen Fortschritt.

Darüber hinaus wird Ihre Hintergrundaktivität fortgesetzt, wenn ein nachfolgender Aufruf in derselben Umgebung ausgeführt wird, wodurch der neue Aufruf beeinträchtigt wird. Dies kann zu unerwartetem Verhalten und Fehlern führen, die schwer zu diagnostizieren sind. Der Zugriff auf das Netzwerk nach Beendigung einer Funktion führt in der Regel zum Zurücksetzen der Verbindungen (Fehlercode ECONNRESET ).

Hintergrundaktivitäten können oft in Protokollen einzelner Aufrufe erkannt werden, indem alles gefunden wird, was nach der Zeile protokolliert wird, die besagt, dass der Aufruf beendet wurde. Hintergrundaktivitäten können manchmal tiefer im Code vergraben sein, insbesondere wenn asynchrone Vorgänge wie Rückrufe oder Timer vorhanden sind. Überprüfen Sie Ihren Code, um sicherzustellen, dass alle asynchronen Vorgänge abgeschlossen sind, bevor Sie die Funktion beenden.

Temporäre Dateien immer löschen

Der lokale Plattenspeicher im temporären Verzeichnis ist ein In-Memory-Dateisystem. Dateien, die Sie schreiben, verbrauchen Speicherplatz, der Ihrer Funktion zur Verfügung steht, und bleiben manchmal zwischen Aufrufen bestehen. Wenn diese Dateien nicht explizit gelöscht werden, kann dies schließlich zu einem Speichermangel und einem anschließenden Kaltstart führen.

Sie können den von einer einzelnen Funktion verwendeten Arbeitsspeicher anzeigen, indem Sie sie in der Liste der Funktionen in der GCP Console auswählen und das Arbeitsspeichernutzungsdiagramm auswählen.

Versuchen Sie nicht, außerhalb des temporären Verzeichnisses zu schreiben, und stellen Sie sicher, dass Sie plattform-/betriebssystemunabhängige Methoden verwenden, um Dateipfade zu erstellen.

Sie können den Speicherbedarf bei der Verarbeitung größerer Dateien mithilfe von Pipelining reduzieren. Beispielsweise können Sie eine Datei in Cloud Storage verarbeiten, indem Sie einen Lesestream erstellen, ihn durch einen streambasierten Prozess leiten und den Ausgabestream direkt in Cloud Storage schreiben.

Werkzeug

Dieser Abschnitt enthält Richtlinien zur Verwendung von Tools zum Implementieren, Testen und Interagieren mit Cloud Functions.

Lokale Entwicklung

Die Funktionsbereitstellung nimmt etwas Zeit in Anspruch, daher ist es oft schneller, den Code Ihrer Funktion lokal zu testen.

Firebase-Entwickler können den Firebase CLI Cloud Functions-Emulator verwenden.

Verwenden Sie Sendgrid, um E-Mails zu senden

Cloud Functions lässt keine ausgehenden Verbindungen auf Port 25 zu, daher können Sie keine unsicheren Verbindungen zu einem SMTP-Server herstellen. Die empfohlene Methode zum Senden von E-Mails ist die Verwendung von SendGrid . Weitere Optionen zum Senden von E-Mails finden Sie im Tutorial zum Senden von E-Mails von einer Instanz für Google Compute Engine.

Leistung

In diesem Abschnitt werden Best Practices zur Leistungsoptimierung beschrieben.

Verwenden Sie Abhängigkeiten mit Bedacht

Da Funktionen zustandslos sind, wird die Ausführungsumgebung oft von Grund auf neu initialisiert (während eines sogenannten Kaltstarts ). Bei einem Kaltstart wird der globale Kontext der Funktion ausgewertet.

Wenn Ihre Funktionen Module importieren, kann die Ladezeit für diese Module die Aufruflatenz während eines Kaltstarts erhöhen. Sie können diese Latenz sowie die zum Bereitstellen Ihrer Funktion erforderliche Zeit reduzieren, indem Sie Abhängigkeiten korrekt laden und keine Abhängigkeiten laden, die Ihre Funktion nicht verwendet.

Verwenden Sie globale Variablen, um Objekte in zukünftigen Aufrufen wiederzuverwenden

Es gibt keine Garantie dafür, dass der Zustand einer Cloud-Funktion für zukünftige Aufrufe erhalten bleibt. Cloud Functions recycelt jedoch häufig die Ausführungsumgebung eines vorherigen Aufrufs. Wenn Sie eine Variable im globalen Geltungsbereich deklarieren, kann ihr Wert in nachfolgenden Aufrufen wiederverwendet werden, ohne neu berechnet werden zu müssen.

Auf diese Weise können Sie Objekte zwischenspeichern, deren Neuerstellung bei jedem Funktionsaufruf teuer sein kann. Das Verschieben solcher Objekte aus dem Funktionshauptteil in den globalen Gültigkeitsbereich kann zu erheblichen Leistungsverbesserungen führen. Das folgende Beispiel erstellt ein schweres Objekt nur einmal pro Funktionsinstanz und teilt es mit allen Funktionsaufrufen, die die angegebene Instanz erreichen:

console.log('Global scope');
const perInstance = heavyComputation();
const functions = require('firebase-functions');

exports.function = functions.https.onRequest((req, res) => {
    console.log('Function invocation');
    const perFunction = lightweightComputation();

    res.send(`Per instance: ${perInstance}, per function: ${perFunction}`);
});

Es ist besonders wichtig, Netzwerkverbindungen, Bibliotheksreferenzen und API-Client-Objekte im globalen Bereich zwischenzuspeichern. Beispiele finden Sie unter Optimieren des Netzwerks .

Verzögerte Initialisierung globaler Variablen

Wenn Sie Variablen im globalen Bereich initialisieren, wird der Initialisierungscode immer über einen Kaltstartaufruf ausgeführt, wodurch sich die Latenz Ihrer Funktion erhöht. In bestimmten Fällen führt dies zu intermittierenden Timeouts bei den aufgerufenen Diensten, wenn sie in einem try / catch Block nicht angemessen behandelt werden. Wenn einige Objekte nicht in allen Codepfaden verwendet werden, sollten Sie sie träge bei Bedarf initialisieren:

const functions = require('firebase-functions');
let myCostlyVariable;

exports.function = functions.https.onRequest((req, res) => {
    doUsualWork();
    if(unlikelyCondition()){
        myCostlyVariable = myCostlyVariable || buildCostlyVariable();
    }
    res.status(200).send('OK');
});

Dies ist besonders wichtig, wenn Sie mehrere Funktionen in einer einzigen Datei definieren und verschiedene Funktionen verschiedene Variablen verwenden. Wenn Sie keine verzögerte Initialisierung verwenden, verschwenden Sie möglicherweise Ressourcen für Variablen, die initialisiert, aber nie verwendet werden.

Reduzieren Sie Kaltstarts, indem Sie eine Mindestanzahl von Instanzen festlegen

Standardmäßig skaliert Cloud Functions die Anzahl der Instanzen basierend auf der Anzahl der eingehenden Anfragen. Sie können dieses Standardverhalten ändern, indem Sie eine Mindestanzahl von Instanzen festlegen, die Cloud Functions bereit halten muss, um Anfragen zu bedienen. Das Festlegen einer Mindestanzahl von Instanzen reduziert Kaltstarts Ihrer Anwendung. Wir empfehlen, eine Mindestanzahl von Instanzen festzulegen, wenn Ihre Anwendung latenzempfindlich ist.

Weitere Informationen zu diesen Laufzeitoptionen finden Sie unter Steuerung des Skalierungsverhaltens .

Zusätzliche Ressourcen

Erfahren Sie mehr über die Optimierung der Leistung im Video "Google Cloud Performance Atlas" Cloud Functions Cold Boot Time .