Ausführungsumgebung von Cloud Run Functions

Cloud Run Functions-Funktionen werden in einer vollständig verwalteten, serverlosen Umgebung ausgeführt, in der Google sich um die Verwaltung der Infrastruktur, Betriebssysteme und Laufzeitumgebungen kümmert. Jede Cloud Functions-Funktion wird in ihrem eigenen isolierten, sicheren Ausführungskontext bereitgestellt und automatisch skaliert. Ihr Lebenszyklus ist von dem anderer Funktionen unabhängig.

Laufzeiten

Cloud Run Functions unterstützt mehrere Sprachlaufzeiten. Jede enthält eine Standardreihe von Systempaketen sowie die Tools und Bibliotheken, die für diese Sprache benötigt werden. Sie benötigen den Laufzeit-ID-Wert, wenn Sie Funktionen über die Befehlszeile oder über Terraform bereitstellen.

Sicherheits- und Wartungsupdates werden für alle Ausführungsumgebungen von Cloud Run Functions und Cloud Run Functions der 1. Generation bereitgestellt. Diese Updates werden automatisch oder manuell angewendet, je nach Umgebung und Ihrer Konfiguration. Weitere Informationen zu Updates der Ausführungsumgebung finden Sie unter Cloud Run Functions-Funktionen schützen.

Laufzeit-Images werden in jeder Region gehostet, in der Artifact Registry verfügbar ist. Sie können den Pfad zum Laufzeit-Image anpassen, indem Sie den ersten Teil der URI durch die gewünschte Region ersetzen:

REGION-docker.pkg.dev/serverless-runtimes/STACK/runtimes/RUNTIME_ID

Ersetzen Sie:

  • REGION durch die gewünschte Region, z. B. us-central1
  • STACK mit dem bevorzugten Betriebssystemstack, z. B. google-22-full
  • RUNTIME_ID durch die von der Funktion verwendete Laufzeit-ID, z. B. python310

Beispiel: Das neueste Node.js 20-Basis-Image mit dem google-22-full-Stack, das in us-central1 gehostet wird, wird mit dieser URL referenziert: us-central1-docker.pkg.dev/serverless-runtimes/google-22-full/runtimes/nodejs22

Node.js

Laufzeit Generierung Laufzeit-ID Stacks Laufzeit-Basis-Image
Node.js 22 Funktionen ausführen nodejs22 google-22-full google-22-full/nodejs22
Node.js 20 1. Generation, Funktionen ausführen nodejs20 google-22-full google-22-full/nodejs20
Node.js 18 1. Generation, Funktionen ausführen nodejs18 google-22-full google-22-full/nodejs18
Node.js 16 1. Generation, Funktionen ausführen nodejs16 google-18-full google-18-full/nodjes16
Node.js 14 1. Generation, Funktionen ausführen nodejs14 google-18-full google-18-full/nodjes14
Node.js 12 1. Generation, Funktionen ausführen nodejs12 google-18-full google-18-full/nodjes14
Node.js 10 1. Generation, Funktionen ausführen nodejs10 google-18-full google-18-full/nodjes10
Node.js 8 1. Generation, Funktionen ausführen nodejs8 Außer Betrieb genommen Außer Betrieb genommen
Node.js 6 1. Generation, Funktionen ausführen nodejs6 Außer Betrieb genommen Außer Betrieb genommen

Python

Laufzeit Generierung Laufzeit-ID Stacks Laufzeit-Basis-Image
Python 3.12 1. Generation, Funktionen ausführen python312 google-22-full google-22-full/python312
Python 3.11 1. Generation, Funktionen ausführen python311 google-22-full google-22-full/python311
Python 3.10 1. Generation, Funktionen ausführen python310 google-22-full google-22-full/python310
Python 3.9 1. Generation, Funktionen ausführen python39 google-18-full google-18-full/python39
Python 3.8 1. Generation, Funktionen ausführen python38 google-18-full google-18-full/python38
Python 3.7 1. Generation, Funktionen ausführen python37 google-18-full google-18-full/python37

