Ambiente di esecuzione di Cloud Functions

Le funzioni Cloud Run vengono eseguite in un ambiente serverless completamente gestito in cui Google si occupa dell'infrastruttura, dei sistemi operativi e degli ambienti di runtime. Ogni funzione viene eseguita nel proprio contesto di esecuzione sicuro e isolato, offre scalabilità automatica e ha un ciclo di vita indipendente da altre funzioni.

Runtime

Cloud Run Functions supporta più runtime di linguaggi. Ognuno contiene un set standard di pacchetti di sistema, oltre agli strumenti e alle librerie necessari per il linguaggio specifico. Se esegui il deployment delle funzioni dalla riga di comando o tramite Terraform, dovrai conoscere il valore dell'ID runtime.

Gli aggiornamenti di sicurezza e manutenzione vengono resi disponibili per tutti gli ambienti di esecuzione delle versioni 1ª gen. e 2ª gen. Questi aggiornamenti vengono applicati automaticamente o manualmente, a seconda dell'ambiente e del modo in cui è stato configurato. Per saperne di più sugli aggiornamenti degli ambienti di esecuzione, consulta Proteggi la funzione Cloud Run.

Node.js

Runtime Generazione Ambiente ID runtime Immagine runtime
Node.js 24
(anteprima)
2ª gen. Ubuntu 24.04 nodejs24 us-central1-docker.pkg.dev/serverless-runtimes/google-24-full/runtimes/nodejs24
Node.js 22 1ª gen., 2ª gen. Ubuntu 22.04 nodejs22 us-central1-docker.pkg.dev/serverless-runtimes/google-22-full/runtimes/nodejs22
Node.js 20 1ª gen., 2ª gen. Ubuntu 22.04 nodejs20 us-central1-docker.pkg.dev/serverless-runtimes/google-22-full/runtimes/nodejs20
Node.js 18 1ª gen., 2ª gen. Ubuntu 22.04 nodejs18 us-central1-docker.pkg.dev/serverless-runtimes/google-22-full/runtimes/nodejs18
Node.js 16 1ª gen., 2ª gen. Ubuntu 18.04 nodejs16 us-central1-docker.pkg.dev/serverless-runtimes/google-18-full/runtimes/nodejs16
Node.js 14 1ª gen., 2ª gen. Ubuntu 18.04 nodejs14 us-central1-docker.pkg.dev/serverless-runtimes/google-18-full/runtimes/nodejs14
Node.js 12 1ª gen., 2ª gen. Ubuntu 18.04 nodejs12 us-central1-docker.pkg.dev/serverless-runtimes/google-18-full/runtimes/nodejs12
Node.js 10 1ª gen., 2ª gen. Ubuntu 18.04 nodejs10 us-central1-docker.pkg.dev/serverless-runtimes/google-18-full/runtimes/nodejs10
Node.js 8 1ª gen., 2ª gen. Ubuntu 18.04 nodejs8 Dismesso
Node.js 6 1ª gen., 2ª gen. Ubuntu 18.04 nodejs6 Dismesso

Python

Runtime Generazione Ambiente ID runtime Immagine runtime
Python 3.13 2ª gen. Ubuntu 22.04 python313 us-central1-docker.pkg.dev/serverless-runtimes/google-22-full/runtimes/python313
Python 3.12 1ª gen., 2ª gen. Ubuntu 22.04 python312 us-central1-docker.pkg.dev/serverless-runtimes/google-22-full/runtimes/python312
Python 3.11 1ª gen., 2ª gen. Ubuntu 22.04 python311 us-central1-docker.pkg.dev/serverless-runtimes/google-22-full/runtimes/python311
Python 3.10 1ª gen., 2ª gen. Ubuntu 22.04 python310 us-central1-docker.pkg.dev/serverless-runtimes/google-22-full/runtimes/python310
Python 3.9 1ª gen., 2ª gen. Ubuntu 18.04 python39 us-central1-docker.pkg.dev/serverless-runtimes/google-18-full/runtimes/python39
Python 3.8 1ª gen., 2ª gen. Ubuntu 18.04 python38 us-central1-docker.pkg.dev/serverless-runtimes/google-18-full/runtimes/python38
Python 3.7 1ª gen. Ubuntu 18.04 python37 us-central1-docker.pkg.dev/serverless-runtimes/google-18-full/runtimes/python37

