Questa guida fornisce le migliori pratiche per la progettazione, l'implementazione, il test e la distribuzione di un servizio Cloud Run. Per ulteriori suggerimenti, vedere Migrazione di un servizio esistente.
Scrivere servizi efficaci
Questa sezione descrive le migliori pratiche generali per la progettazione e l'implementazione di un servizio Cloud Run.
Attività di sfondo
Le attività in background sono tutto ciò che accade dopo l'invio della risposta HTTP. Per determinare se nel tuo servizio è presente un'attività in background non immediatamente evidente, controlla i log per individuare qualsiasi voce registrata dopo quella relativa alla richiesta HTTP.
Configura la fatturazione basata sulle istanze per utilizzare le attività in background
Se vuoi supportare le attività in background nel tuo servizio Cloud Run, imposta il servizio Cloud Run sulla fatturazione basata sulle istanze in modo da poter eseguire le attività in background al di fuori delle richieste e avere comunque accesso alla CPU.
Evitate le attività in background se utilizzate la fatturazione su richiesta.
Se devi impostare il tuo servizio su fatturazione basata su richiesta, quando il servizio Cloud Run termina di elaborare una richiesta, l'accesso dell'istanza alla CPU verrà disabilitato o fortemente limitato. Se si utilizza questo tipo di fatturazione, è sconsigliabile avviare thread o routine in background che vengano eseguiti al di fuori dell'ambito dei gestori delle richieste.
Controlla il codice per assicurarti che tutte le operazioni asincrone vengano completate prima di fornire la risposta.
L'esecuzione di thread in background con la fatturazione basata sulle richieste abilitata può comportare comportamenti imprevisti, poiché qualsiasi richiesta successiva alla stessa istanza del container riprende l'attività in background sospesa.
Elimina i file temporanei
Nell'ambiente Cloud Run, l'archiviazione su disco è un filesystem in memoria. I file scritti su disco consumano memoria altrimenti disponibile per il servizio e possono persistere tra un'esecuzione e l'altra. La mancata eliminazione di questi file può causare un errore di memoria insufficiente e, di conseguenza, un rallentamento dell'avvio del container.
Segnala gli errori
Gestisci tutte le eccezioni e impedisci che il servizio si blocchi in caso di errori. Un arresto anomalo provoca un avvio lento del container, mentre il traffico viene messo in coda per un'istanza sostitutiva.
Consulta la Guida alla segnalazione degli errori per informazioni su come segnalare correttamente gli errori.
Ottimizza le prestazioni
Questa sezione descrive le best practice per ottimizzare le prestazioni.
Avvia rapidamente i container
Poiché le istanze vengono scalate in base alle necessità, il loro tempo di avvio influisce sulla latenza del servizio. Cloud Run separa l'avvio dell'istanza dall'elaborazione della richiesta, quindi in alcuni casi una richiesta deve attendere l'avvio di una nuova istanza prima di poter essere elaborata. Questo accade comunemente quando un servizio viene scalato da zero.
La routine di avvio è costituita da:
- Download dell'immagine del container (utilizzando la tecnologia di streaming delle immagini container di Cloud Run)
- Avvio del container eseguendo il comando entrypoint.
- In attesa che il container inizi ad ascoltare sulla porta configurata.
L'ottimizzazione della velocità di avvio del container riduce al minimo la latenza di elaborazione delle richieste.
Utilizza il boosting della CPU all'avvio per ridurre la latenza di avvio
Puoi attivare il boosting della CPU all'avvio per aumentare temporaneamente l'allocazione della CPU durante l'avvio dell'istanza al fine di ridurre la latenza di avvio.
Utilizzare il numero minimo di istanze per ridurre i tempi di avvio dei container.
È possibile configurare istanze minime e concorrenza per ridurre al minimo i tempi di avvio dei container. Ad esempio, l'utilizzo di un numero minimo di istanze pari a 1 significa che il servizio è pronto a ricevere fino al numero di richieste simultanee configurate per il servizio senza dover avviare una nuova istanza. Quando utilizzi le istanze minime, evita di utilizzare le uscite di sistema che arrestano un'istanza e potenzialmente aumentano gli avvii a freddo.
Si noti che una richiesta in attesa dell'avvio di un'istanza verrà mantenuta in sospeso in una coda come segue:
Le richieste rimarranno in attesa fino a 3, 5 volte il tempo di avvio medio delle istanze di container di questo servizio o 10 secondi, a seconda di quale sia il valore maggiore.
Utilizza le dipendenze in modo strategico
Se si utilizza un linguaggio dinamico con librerie dipendenti, come ad esempio l'importazione di moduli in Node.js, il tempo di caricamento di tali moduli contribuisce alla latenza di avvio.
Riduci la latenza di avvio nei seguenti modi:
- Per creare un servizio snello, riduci al minimo il numero e le dimensioni delle dipendenze.
- Se il linguaggio di programmazione lo supporta, carica in modo differito il codice che viene utilizzato raramente.
- Utilizza ottimizzazioni del caricamento del codice come l'ottimizzazione del caricamento automatico di Composer di PHP.
Utilizzare variabili globali
In Cloud Run, non si può presumere che lo stato del servizio venga mantenuto tra una richiesta e l'altra. Tuttavia, Cloud Run riutilizza le singole istanze per gestire il traffico in corso, quindi è possibile dichiarare una variabile con ambito globale per consentirne il riutilizzo del valore nelle invocazioni successive. Non è possibile sapere in anticipo se una singola richiesta beneficerà di questo riutilizzo.
È inoltre possibile memorizzare nella cache gli oggetti se la loro ricreazione ad ogni richiesta di servizio risulta onerosa. Spostando questa logica dalla fase di richiesta alla fase globale si ottengono prestazioni migliori.
Node.js
Python
Go
Java
Esegui l'inizializzazione lazy delle variabili globali
L'inizializzazione delle variabili globali avviene sempre durante l'avvio, il che aumenta il tempo di avvio del container. Utilizza l'inizializzazione differita per gli oggetti usati raramente, in modo da posticipare il costo temporale e ridurre i tempi di avvio del container.
Uno svantaggio dell'inizializzazione differita è l'aumento della latenza per le prime richieste alle nuove istanze. Ciò può causare un overscaling e richieste eliminate quando deploy una nuova revisione di un servizio che gestisce attivamente molte richieste.
Node.js
Python
Go
Java
Utilizzare un ambiente di esecuzione diverso
Potresti riscontrare tempi di avvio più rapidi utilizzando un ambiente di esecuzione diverso.
Ottimizzare la concorrenza
Le istanze Cloud Run possono gestire più richieste simultaneamente, "in parallelo", fino a un massimo di concorrenza configurabile .
Cloud Run regola automaticamente il numero di processi simultanei fino al valore massimo configurato.
Il valore predefinito di 80 per la concorrenza massima è adatto a molte immagini container. Tuttavia, devi:
- Riduci questo valore se il tuo container non è in grado di elaborare molte richieste simultanee.
- Aumentalo se il tuo container è in grado di gestire un volume elevato di richieste.
Ottimizza la concorrenza per il tuo servizio
Il numero di richieste simultanee che ogni istanza può gestire può essere limitato dallo stack tecnologico e dall'utilizzo di risorse condivise come variabili e connessioni al database.
Per ottimizzare il servizio e ottenere la massima concorrenza stabile:
- Ottimizza le prestazioni del tuo servizio.
- Imposta il livello di supporto alla concorrenza previsto in qualsiasi configurazione di concorrenza a livello di codice. Non tutti gli stack tecnologici richiedono tale impostazione.
- Distribuisci il tuo servizio.
- Imposta la concorrenza di Cloud Run per il tuo servizio in modo che sia uguale o inferiore a qualsiasi configurazione a livello di codice. Se non è presente una configurazione a livello di codice, utilizza il livello di concorrenza previsto.
- Utilizzare strumenti di test di carico load test che supportino una concorrenza configurabile. È necessario verificare che il servizio rimanga stabile con il carico e la concorrenza previsti.
- Se il servizio non funziona correttamente, passa al passaggio 1 per migliorarlo oppure al passaggio 2 per ridurre la concorrenza. Se il servizio funziona correttamente, torna al passaggio 2 e aumenta la concorrenza.
Continua a iterare finché non trovi la massima concorrenza stabile.
Adattare la memoria alla concorrenza
Ogni richiesta gestita dal tuo servizio richiede una certa quantità di memoria aggiuntiva. Pertanto, quando aumenti o diminuisci la concorrenza, assicurati di regolare anche il limite di memoria.
Evitare lo stato globale mutabile
Se si desidera utilizzare uno stato globale modificabile in un contesto concorrente, è necessario adottare ulteriori misure nel codice per garantire che ciò avvenga in modo sicuro. Riduci al minimo la contesa limitando le variabili globali all'inizializzazione e al riutilizzo una tantum, come descritto sopra in Performance.
Se si utilizzano variabili globali mutabili in un servizio che gestisce più richieste contemporaneamente, è necessario utilizzare blocchi o mutex per prevenire condizioni di competizione.
Compromessi tra velocità di trasmissione, latenza e costi.
Regolare l'impostazione del numero massimo di richieste simultanee può aiutare a trovare un equilibrio tra velocità di trasmissione, latenza e costo del servizio.
In generale, un'impostazione del numero massimo di richieste simultanee più basso comporta una latenza inferiore e un throughput inferiore per istanza. Con un numero massimo di richieste simultanee inferiore, un minor numero di richieste compete per le risorse all'interno di ciascuna istanza e ogni richiesta ottiene prestazioni migliori. Tuttavia, poiché ogni istanza può gestire un numero inferiore di richieste contemporaneamente, la velocità di elaborazione per istanza è inferiore e il servizio necessita di un numero maggiore di istanze per gestire lo stesso traffico.
Nella direzione opposta, un'impostazione del numero massimo di richieste simultanee più elevata generalmente comporta una latenza maggiore e un throughput maggiore per istanza. Le richieste potrebbero dover attendere l'accesso a risorse come CPU, GPU e larghezza di banda della memoria all'interno dell'istanza, il che comporta una maggiore latenza. Ma ogni istanza può elaborare più richieste contemporaneamente, in modo che il servizio necessiti complessivamente di un minor numero di istanze per elaborare lo stesso traffico.
Considerazioni sui costi
Il prezzo di Cloud Run è per tempo di istanza. Se imposti fatturazione basata sull'istanza, il tempo dell'istanza corrisponde alla durata totale di ciascuna istanza. Se imposti la fatturazione basata sulle richieste, il tempo di istanza è il tempo che ogni istanza trascorre a elaborare almeno una richiesta.
L'impatto del numero massimo di richieste simultanee sulla fatturazione dipende dal pattern di traffico. La riduzione delle richieste simultanee massime può comportare una fattura inferiore se l'impostazione più bassa porta a
- Latenza ridotta
- Casi in cui il lavoro viene completato più velocemente
- Istanze che si arrestano più rapidamente anche se sono necessarie più istanze totali
Ma è possibile anche il contrario: la riduzione delle richieste simultanee massime può aumentare la fatturazione se l'aumento del numero di istanze non è compensato dalla riduzione del tempo di esecuzione di ciascuna istanza, a causa della latenza migliorata.
Il modo migliore per ottimizzare la fatturazione è attraverso test di carico utilizzando diverse impostazioni di richieste simultanee massime per identificare l'impostazione che si traduce nel tempo di istanza fatturabile più basso, come si vede nella metrica di monitoraggio container/billable_instance_timemonitor.
Sicurezza dei container
Molte pratiche di sicurezza software di uso generale si applicano anche ai servizi containerizzati. Esistono alcune pratiche specifiche per i container o che sono in linea con la filosofia e l'architettura dei container.
Per migliorare la sicurezza dei container:
Utilizza immagini di base sicure e gestite attivamente, come le immagini di base di Google o le immagini ufficiali di Docker Hub.
Applica gli aggiornamenti di sicurezza ai tuoi servizi ricreando regolarmente le immagini dei container e ridistribuendo i servizi.
Includi nel container solo ciò che è necessario per eseguire il tuo servizio. Codice aggiuntivo, pacchetti e strumenti non necessari rappresentano potenziali vulnerabilità di sicurezza. Vedi sopra per il relativo impatto sulle prestazioni.
Implementare un processo di compilazione deterministico che includa versioni specifiche di software e librerie. In questo modo, il codice non verificato non viene incluso nel contenitore.
Imposta il tuo contenitore in modo che venga eseguito come un utente diverso da
rootcon ilDockerfileUSERdichiarazione. Alcune immagini container potrebbero già avere un utente specifico configurato.Impedisci l'utilizzo delle funzionalità di anteprima tramite policy organizzative personalizzate.
Automatizzare la scansione di sicurezza
Abilita l'analisi delle vulnerabilità per l'analisi della sicurezza delle immagini container archiviate in Artifact Registry.
Creare immagini container minimali
Le immagini container di grandi dimensioni tendono ad aumentare le vulnerabilità di sicurezza perché contengono più elementi di quelli necessari al codice.
Grazie alla tecnologia di streaming delle immagini container di Cloud Run, le dimensioni dell'immagine container non influiscono sui tempi di avvio del container o sui tempi di elaborazione delle richieste. Anche le dimensioni dell'immagine container non vengono conteggiate ai fini della memoria disponibile del container.
Per creare un container minimale, si consiglia di partire da un'immagine base essenziale come:
Ubuntu è più grande in termini di dimensioni, ma è un'immagine di base comunemente utilizzata con un ambiente server più completo pronto all'uso.
Se il tuo servizio ha un processo di compilazione che richiede molti strumenti, considera l'utilizzo di compilation multi-stage per mantenere il tuo container leggero in fase di esecuzione.
Queste risorse forniscono ulteriori informazioni sulla creazione di immagini container lean:
- Migliori pratiche di Kubernetes: come e perché creare immagini container di piccole dimensioni
- 7 migliori pratiche per la creazione di container