Go

Laufzeit Generierung Laufzeit-ID Stacks Laufzeit-Basis-Image
Go 1.23
(nur Vorabversion)
Funktionen ausführen go123 google-22-full google-22-full/go123
Go 1.22 Funktionen ausführen go122 google-22-full google-22-full/go122
Go 1.21 Funktionen ausführen go121 google-22-full google-22-full/go121
Go 1.20 Funktionen ausführen go120 google-22-full google-22-full/go120
Go 1.19 1. Generation, Funktionen ausführen go119 google-22-full google-22-full/go119
Go 1.18 1. Generation, Funktionen ausführen go118 google-22-full google-22-full/go120
Go 1.16 1. Generation, Funktionen ausführen go116 google-18-full google-18-full/go116
Go 1.13 1. Generation, Funktionen ausführen go113 google-18-full google-18-full/go113
Go 1.11 1. Generation, Funktionen ausführen go111 Außer Betrieb genommen Außer Betrieb genommen

Java

Laufzeit Generierung Laufzeit-ID Stacks Laufzeit-Basis-Image
Java 21 Funktionen ausführen java21 google-22-full google-22-full/java21
Java 17 1. Generation, Funktionen ausführen java17 google-22-full google-22-full/java17
Java 11 1. Generation, Funktionen ausführen java11 google-18 google-18/java11

Ruby

Laufzeit Generierung Laufzeit-ID Stacks Laufzeit-Basis-Image
Ruby 3.3 1. Generation, Funktionen ausführen ruby33 google-22-full google-22-full/ruby33
Ruby 3.2 1. Generation, Funktionen ausführen ruby32 google-22-full google-22-full/ruby32
Ruby 3.0 1. Generation, Funktionen ausführen ruby30 google-18-full google-18-full/ruby30
Ruby 2.7 1. Generation, Funktionen ausführen ruby27 google-18-full google-18-full/ruby27
Ruby 2.6 1. Generation, Funktionen ausführen ruby26 google-18-full google-18-full/ruby26

PHP

Laufzeit Generierung Laufzeit-ID Stacks Laufzeit-Basis-Image
PHP 8.3 Funktionen ausführen php83 google-22-full google-22-full/php83
PHP 8.2 1. Generation, Funktionen ausführen php82 google-22-full google-22-full/php82
PHP 8.1 1. Generation, Funktionen ausführen php81 google-18-full google-18-full/php81
PHP 7.4 1. Generation, Funktionen ausführen php74 google-18-full google-18-full/php74

.NET Core

Laufzeit Generierung Laufzeit-ID Stacks Laufzeit-Basis-Image
.NET Core 8 Funktionen ausführen dotnet8 google-22-full google-22-full/dotnet8
.NET Core 6 1. Generation, Funktionen ausführen dotnet6 google-22-full google-22-full/dotnet6
.NET Core 3 1. Generation, Funktionen ausführen dotnet3 google-18-full google-18-full/dotnet3

Verhalten von Autoscaling

Cloud Run Functions ist eine serverlose Umgebung. Sie müssen sich bei der Codeausführung also nicht um die darunterliegende Infrastruktur wie Server oder virtuelle Maschinen kümmern. Nach der Bereitstellung werden die Funktionen automatisch verwaltet und skaliert.

Cloud Run Functions verarbeitet eingehende Anfragen, indem diese den Instanzen Ihrer Funktion zugewiesen werden. Abhängig von der Anzahl der Anfragen sowie der Anzahl der vorhandenen Funktionsinstanzen kann Cloud Run Functions eine Anfrage einer vorhandenen Instanz zuweisen oder eine neue erstellen.

