Ambiente di esecuzione di Cloud Functions
Cloud Functions viene eseguito in un ambiente serverless completamente gestito in cui Google gestisce completamente l'infrastruttura, i sistemi operativi e gli ambienti di runtime. Ogni funzione Cloud Functions viene eseguita in un proprio contesto di esecuzione sicuro isolato, scala automaticamente e ha un ciclo di vita indipendente da altre funzioni.
Runtime
Cloud Functions supporta runtime in più lingue. Se hai eseguito il deployment delle funzioni dalla riga di comando o tramite Terraform, devi utilizzare il valore ID runtime.
Runtime | Immagine di base | ID runtime |
---|---|---|
Node.js 16 (consigliato) | Ubuntu 18.04 | Nodejs16 |
Node.js 14 | Ubuntu 18.04 | Nodejs14 |
Node.js 12 | Ubuntu 18.04 | Nodejs12 |
Node.js 10 | Ubuntu 18.04 | Nodejs10 |
Node.js 8 (deprecato) | Ubuntu 18.04 | Nodejs8 |
Node.js 6 (ritirato) | Debian 8 | Nodejs6 |
Python 3.9 (consigliato) | Ubuntu 18.04 | Python39 |
Python 3.8 | Ubuntu 18.04 | Python38 |
Python 3.7 | Ubuntu 18.04 | Python37 |
Go 1.16 (consigliato) | Ubuntu 18.04 | go116 |
Go 1.13 | Ubuntu 18.04 | go113 |
Go 1.11 | Ubuntu 18.04 | go111 |
Java 17 (anteprima) | Ubuntu 18.04 | java17 |
Java 11 (consigliato) | Ubuntu 18.04 | Java11 |
.NET Core 3.1 (consigliato) | Ubuntu 18.04 | dotnet3 |
Ruby 3.0 (anteprima) | Ubuntu 18.04 | rubino30 |
Ruby 2.7 (consigliato) | Ubuntu 18.04 | rubino27 |
Ruby 2.6 | Ubuntu 18.04 | rubino26 |
PHP 7.4 (consigliato) | Ubuntu 18.04 | php74 |
Gli aggiornamenti ai runtime vengono generalmente eseguiti automaticamente, se non diversamente specificato. Tutti i runtime ricevono aggiornamenti automatici per la versione della lingua non appena vengono resi disponibili alla community della lingua. Analogamente, Cloud Functions potrebbe applicare aggiornamenti ad altri aspetti dell'ambiente di esecuzione, ad esempio il sistema operativo o i pacchetti inclusi. Questi aggiornamenti aiutano a mantenere sicura la tua funzione.
Funzioni stateless
Cloud Functions implementa il paradigma serverless in cui esegui il tuo codice senza preoccuparti dell'infrastruttura di base, come i server o le macchine virtuali. Per consentire a Google di gestire e scalare automaticamente le funzioni, queste devono essere stateless: una chiamata funzione non deve fare affidamento sullo stato in memoria impostato da una chiamata precedente. Tuttavia, lo stato esistente può spesso essere riutilizzato per l'ottimizzazione del rendimento. Per ulteriori dettagli, consulta il consiglio Suggerimenti e consigli.
Ad esempio, il valore contatore restituito dalla funzione seguente non corrisponde al conteggio delle chiamate della funzione totale perché le chiamate potrebbero essere gestite da istanze di funzioni diverse, che non condividono variabili globali, memoria, file system o altri stati:
Node.js
Python
Go
Java
C#
Ruby
PHP
Le funzioni PHP non possono mantenere lo stato (come valori di variabile) tra le richieste.Se devi condividere lo stato tra più chiamate di funzione, devi utilizzare un servizio come Datastore, Firestore o Cloud Storage per conservare i dati. Per un elenco completo delle opzioni di archiviazione disponibili, consulta la sezione Scegliere un'opzione di archiviazione.
Scalabilità automatica e contemporaneità
Cloud Functions gestisce le richieste in entrata assegnandole alle istanze della tua funzione. A seconda del volume di richieste e del numero di istanze di funzione esistenti, Cloud Functions può assegnare una richiesta a un'istanza esistente o crearne una nuova.
Ogni istanza di una funzione gestisce una sola richiesta in parallelo alla volta. Ciò significa che mentre il codice è in fase di elaborazione di una richiesta, non è possibile instradare una seconda richiesta alla stessa istanza. La richiesta originale può quindi utilizzare l'intera quantità di risorse (CPU e memoria) che hai richiesto.
Se il volume della richiesta in entrata supera il numero di istanze esistenti, Cloud Functions potrebbe avviare più nuove istanze per gestire le richieste. Questo comportamento di scalabilità automatica consente a Cloud Functions di gestire molte richieste in parallelo, ciascuna utilizzando un'istanza diversa della funzione.
Poiché le richieste in parallelo vengono elaborate da istanze di funzione diverse, non condividono le variabili o la memoria locale. Ne parliamo in dettaglio più avanti in questo documento.
Controllo del comportamento di scalabilità automatica
Cloud Functions ti consente di impostare un limite sul numero totale di istanze di funzione che possono coesistere in un dato momento. In alcuni casi, è preferibile evitare una scalabilità senza limiti. Ad esempio, la tua funzione potrebbe dipendere da una risorsa (ad esempio un database) che non è in grado di fare lo scale up allo stesso livello di Cloud Functions. Un enorme picco del volume delle richieste potrebbe determinare la creazione di istanze di funzioni da parte di Cloud Functions in modo da riuscire a tollerare il tuo database.
Avvio completo
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 per fare lo scale up fino al carico oppure, 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 di un'istanza di funzione (avvii a freddo) possono essere più lente delle richieste che interessano le istanze di funzione esistenti. Se la funzione riceve un carico costante, tuttavia, il numero di avvii completi è generalmente trascurabile, a meno che la funzione non si arresti spesso e richieda il riavvio dell'ambiente della funzione. Leggi la sezione Errori per scoprire come gestire correttamente gli errori ed evitare avvii completi dovuti a funzioni che si sono arrestate in modo anomalo.
Se la tua funzione è sensibile alla latenza, valuta la possibilità di impostare un limite minimo di istanze per evitare avvii completi.
Durata istanza funzione
L'ambiente che esegue un'istanza di funzione in genere è resiliente e riutilizzato da chiamate di funzioni successive, a meno che il numero di istanze non venga ridotto (a causa della mancanza di traffico in corso) o dell'arresto anomalo della funzione. Questo significa che quando un'esecuzione di funzione funziona, un'altra chiamata a funzione può essere gestita dalla stessa istanza di funzione. Pertanto, quando possibile, ti consigliamo di memorizzare lo stato nella cache tra le chiamate nell'ambito globale. La funzione deve essere ancora pronta per funzionare senza questa cache disponibile, poiché non è garantito che la chiamata successiva raggiunga la stessa istanza di funzione (consulta la sezione Funzioni stateless).
Ambito della funzione e ambito globale
Una chiamata a funzione singola comporta l'esecuzione solo del corpo della funzione dichiarata come punto di contatto. L'ambito globale nel file della funzione, che dovrebbe contenere la definizione della funzione, viene eseguito a ogni avvio a freddo, ma non se l'istanza è già stata inizializzata.
Node.js
Python
Go
Java
Ruby
Puoi presumere che l'ambito globale sia stato eseguito esattamente una volta prima che il codice della funzione venga richiamato in una nuova istanza di funzione (e in ogni creazione successiva di una nuova istanza di funzione). Tuttavia, non devi dipendere dal numero totale o dalle tempistiche delle esecuzioni degli ambiti globali, in quanto dipendono dalla scalabilità automatica gestita da Google.
Cronologia di esecuzione della funzione
Una funzione ha accesso alle risorse richieste (CPU e memoria) solo per la durata dell'esecuzione della funzione. Non è garantito che il codice eseguito al di fuori del periodo di esecuzione venga eseguito e può essere interrotto in qualsiasi momento. Pertanto, dovresti sempre segnalare correttamente la fine dell'esecuzione della tua funzione ed evitare di eseguire codice aggiuntivo. Per indicazioni, consulta Funzioni HTTP, Funzioni in background e Funzionalità CloudEvent.
Ad esempio, il codice eseguito dopo l'invio della risposta HTTP potrebbe essere interrotto in qualsiasi momento:
Node.js
È importante tenere in considerazione la sequenza temporale di esecuzione durante l'inizializzazione dell'applicazione. Le attività in background non devono essere create nell'ambito globale durante l'inizializzazione, in quanto vengono eseguite al di fuori della durata di una richiesta.
Garanzie di esecuzione
In genere le funzioni vengono richiamate una volta per ogni evento in entrata. Tuttavia, Cloud 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 verrà richiamata in un singolo evento dipende dal tipo di funzione:
Le funzioni HTTP vengono richiamate al massimo numero di volte. Ciò avviene a causa della natura sincrona delle chiamate HTTP e indica che verrà restituito qualsiasi errore nella gestione della chiamata della funzione senza nuovi 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 di gestione degli eventi, in cui nessun chiamante attende la risposta. Il sistema potrebbe, in rari casi, richiamare una funzione basata su eventi più di una volta per garantire la pubblicazione dell'evento. Se una chiamata di funzione basata su eventi non riesce e restituisce un errore, non verrà richiamata a meno che non sia abilitato i nuovi tentativi in caso di errore.
Per assicurarti che la funzione si comporti correttamente durante i nuovi tentativi di esecuzione, dovresti renderla idempotente implementandola in modo che un evento generi i risultati (ed effetti collaterali) desiderati anche se viene eseguito più volte. Nel caso delle funzioni HTTP, ciò comporta anche la restituzione del valore desiderato anche se il chiamante riprova a chiamare l'endpoint della funzione HTTP. Per ulteriori informazioni su come rendere la funzione idempotente, consulta la sezione Riprovare le funzioni basate su eventi.
Errori
Il metodo consigliato per segnalare un errore dipende dal tipo di funzione:
Le funzioni HTTP devono restituire codici di stato HTTP appropriati che indicano un errore. Per esempi, vedi Funzioni HTTP.
Le funzioni basate su eventi devono registrare e restituire un messaggio di errore. Per vedere degli esempi, consulta le funzioni in background e le funzioni di CloudEvent.
Se un errore viene restituito nel modo consigliato, l'istanza di funzione che ha restituito l'errore viene etichettata come normale e può soddisfare richieste future, se necessario.
Se il codice o qualsiasi altro codice chiamato genera un'eccezione non rilevata o causa un arresto anomalo del processo attuale, l'istanza di funzione potrebbe essere riavviata prima di gestire la chiamata successiva. Ciò può causare avvii più freddi, con conseguente maggiore latenza, quindi è sconsigliato.
Per ulteriori dettagli su come segnalare errori in Cloud Functions, vedi Segnalazione degli errori.
Timeout
Il tempo di esecuzione della funzione è limitato dalla durata del timeout, che puoi specificare al momento del deployment della funzione. Per impostazione predefinita, una funzione scade dopo 1 minuto, ma puoi estendere questo periodo fino a 9 minuti.
Quando l'esecuzione della funzione supera il timeout, lo stato dell'errore viene immediatamente restituito al chiamante. Le risorse della CPU utilizzate dall'istanza della funzione con timeout sono ridotte e l'elaborazione delle richieste può essere messa in pausa immediatamente. Il lavoro in pausa potrebbe non procedere o meno per le richieste successive, causando effetti collaterali imprevisti.
Lo snippet riportato di seguito include il codice pianificato per essere eseguito 2 minuti dopo l'inizio dell'esecuzione della funzione. Se il timeout viene impostato su 1 minuto, il codice potrebbe non essere mai eseguito:
Node.js
Python
Go
Java
In alcune circostanze, il codice riportato sopra può essere eseguito correttamente, ma in modo imprevisto. Considera lo scenario quando la funzione scade. L'istanza che gestisce la richiesta è in pausa (limitando la CPU). I lavori in attesa sono in pausa. Se una richiesta successiva viene instradata alla stessa istanza, il lavoro viene ripristinato e Function running...
viene emesso nei log.
Un sintomo comune di questo comportamento è l'aspetto che i lavori e i log di un'unica richiesta vengono segnalati in una richiesta successiva. Poiché non puoi dipendere dal ripristino dei lavori in pausa, non devi fare affidamento su tale comportamento. La funzione deve invece evitare timeout utilizzando una combinazione delle seguenti tecniche:
- Imposta un timeout superiore al tempo di esecuzione della funzione previsto.
- Monitora il tempo rimanente durante l'esecuzione ed esegui la pulizia/uscita in anticipo.
Per impostare il tempo di esecuzione massimo di una funzione utilizzando l'interfaccia a riga di comando di Google Cloud, utilizza il flag --timeout
al momento del deployment:
gcloud functions deploy FUNCTION_NAME --timeout=TIMEOUT FLAGS...
Nel comando riportato sopra, FLAGS...
si riferisce ad altre opzioni trasmesse durante il deployment della funzione. Per un riferimento completo per il comando deploy
, consulta la pagina
gcloud functions deploy
.
Puoi anche impostare il timeout durante la creazione della funzione in Cloud Console, come descritto di seguito:
Vai alla pagina Panoramica di Cloud Functions in Cloud Console.
Fai clic su Crea funzione.
Compila i campi obbligatori per la funzione.
Visualizza le impostazioni avanzate facendo clic su Altro.
Inserisci un valore nel campo Timeout.
Memoria
Per impostare la memoria di una funzione tramite l'interfaccia a riga di comando di Google Cloud, utilizza il
flag --memory
con il
numero di megabyte. Ad esempio:
gcloud functions deploy FUNCTION_NAME --memory=MEMORY
Per impostazione predefinita, la memoria allocata a ciascuna funzione è di 256 MB.
File system
L'ambiente di esecuzione della funzione contiene un file di funzione eseguibile, oltre a file e directory inclusi nel pacchetto delle funzioni di cui è stato eseguito il deployment, ad esempio dipendenze locali. Questi file sono disponibili in una directory di sola lettura, che può essere determinata in base alla posizione del file della funzione. Tieni presente che la directory della funzione può essere diversa dalla directory di lavoro corrente.
L'esempio seguente elenca i file che si trovano nella directory delle funzioni:
Node.js
Python
Go
Java
C#
Ruby
PHP
Puoi anche caricare il codice da altri file di cui è stato eseguito il deployment con la funzione.
Il file system stesso è completamente scrivibile (tranne per i file usati dal sistema operativo sottostante) e viene archiviato nella memoria dell'istanza di Cloud Functions.
Rete
La tua funzione può accedere alla rete Internet pubblica utilizzando le librerie standard offerte dal runtime o da provider di terze parti. Ad esempio, puoi chiamare un endpoint HTTP come mostrato di seguito:
Node.js
Python
Go
Java
C#
Ruby
PHP
Prova a riutilizzare le connessioni di rete nelle chiamate delle funzioni, come descritto in Ottimizzare il networking. Tuttavia, tieni presente che una connessione che rimane inutilizzata per 10 minuti potrebbe essere chiusa dal sistema e ulteriori tentativi di utilizzo di una connessione chiusa comporteranno un errore di reimpostazione della connessione. Il codice deve utilizzare una libreria che gestisce bene le connessioni chiuse o gestirla esplicitamente se vengono utilizzati costrutti di networking di basso livello.
Più funzioni
Ogni funzione di cui è stato eseguito il deployment viene isolata da tutte le altre, anche quelle di cui è stato eseguito il deployment dallo stesso file di origine. In particolare, non condividono memoria, variabili globali, file system o altri stati.
Per condividere i dati tra le funzioni di cui è stato eseguito il deployment, puoi utilizzare servizi di archiviazione come Datastore, Firestore o Cloud Storage. In alternativa, puoi richiamare una funzione da un'altra, utilizzando i relativi trigger appropriati. Ad esempio, effettua una richiesta HTTP all'endpoint di una funzione HTTP o pubblica un messaggio in un argomento Pub/Sub per attivare una funzione Pub/Sub.