Go

Runtime Generazione Ambiente ID runtime Immagine runtime
Go 1.25 2ª gen. Ubuntu 22.04 go125 us-central1-docker.pkg.dev/serverless-runtimes/google-22-full/runtimes/go125
Go 1.24 2ª gen. Ubuntu 22.04 go124 us-central1-docker.pkg.dev/serverless-runtimes/google-22-full/runtimes/go124
Go 1.23 2ª gen. Ubuntu 22.04 go123 us-central1-docker.pkg.dev/serverless-runtimes/google-22-full/runtimes/go123
Go 1.22 2ª gen. Ubuntu 22.04 go122 us-central1-docker.pkg.dev/serverless-runtimes/google-22-full/runtimes/go122
Go 1.21 1ª gen., 2ª gen. Ubuntu 22.04 go121 us-central1-docker.pkg.dev/serverless-runtimes/google-22-full/runtimes/go121
Go 1.20 1ª gen., 2ª gen. Ubuntu 22.04 go120 us-central1-docker.pkg.dev/serverless-runtimes/google-22-full/runtimes/go120
Go 1.19 1ª gen., 2ª gen. Ubuntu 22.04 go119 us-central1-docker.pkg.dev/serverless-runtimes/google-22-full/runtimes/go119
Go 1.18 1ª gen., 2ª gen. Ubuntu 22.04 go118 us-central1-docker.pkg.dev/serverless-runtimes/google-22-full/runtimes/go118
Go 1.16 1ª gen., 2ª gen. Ubuntu 18.04 go116 us-central1-docker.pkg.dev/serverless-runtimes/google-18-full/runtimes/go116
Go 1.13 1ª gen., 2ª gen. Ubuntu 18.04 go113 us-central1-docker.pkg.dev/serverless-runtimes/google-18-full/runtimes/go113
Go 1.11 1ª gen., 2ª gen. Ubuntu 18.04 go111 Dismesso

Java

Runtime Generazione Ambiente ID runtime Immagine runtime
Java 25
(Anteprima)
2ª gen. Ubuntu 24.04 java25 us-central1-docker.pkg.dev/serverless-runtimes/google-24-full/runtimes/java25
Java 21 2ª gen. Ubuntu 22.04 java21 us-central1-docker.pkg.dev/serverless-runtimes/google-22-full/runtimes/java21
Java 17 1ª gen., 2ª gen. Ubuntu 22.04 java17 us-central1-docker.pkg.dev/serverless-runtimes/google-22-full/runtimes/java17
Java 11 1ª gen., 2ª gen. Ubuntu 18.04 java11 us-central1-docker.pkg.dev/serverless-runtimes/google-18-full/runtimes/java11

Ruby

Runtime Generazione Ambiente ID runtime Immagine runtime
Ruby 3.4 2ª gen. Ubuntu 22.04 ruby34 us-central1-docker.pkg.dev/serverless-runtimes/google-22-full/runtimes/ruby34
Ruby 3.3 1ª gen., 2ª gen. Ubuntu 22.04 ruby33 us-central1-docker.pkg.dev/serverless-runtimes/google-22-full/runtimes/ruby33
Ruby 3.2 1ª gen., 2ª gen. Ubuntu 22.04 ruby32 us-central1-docker.pkg.dev/serverless-runtimes/google-22-full/runtimes/ruby32
Ruby 3.0 1ª gen., 2ª gen. Ubuntu 18.04 ruby30 us-central1-docker.pkg.dev/serverless-runtimes/google-18-full/runtimes/ruby30
Ruby 2.7 1ª gen., 2ª gen. Ubuntu 18.04 ruby27 us-central1-docker.pkg.dev/serverless-runtimes/google-18-full/runtimes/ruby27
Ruby 2.6 1ª gen., 2ª gen. Ubuntu 18.04 ruby26 us-central1-docker.pkg.dev/serverless-runtimes/google-18-full/runtimes/ruby26