Wenn das Volumen der eingehenden Anfragen die Anzahl der vorhandenen Instanzen überschreitet, kann Cloud Run Functions mehrere neue Instanzen zur Verarbeitung von Anfragen starten. Dieses automatische Skalierungsverhalten ermöglicht es Cloud Run Functions, viele Anfragen parallel zu verarbeiten, wobei jede eine andere Instanz Ihrer Funktion verwendet.

In einigen Fällen kann eine unbegrenzte Skalierung unerwünscht sein. Zur Behebung dieses Problems können Sie in Cloud Run Functions eine maximale Anzahl von Instanzen konfigurieren, die zu einer bestimmten Zeit für eine bestimmte Funktion koexistieren können.

Zustandslosigkeit

Wenn Sie die automatische Verwaltung und Skalierung der Funktionen aktivieren möchten, müssen sie zustandslos sein. Ein Funktionsaufruf darf nicht auf dem Speicherzustand basieren, der durch einen vorherigen Aufruf festgelegt wurde. Aufrufe können von verschiedenen Funktionsinstanzen verarbeitet werden, die nicht die gleichen globalen Variablen, Speicher, Dateisysteme oder andere Zustände haben.

Wenn Sie den Status für Funktionsaufrufe freigeben müssen, sollte die Funktion einen Dienst wie Memorystore, Datastore, Firestore oder Cloud Storage verwenden, um Daten zu speichern. Weitere Informationen zu Datenbank- und Speicheroptionen von Google Cloud finden Sie unter Google Cloud-Datenbanken und Google Cloud-Speicherprodukte.

Gleichzeitigkeit

Cloud Run-Funktionen

Cloud Run-Funktionen unterstützen die Verarbeitung mehrerer gleichzeitiger Anfragen auf einer einzelnen Funktionsinstanz. Dies kann hilfreich sein, um Kaltstarts zu verhindern, da eine bereits vorbereitete Instanz mehrere Anfragen gleichzeitig verarbeiten kann, wodurch die Gesamtlatenz verringert wird. Weitere Informationen finden Sie unter Nebenläufigkeit.

Cloud Run Functions (1. Generation)

In Cloud Run Functions (1. Generation) wird von jeder Instanz einer Funktion jeweils nur eine gleichzeitige Anfrage verarbeitet. Das bedeutet, dass keine zweite Anfrage an dieselbe Instanz weitergeleitet werden kann, während Ihr Code eine Anfrage verarbeitet. Die ursprüngliche Anfrage kann also die gesamte von Ihnen zugewiesene Anzahl von Ressourcen (Arbeitsspeicher und CPU) nutzen.

Da gleichzeitige Anfragen in Cloud Run Functions (1. Generation) von verschiedenen Funktionsinstanzen verarbeitet werden, teilen diese keine Variablen oder lokalen Arbeitsspeicher. Weitere Informationen finden Sie unter Zustandslosigkeit und Lebensdauer von Funktionsinstanzen.

Kaltstarts

Eine neue Funktionsinstanz wird in zwei Fällen gestartet:

  • Wenn Sie die Funktion bereitstellen

  • Wenn die Funktion als Reaktion auf eine gestiegene Arbeitslast oder als Ersatz für eine andere Instanz automatisch erstellt wird.

Beim Starten einer neuen Funktionsinstanz werden die Laufzeit und der Code geladen. Anfragen, die den Start einer Funktionsinstanz (Kaltstart) enthalten, können langsamer sein als Anfragen, die an vorhandene Funktionsinstanzen weitergeleitet werden. Wenn Ihre Funktion eine konstante Workload verarbeitet, ist die Anzahl der Kaltstarts normalerweise vernachlässigbar, es sei denn, sie stürzt häufig ab und die Funktionsumgebung muss neu gestartet werden.

Wenn Ihr Funktionscode eine nicht abgefangene Ausnahme auslöst oder den aktuellen Prozess zum Abstürzen bringt, kann die Funktionsinstanz neu gestartet werden. Das kann zu Kaltstarts und damit einer höheren Latenz führen. Daher empfehlen wir, Ausnahmen abzufangen und andernfalls die Beendigung des aktuellen Prozesses zu vermeiden. Unter Fehler melden erfahren Sie, wie Sie Fehler in Cloud Run Functions verarbeiten und melden.