PHP

Runtime Ambiente Generazione ID runtime Immagine runtime
PHP 8.4 2ª gen. Ubuntu 22.04 php84 us-central1-docker.pkg.dev/serverless-runtimes/google-22-full/runtimes/php84
PHP 8.3 2ª gen. Ubuntu 22.04 php83 us-central1-docker.pkg.dev/serverless-runtimes/google-22-full/runtimes/php83
PHP 8.2 1ª gen., 2ª gen. Ubuntu 22.04 php82 us-central1-docker.pkg.dev/serverless-runtimes/google-22-full/runtimes/php82
PHP 8.1 1ª gen., 2ª gen. Ubuntu 18.04 php81 us-central1-docker.pkg.dev/serverless-runtimes/google-18-full/runtimes/php81
PHP 7.4 1ª gen., 2ª gen. Ubuntu 18.04 php74 us-central1-docker.pkg.dev/serverless-runtimes/google-18-full/runtimes/php74

.NET Core

Runtime Generazione Ambiente ID runtime Immagine runtime
.NET Core 8 2ª gen. Ubuntu 22.04 dotnet8 us-central1-docker.pkg.dev/serverless-runtimes/google-22-full/runtimes/dotnet8
.NET Core 6 1ª gen., 2ª gen. Ubuntu 22.04 dotnet6 us-central1-docker.pkg.dev/serverless-runtimes/google-22-full/runtimes/dotnet6
.NET Core 3 1ª gen., 2ª gen. Ubuntu 18.04 dotnet3 us-central1-docker.pkg.dev/serverless-runtimes/google-18-full/runtimes/dotnet3

Comportamento della scalabilità automatica

Cloud Run Functions implementa il paradigma serverless, in base al quale esegui il tuo codice senza preoccuparti dell'infrastruttura sottostante, come server o macchine virtuali. Una volta eseguito il deployment delle funzioni, queste vengono gestite e scalate automaticamente.

Cloud Run Functions gestisce le richieste in entrata assegnandole a istanze della funzione. A seconda del volume di richieste e del numero di istanze di funzioni esistenti, Cloud Run Functions può assegnare una richiesta a un'istanza esistente o crearne una nuova.

Nei casi in cui il volume delle richieste in entrata supera il numero di istanze esistenti, Cloud Run Functions potrebbe avviare diverse nuove istanze per gestire le richieste. Questo comportamento di scalabilità automatica consente a Cloud Run Functions di gestire molte richieste in parallelo, ognuna mediante un'istanza diversa della funzione.

In alcuni casi, la scalabilità illimitata potrebbe non essere auspicabile. Per risolvere il problema, Cloud Run Functions consente di configurare un numero massimo di istanze che possono coesistere in un determinato periodo di tempo per una particolare funzione.

Condizione stateless

Per abilitare la gestione e la scalabilità automatiche delle funzioni, queste devono essere stateless, che significa che la chiamata di una funzione non deve basarsi sullo stato in memoria impostato da una chiamata precedente. Le chiamate potrebbero essere gestite da istanze di funzioni diverse, che non condividono variabili globali, memoria, file system o altro stato.

Se devi condividere lo stato tra le chiamate di una funzione, la funzione deve utilizzare un servizio come Memorystore, Datastore, Firestore o Cloud Storage per rendere persistenti i dati. Per saperne di più sulle opzioni di database e archiviazione forniti da Google Cloud, consulta DatabaseGoogle Cloud e Prodotti di archiviazione diGoogle Cloud .

Concorrenza

Cloud Run Functions (2ª gen.)

Cloud Run Functions (2ª gen.) supporta la gestione di più richieste in parallelo su una singola istanza di funzione. Ciò può essere utile per evitare avvii a freddo, poiché un'istanza già preparata può elaborare più richieste contemporaneamente, riducendo così la latenza complessiva. Per maggiori dettagli, consulta Concorrenza.