Wenn Ihre Funktion latenzempfindlich ist, sollten Sie eine Mindestzahl von Instanzen festlegen, um Kaltstarts zu vermeiden.

Lebensdauer einer Funktionsinstanz

Funktionsinstanzen sind in der Regel ausfallsicher und werden von nachfolgenden Funktionsaufrufen wiederverwendet, es sei denn, die Anzahl der Instanzen wird verkleinert, da der laufende Traffic fehlt oder die Funktion abstürzt. Das bedeutet, wenn eine Funktionsausführung endet, kann dieselbe Funktionsinstanz einen weiteren Funktionsaufruf verarbeiten.

Funktionsbereich oder globaler Bereich

Beim Aufrufen einer einzelnen Funktion wird nur der als Einstiegspunkt deklarierte Funktionsteil ausgeführt. Der globale Geltungsbereich des Funktionsquellcodes wird nur bei Kaltstarts und nicht bei Instanzen ausgeführt, die bereits initialisiert wurden.

Node.js

const functions = require('@google-cloud/functions-framework');

// TODO(developer): Define your own computations
const {lightComputation, heavyComputation} = require('./computations');

// Global (instance-wide) scope
// This computation runs once (at instance cold-start)
const instanceVar = heavyComputation();

/**
 * HTTP function that declares a variable.
 *
 * @param {Object} req request context.
 * @param {Object} res response context.
 */
functions.http('scopeDemo', (req, res) => {
  // Per-function scope
  // This computation runs every time this function is called
  const functionVar = lightComputation();

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

Python

import time

import functions_framework


# Placeholder
def heavy_computation():
    return time.time()


# Placeholder
def light_computation():
    return time.time()


# Global (instance-wide) scope
# This computation runs at instance cold-start
instance_var = heavy_computation()


@functions_framework.http
def scope_demo(request):
    """
    HTTP Cloud Function that declares a variable.
    Args:
        request (flask.Request): The request object.
        <http://flask.pocoo.org/docs/1.0/api/#flask.Request>
    Returns:
        The response text, or any set of values that can be turned into a
        Response object using `make_response`
        <http://flask.pocoo.org/docs/1.0/api/#flask.Flask.make_response>.
    """

    # Per-function scope
    # This computation runs every time this function is called
    function_var = light_computation()
    return f"Instance: {instance_var}; function: {function_var}"

Go


// h is in the global (instance-wide) scope.
var h string

// init runs during package initialization. So, this will only run during an
// an instance's cold start.
func init() {
	h = heavyComputation()
	functions.HTTP("ScopeDemo", ScopeDemo)
}

// ScopeDemo is an example of using globally and locally
// scoped variables in a function.
func ScopeDemo(w http.ResponseWriter, r *http.Request) {
	l := lightComputation()
	fmt.Fprintf(w, "Global: %q, Local: %q", h, l)
}

Java


import com.google.cloud.functions.HttpFunction;
import com.google.cloud.functions.HttpRequest;
import com.google.cloud.functions.HttpResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;

public class Scopes implements HttpFunction {
  // Global (instance-wide) scope
  // This computation runs at instance cold-start.
  // Warning: Class variables used in functions code must be thread-safe.
  private static final int INSTANCE_VAR = heavyComputation();

  @Override
  public void service(HttpRequest request, HttpResponse response)
      throws IOException {
    // Per-function scope
    // This computation runs every time this function is called
    int functionVar = lightComputation();

    var writer = new PrintWriter(response.getWriter());
    writer.printf("Instance: %s; function: %s", INSTANCE_VAR, functionVar);
  }

  private static int lightComputation() {
    int[] numbers = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    return Arrays.stream(numbers).sum();
  }

  private static int heavyComputation() {
    int[] numbers = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    return Arrays.stream(numbers).reduce((t, x) -> t * x).getAsInt();
  }
}

Ruby

# Global (instance-wide) scope.
# This block runs on cold start, before any function is invoked.
#
# Note: It is usually best to run global initialization in an on_startup block
# instead at the top level of the Ruby file. This is because top-level code
# could be executed to verify the function during deployment, whereas an
# on_startup block is run only when an actual function instance is starting up.
FunctionsFramework.on_startup do
  instance_data = perform_heavy_computation

  # To pass data into function invocations, the best practice is to set a
  # key-value pair using the Ruby Function Framework's built-in "set_global"
  # method. Functions can call the "global" method to retrieve the data by key.
  # (You can also use Ruby global variables or "toplevel" local variables, but
  # they can make it difficult to isolate global data for testing.)
  set_global :my_instance_data, instance_data
end

FunctionsFramework.http "tips_scopes" do |_request|
  # Per-function scope.
  # This method is called every time this function is called.
  invocation_data = perform_light_computation

  # Retrieve the data computed by the on_startup block.
  instance_data = global :my_instance_data

  "instance: #{instance_data}; function: #{invocation_data}"
end

Sie können globale Variablen als Leistungsoptimierung verwenden. Sie dürfen sich jedoch bei vorherigen Funktionsaufrufen nicht auf den im globalen Bereich festgelegten Status verlassen. Weitere Informationen finden Sie unter Zustandslosigkeit.

Sie können davon ausgehen, dass für jede Funktionsinstanz der globale Geltungsbereich genau einmal ausgeführt wurde, bevor Ihr Funktionscode aufgerufen wird. Sie dürfen jedoch nicht von der Gesamtzahl oder dem Zeitpunkt der Ausführungen im globalen Bereich abhängig sein, da diese je nach Autoscaling-Aktivität variieren können.

Zeitlicher Ablauf der Funktionsausführung

Eine Funktion hat nur für die Dauer der Funktionsausführung Zugriff auf die zugewiesenen Ressourcen (Speicher und CPU). Code, der außerhalb des Ausführungszeitraums ausgeführt wird, wird nicht garantiert ausgeführt und kann jederzeit angehalten werden. Daher sollten Sie das Ende der Ausführung der Funktion immer korrekt signalisieren und vermeiden, dass Code darüber hinaus ausgeführt wird. Weitere Informationen finden Sie unter HTTP-Funktionen, Hintergrundfunktionen und CloudEvent-Funktionen.

Die Funktionsausführung unterliegt auch der Zeitüberschreitung der Funktion. Weitere Informationen finden Sie unter Funktionszeitlimit.

Berücksichtigen Sie bei der Initialisierung Ihrer Anwendung den zeitlichen Ablauf der Ausführung. Hintergrundaufgaben sollten während der Initialisierung nicht im globalen Bereich erstellt werden, da sie außerhalb der Dauer einer Anfrage ausgeführt werden.

Ausführungsgarantien

Eine Funktion wird normalerweise einmal für jedes eingehende Ereignis aufgerufen. Cloud Run Functions kann den einmaligen Aufruf aufgrund von Unterschieden in den Fehlerszenarien aber nicht in allen Fällen garantieren.

Die maximale oder minimale Häufigkeit, mit der eine Funktion für ein einzelnes Ereignis aufgerufen werden kann, hängt von ihrem Typ ab:

  • HTTP-Funktionen werden höchstens einmal aufgerufen. Das liegt daran, dass HTTP-Aufrufe synchron erfolgen. Jeder Fehler, der während des Funktionsaufrufs auftritt, wird ohne einen erneuten Versuch zurückgegeben. Es wird erwartet, dass der Aufrufer der HTTP-Funktion die Fehler behandelt und bei Bedarf den Aufruf wiederholt.

  • Ereignisgesteuerte Funktionen werden mindestens einmal aufgerufen. Das liegt an der asynchronen Behandlung von Ereignissen, bei denen kein Aufrufer auf die Antwort wartet. In seltenen Fällen kann es vorkommen, dass das System eine ereignisgesteuerte Funktion mehr als einmal aufruft, um die Zustellung des Ereignisses sicherzustellen. Wenn ein ereignisbasierter Funktionsaufruf mit einem Fehler fehlschlägt, wird die Funktion nur dann wieder aufgerufen, wenn für diese Funktion Wiederholungsversuche bei Fehlern aktiviert wurden.

Damit sich die Funktion bei wiederholten Ausführungsversuchen korrekt verhält, sollten Sie sie idempotent machen, indem Sie sie so implementieren, dass die gewünschten Ergebnisse (und Nebeneffekte) auch dann erzeugt werden, wenn ein Ereignis mehrmals bereitgestellt wird. Für HTTP-Funktionen bedeutet das, dass der gewünschte Wert geliefert wird, selbst wenn der Aufrufer die Aufrufe an den HTTP-Funktionsendpunkt wiederholt. Weitere Informationen dazu, wie Sie Ihre Funktion idempotent machen, finden Sie unter Ereignisgesteuerte Funktionen wiederholen.

Speicher- und Dateisystem

Jeder Funktion ist eine bestimmte Menge an Arbeitsspeicher zugewiesen. Sie können die Speichermenge während der Bereitstellung konfigurieren. Weitere Informationen finden Sie unter Speicherlimits.

Die Funktionsausführungsumgebung enthält ein speicherinternes Dateisystem, das die mit Ihrer Funktion bereitgestellten Quelldateien und Verzeichnisse enthält (siehe Quellcode strukturieren). Das Verzeichnis mit den Quelldateien ist schreibgeschützt, der Rest des Dateisystems ist jedoch beschreibbar (außer für Dateien, die vom Betriebssystem verwendet werden). Die Verwendung des Dateisystems wird auf die Speichernutzung einer Funktion angerechnet.

Ihre Funktion kann mithilfe von Standardmethoden in jeder Programmiersprache mit dem Dateisystem interagieren.

Netzwerk

Die Funktion kann über Standardmethoden in jeder Programmiersprache auf das öffentliche Internet zugreifen, sei es über integrierte Bibliotheken, die von den Laufzeitbibliotheken oder Drittanbieterbibliotheken angeboten werden, die Sie als Abhängigkeiten hinzufügen.

Versuchen Sie, Netzwerkverbindungen in mehreren Funktionsaufrufen wiederzuverwenden, wie unter Netzwerke optimieren beschrieben. Eine Verbindung, die 10 Minuten lang nicht verwendet wurde, wird vom System möglicherweise geschlossen. Weitere Versuche, eine geschlossene Verbindung zu verwenden, führen zu einem Fehler "Verbindung zurückgesetzt". Ihr Code sollte daher entweder eine Bibliothek verwenden, die geschlossene Verbindungen verarbeiten kann, oder diese explizit behandeln, wenn Netzwerkkonstrukte auf niedriger Ebene verwendet werden.

Funktionsisolation

Jede bereitgestellte Funktion ist von allen anderen Funktionen isoliert, selbst wenn diese von derselben Quelldatei stammen. Sie teilen weder Arbeitsspeicher, globale Variablen, Dateisysteme noch andere Zustände.

Zur Freigabe von Daten für alle bereitgestellten Funktionen können Sie Dienste wie Memorystore, Datastore, Firestore oder Cloud Storage verwenden. Alternativ können Sie mit den entsprechenden Triggern eine Funktion aus einer anderen aufrufen und die erforderlichen Daten weitergeben. Führen Sie zum Beispiel eine HTTP-Anfrage an den Endpunkt einer HTTP-Funktion aus oder veröffentlichen Sie eine Nachricht an ein Pub- / Sub-Thema, um eine Pub/Sub-Funktion auszulösen.