Cloud Run Functions (1ª gen.)

In Cloud Run Functions (1ª gen.), ogni istanza di una funzione gestisce una sola richiesta in parallelo alla volta. Ciò significa che mentre il codice elabora una richiesta, non c'è alcuna possibilità che una seconda richiesta venga indirizzata alla stessa istanza. Pertanto, la richiesta originale può utilizzare l'intera quantità di risorse (memoria e CPU) allocate.

Poiché le richieste in parallelo in Cloud Run Functions (1ª gen.) vengono elaborate da diverse istanze di funzioni, non condividono variabili o memoria locale. Per saperne di più, consulta Condizione stateless e Durata dell'istanza di funzione.

Avvii a freddo

Una nuova istanza di funzione viene avviata in due casi:

  • Quando esegui il deployment della funzione.

  • Quando viene creata automaticamente una nuova istanza di funzione di cui fare lo scale up in base al carico o, occasionalmente, per sostituire un'istanza esistente.

L'avvio di una nuova istanza di funzione comporta il caricamento del runtime e del codice. Le richieste che includono l'avvio dell'istanza di funzione, o avvii a freddo, possono essere più lente delle richieste indirizzate alle istanze di funzione esistenti. Tuttavia, se la funzione riceve un carico costante, il numero di avvii a freddo è in genere trascurabile, a meno che la funzione non si arresti in modo anomalo di frequente richiedendo il riavvio dell'ambiente della funzione.

Se il codice della funzione genera un'eccezione non rilevata o causa un arresto anomalo del processo corrente, l'istanza della funzione potrebbe essere riavviata. Questo può a sua volta comportare più avvii a freddo, con conseguente aumento della latenza, pertanto ti consigliamo di rilevare le eccezioni ed evitare in altro modo che il processo corrente venga terminato.

Se la tua funzione è sensibile alla latenza, valuta la possibilità di impostare un numero minimo di istanze per evitare gli avvii a freddo.

Durata dell'istanza di funzione

Le istanze di funzione sono in genere resilienti e riutilizzate dalle chiamate di funzioni successive, a meno che non venga fatto lo scale down del numero di istanze a causa della mancanza di traffico continuo o di un arresto anomalo della funzione. Ciò significa che quando termina l'esecuzione di una funzione, un'altra chiamata di funzione può essere gestita dalla stessa istanza di funzione.

Ambito della funzione e ambito globale

Una singola chiamata di funzione comporta l'esecuzione solo del corpo della funzione dichiarata come entry point. L'ambito globale del codice sorgente della funzione viene eseguito solo sugli avvii a freddo e non sulle istanze che sono già state inizializzate.

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

Puoi utilizzare le variabili globali per ottimizzare le prestazioni, ma non devi fare affidamento sullo stato impostato nell'ambito globale dalle chiamate di funzioni precedenti. Per saperne di più, consulta Condizione stateless.

Puoi presupporre che, per ogni istanza di funzione, l'ambito globale sia stato eseguito esattamente una volta prima della chiamata del codice della funzione. Non devi però fare affidamento sul numero totale o sulla tempistica delle esecuzioni dell'ambito globale, in quanto potrebbero variare a seconda dell'attività di scalabilità automatica.

Sequenza temporale di esecuzione della funzione

Una funzione ha accesso alle relative risorse allocate (memoria e CPU) solo per la durata dell'esecuzione della funzione. L'esecuzione di codice al di fuori del periodo di esecuzione non è garantita e può essere interrotta in qualsiasi momento. Pertanto, devi sempre segnalare correttamente il termine dell'esecuzione della funzione ed evitare di eseguire qualsiasi codice oltre questo termine. Per indicazioni, consulta Funzioni HTTP, Funzioni in background e Funzioni CloudEvent.

L'esecuzione della funzione è soggetta anche alla durata del timeout della funzione stessa. Per saperne di più, consulta Timeout della funzione.

Quando inizializzi l'applicazione, tieni conto della sequenza temporale di esecuzione. Durante l'inizializzazione non devono essere create attività in background nell'ambito globale, in quanto verrebbero eseguite al di fuori della durata di una richiesta.

Garanzie di esecuzione

Le funzioni vengono in genere richiamate una volta per ogni evento in entrata. Tuttavia, Cloud Run Functions non garantisce una singola chiamata in tutti i casi, a causa delle differenze negli scenari di errore.

Il numero massimo o minimo di volte in cui la funzione può essere richiamata per un singolo evento dipende dal tipo di funzione:

  • Le funzioni HTTP vengono richiamate al massimo una volta. Ciò è dovuto alla natura sincrona delle chiamate HTTP e significa che qualsiasi errore che si verifica durante la chiamata della funzione verrà restituito senza ulteriori tentativi. Il chiamante di una funzione HTTP dovrebbe gestire gli errori e riprovare se necessario.

  • Le funzioni basate su eventi vengono richiamate almeno una volta. Ciò è dovuto alla natura asincrona degli eventi, in cui non esiste un chiamante che attende la risposta. In rari casi, il sistema potrebbe richiamare una funzione basata su eventi più di una volta per garantire il recapito dell'evento. Se la chiamata di una funzione basata su eventi non riesce e restituisce un errore, la funzione non viene richiamata di nuovo a meno che non siano abilitati i nuovi tentativi in caso di errore per quella funzione.

Per assicurarti che la funzione si comporti correttamente nei tentativi di esecuzione ripetuti, devi renderla idempotente implementandola in modo che i risultati desiderati (e gli effetti collaterali) vengano prodotti anche se un evento viene inviato più volte. Nel caso delle funzioni HTTP, questo comporta anche la restituzione del valore desiderato anche se il chiamante riprova a chiamare l'endpoint della funzione HTTP. Per saperne di più su come rendere idempotente la tua funzione, consulta Nuovo tentativo per le funzioni basate su eventi.

Memoria e file system

A ogni funzione viene allocata una determinata quantità di memoria per il suo utilizzo. Puoi configurare la quantità di memoria al momento del deployment. Per saperne di più, consulta Configura la memoria.

L'ambiente di esecuzione della funzione include un file system in memoria che contiene le directory e i file di origine di cui è stato eseguito il deployment con la funzione (consulta Strutturazione del codice sorgente). La directory contenente i file di origine è di sola lettura, ma il resto del file system è scrivibile (ad eccezione dei file utilizzati dal sistema operativo). L'utilizzo del file system viene conteggiato ai fini della memoria utilizzata di una funzione.

La funzione può interagire con il file system utilizzando i metodi standard di ogni linguaggio di programmazione.

Rete

La tua funzione può accedere a internet pubblico utilizzando i metodi standard di ogni linguaggio di programmazione, tramite librerie integrate offerte dal runtime o librerie di terze parti incluse come dipendenze.

Prova a riutilizzare le connessioni di rete tra le chiamate di funzioni. Tieni però presente che una connessione che rimane inutilizzata per 10 minuti potrebbe venire chiusa dal sistema e ulteriori tentativi di utilizzare una connessione chiusa restituiranno un errore di ripristino della connessione. Il codice deve utilizzare una libreria che gestisca bene le connessioni chiuse oppure gestirle in modo esplicito se utilizza costrutti di networking di basso livello.

Isolamento delle funzioni

Ogni funzione di cui è stato eseguito il deployment è isolata da tutte le altre funzioni, anche da quelle di cui è stato eseguito il deployment dallo stesso file di origine. In particolare, non condividono memoria, variabili globali, file system o altro stato.

Per condividere i dati tra le funzioni di cui è stato eseguito il deployment, puoi utilizzare servizi come Memorystore, Datastore, Firestore o Cloud Storage. In alternativa, puoi richiamare una funzione da un'altra utilizzando i trigger appropriati e passando i dati necessari. Ad esempio, puoi inviare una richiesta HTTP all'endpoint di una funzione HTTP o pubblicare un messaggio in un argomento Pub/Sub per attivare una funzione Pub/Sub.