Workflows ti consente di coordinare e automatizzare i servizi inGoogle Cloud. L'applicazione delle pratiche di architettura consigliate ti aiuta a migliorare l'affidabilità, ottimizzare i costi di esecuzione e creare orchestrazioni resilienti e gestibili.
Questo non è un elenco esaustivo di suggerimenti e non spiega le nozioni di base su come utilizzare Workflows. Questo documento presuppone che tu abbia già una conoscenza generale del panorama complessivo di Google Cloud e di Workflows. Per saperne di più, consulta il Well-Architected Framework diGoogle Cloud e la panoramica di Workflows.
Seleziona un modello di comunicazione ottimale
Quando progetti un'architettura di microservizi per il deployment di più servizi, puoi scegliere tra i seguenti pattern di comunicazione:
Comunicazione diretta tra servizi
Comunicazione indiretta basata su eventi (nota anche come coreografia)
Configurazione, coordinamento e gestione automatizzati (noti anche come orchestrazione)
Assicurati di considerare i vantaggi e gli svantaggi di ciascuna delle opzioni precedenti e seleziona un pattern ottimale per il tuo caso d'uso. Ad esempio, la comunicazione diretta tra servizi potrebbe essere più semplice da implementare rispetto ad altre opzioni, ma accoppia strettamente i servizi. Al contrario, un'architettura basata su eventi consente di accoppiare i servizi a basso accoppiamento; tuttavia, il monitoraggio e il debug potrebbero essere più complicati. Infine, un orchestratore centrale come Workflows, sebbene meno flessibile, consente di coordinare la comunicazione tra i servizi senza l'alto accoppiamento della comunicazione diretta tra servizi o la complessità degli eventi coreografati.
Puoi anche combinare i pattern di comunicazione. Ad esempio, nell'orchestrazione basata su eventi, i servizi strettamente correlati vengono gestiti in un'orchestrazione attivata da un evento. Analogamente, potresti progettare un sistema in cui un'orchestrazione genera un messaggio Pub/Sub per un altro sistema orchestrato.
Suggerimenti di carattere generale
Una volta deciso di utilizzare Workflows come orchestratore di servizi, tieni presente i seguenti suggerimenti utili.
Evita di impostare gli URL come hardcoded
Puoi supportare workflow portatili in più ambienti e più facili da gestire evitando gli URL impostati come hardcoded. Puoi farlo nei seguenti modi:
Definisci gli URL come argomenti di runtime.
Questo può essere utile quando il workflow viene richiamato tramite una libreria client o l'API. Tuttavia, questo non funzionerà se il workflow viene attivato da un evento di Eventarc e l'unico argomento che può essere passato è il payload dell'evento.
Esempio
main: params: [args] steps: - init: assign: - url1: ${args.urls.url1} - url2: ${args.urls.url2}
Quando esegui il workflow, puoi specificare gli URL. Ad esempio:
gcloud workflows run multi-env --data='{"urls":{"url1": "URL_ONE", "url2": "URL_TWO"}}'
Utilizza le variabili di ambiente e crea un workflow configurato in modo dinamico in base all'ambiente in cui viene eseguito il deployment. In alternativa, crea un workflow che possa essere riutilizzato come modello e configurato in base a variabili di ambiente gestite separatamente.
Utilizza una tecnica di sostituzione che ti consenta di creare un unico file di definizione del workflow, ma di eseguire il deployment delle varianti utilizzando uno strumento che sostituisce i segnaposto nel workflow. Ad esempio, puoi utilizzare Cloud Build per eseguire il deployment di un workflow e, nel file di configurazione di Cloud Build, aggiungere un passaggio per sostituire gli URL segnaposto nel workflow.
Esempio
steps: ‐ id: 'replace-urls' name: 'gcr.io/cloud-builders/gcloud' entrypoint: bash args: - -c - | sed -i -e "s~REPLACE_url1~$_URL1~" workflow.yaml sed -i -e "s~REPLACE_url2~$_URL2~" workflow.yaml ‐ id: 'deploy-workflow' name: 'gcr.io/cloud-builders/gcloud' args: ['workflows', 'deploy', 'multi-env-$_ENV', '--source', 'workflow.yaml']
Puoi quindi sostituire i valori delle variabili in fase di build. Ad esempio:
gcloud builds submit --config cloudbuild.yaml \ --substitutions=_ENV=staging,_URL1="URL_ONE",_URL2="URL_TWO"
Per saperne di più, consulta Invia una build tramite interfaccia a riga di comando e API.
In alternativa, puoi utilizzare Terraform per eseguire il provisioning dell'infrastruttura e definire un file di configurazione che crea workflow per ogni ambiente utilizzando le variabili di input.
Esempio
variable "project_id" { type = string } variable "url1" { type = string } variable "url2" { type = string } locals { env = ["staging", "prod"] } # Define and deploy staging and production workflows resource "google_workflows_workflow" "multi-env-workflows" { for_each = toset(local.env) name = "multi-env-${each.key}" project = var.project_id region = "us-central1" source_contents = templatefile("${path.module}/workflow.yaml", { url1 : "${var.url1}-${each.key}", url2 : "${var.url2}-${each.key}" }) }
Quando le variabili vengono dichiarate nel modulo principale della configurazione, possono essere assegnate ai valori in diversi modi. Ad esempio:
terraform apply -var="project_id=PROJECT_ID" -var="url1=URL_ONE" -var="url2=URL_TWO"
Utilizza il connettore Secret Manager per archiviare in modo sicuro gli URL in Secret Manager e recuperarli.
Utilizza i passaggi nidificati
Ogni workflow deve avere almeno un passaggio.
Per impostazione predefinita, Workflows considera i passaggi come se fossero in un elenco ordinato e li esegue uno alla volta fino a quando non sono stati eseguiti tutti. Logicamente, alcuni passaggi devono essere raggruppati e puoi utilizzare un blocco steps per nidificare una serie di passaggi. Questo è utile perché ti consente di fare riferimento al passaggio atomico corretto per elaborare un insieme di passaggi.
Esempio
main: params: [input] steps: - callWikipedia: steps: - checkSearchTermInInput: switch: - condition: ${"searchTerm" in input} assign: - searchTerm: ${input.searchTerm} next: readWikipedia - getCurrentDate: call: http.get args: url: https://timeapi.io/api/Time/current/zone?timeZone=Europe/Amsterdam result: currentDate - setFromCallResult: assign: - searchTerm: ${currentDate.body.dayOfWeek} - readWikipedia: call: http.get args: url: https://en.wikipedia.org/w/api.php query: action: opensearch search: ${searchTerm} result: wikiResult - returnOutput: return: ${wikiResult.body[1]}
Espressioni aggregate
Tutte le espressioni devono iniziare con
un $ ed essere racchiuse tra parentesi graffe:
${EXPRESSION}Per evitare problemi di analisi YAML, puoi racchiudere le espressioni tra virgolette. Ad esempio, le espressioni contenenti due punti possono causare un comportamento imprevisto quando i due punti vengono interpretati come la definizione di una mappa. Puoi risolvere il problema racchiudendo l'espressione YAML tra virgolette singole:
'${"Name: " + myVar}'
Puoi anche utilizzare espressioni che si estendono su più righe. Ad esempio, potrebbe essere necessario racchiudere una query SQL tra virgolette quando utilizzi il connettore BigQuery di Workflows.
Esempio
- runQuery: call: googleapis.bigquery.v2.jobs.query args: projectId: ${sys.get_env("GOOGLE_CLOUD_PROJECT_ID")} body: useLegacySql: false useQueryCache: false timeoutMs: 30000 # Find top 100 titles with most views on Wikipedia query: ${ "SELECT TITLE, SUM(views) FROM `bigquery-samples.wikipedia_pageviews." + table + "` WHERE LENGTH(TITLE) > 10 GROUP BY TITLE ORDER BY SUM(VIEWS) DESC LIMIT 100" } result: queryResult
Per la definizione completa del workflow, consulta Esegui più job BigQuery in parallelo.
Utilizza le chiamate dichiarative
Utilizza Workflows per chiamare i servizi dal workflow stesso e gestire i risultati, nonché per eseguire attività semplici come effettuare una chiamata HTTP. Workflows può richiamare servizi, analizzare risposte e creare input per altri servizi connessi. La chiamata a un servizio ti consente di evitare le complicazioni di chiamate aggiuntive, dipendenze aggiuntive e servizi che chiamano servizi. Valuta la possibilità di sostituire i servizi privi di logica di business con chiamate API dichiarative e utilizza Workflows per astrarre la complessità.
Tuttavia, devi creare servizi per eseguire qualsiasi lavoro troppo complesso per Workflows, ad esempio l'implementazione di logica di business riutilizzabile, calcoli complessi o trasformazioni non supportate dalle espressioni di Workflows e dalla relativa libreria standard. In genere, un caso complicato è più facile da implementare nel codice, anziché utilizzare YAML o JSON e la sintassi di Workflows.
Archivia solo ciò che ti serve
Tieni sotto controllo il consumo di memoria in modo da non raggiungere i limiti delle risorse o un errore che lo indica, ad esempio ResourceLimitError, MemoryLimitExceededError o ResultSizeLimitExceededError.
Sii selettivo su ciò che memorizzi nelle variabili, filtrando e memorizzando solo ciò di cui hai bisogno. Se un servizio restituisce un payload troppo grande, utilizza una funzione separata per effettuare la chiamata e restituire solo ciò che è richiesto.
Puoi liberare memoria cancellando le variabili. Ad esempio, potresti voler liberare memoria necessaria per i passaggi successivi. In alternativa, potresti avere chiamate con risultati che non ti interessano e puoi omettere del tutto questi risultati.
Puoi cancellare una variabile assegnando null. In YAML, puoi anche assegnare un valore vuoto o ~ a una variabile. In questo modo viene identificata la memoria che può essere recuperata in sicurezza.
Esempio
- step: assign: - bigVar:
Utilizza subworkflow e workflow esterni
Puoi utilizzare i subworkflow per definire una parte di logica o un insieme di passaggi che vuoi chiamare più volte, semplificando la definizione del workflow. I subworkflow sono simili a una funzione o a una routine in un linguaggio di programmazione. Possono accettare parametri e restituire valori, consentendoti di creare workflow più complessi con una gamma più ampia di applicazioni.
Tieni presente che i subworkflow sono locali rispetto alla definizione del workflow e non possono essere riutilizzati in altri workflow. Tuttavia, puoi chiamare i workflow da altri workflow. I connettori di Workflows possono aiutarti in questo. Per saperne di più, consulta le panoramiche dei connettori per l'API Workflow Executions e l'API Workflows.
Utilizza i connettori di Workflows
Workflows fornisce una serie di connettori che semplificano l'accesso ad altri prodotti Google Cloud all'interno di un workflow. I connettori semplificano la chiamata dei servizi perché gestiscono la formattazione delle richieste per te, fornendo metodi e argomenti in modo che tu non debba conoscere i dettagli di un'APIGoogle Cloud . I connettori hanno anche un comportamento integrato per la gestione dei nuovi tentativi e delle operazioni a lunga esecuzione, in modo da evitare di ripetere e attendere il completamento delle chiamate. I connettori se ne occupano al posto tuo.
Se devi chiamare un'API Google Cloud , controlla prima se esiste un connettore Workflows per l'API. Se non vedi un connettore per un prodotto Google Cloud , puoi richiederlo.
Scopri come utilizzare un connettore e, per un riferimento dettagliato dei connettori disponibili, consulta il Riferimento dei connettori.
Esegui i passaggi del workflow in parallelo
Sebbene Workflows possa eseguire i passaggi in sequenza, puoi anche eseguire passaggi indipendenti in parallelo. In alcuni casi, questo può velocizzare notevolmente l'esecuzione del workflow. Per saperne di più, consulta Esegui i passaggi del workflow in parallelo.
Applica i nuovi tentativi e il pattern saga
Progetta workflow resilienti e in grado di gestire errori del servizio sia temporanei che permanenti. Gli errori per Workflows potrebbero essere generati, ad esempio, da richieste HTTP, funzioni o connettori non riusciti oppure dal codice del workflow. Aggiungi la gestione degli errori e i nuovi tentativi in modo che un errore in un passaggio non causi l'errore dell'intero workflow.
- Puoi generare errori personalizzati utilizzando la sintassi
raise. - Puoi rilevare gli errori utilizzando un blocco
try/except. - Puoi riprovare i passaggi utilizzando un blocco
try/retrye definire il numero massimo di tentativi di ripetizione.
Alcune transazioni aziendali interessano più servizi, quindi è necessario un meccanismo per implementare le transazioni che interessano i servizi. Il pattern di progettazione saga è un modo per gestire la coerenza dei dati tra i microservizi in scenari di transazioni distribuite. Una saga è una sequenza di transazioni che pubblica un evento per ogni transazione e che attiva la transazione successiva. Se una transazione non va a buon fine, la saga esegue transazioni di compensazione che contrastano gli errori precedenti nella sequenza. Prova il tutorial su nuovi tentativi e pattern Saga in Workflows su GitHub.
Utilizza i callback per l'attesa
I callback consentono alle esecuzioni del workflow di attendere che un altro servizio effettui una richiesta all'endpoint di callback; questa richiesta riprende l'esecuzione del workflow.
Con i callback, puoi segnalare al workflow che si è verificato un evento specificato e attendere l'evento senza polling. Ad esempio, puoi creare un workflow che ti avvisa quando un prodotto torna disponibile o quando un articolo viene spedito oppure che attende per consentire l'interazione umana, ad esempio la revisione di un ordine o la convalida di una traduzione. Puoi anche attendere gli eventi utilizzando i callback e i trigger Eventarc.
Orchestra i job di lunga durata
Se devi eseguire workload di elaborazione batch a lunga esecuzione, puoi utilizzare Batch o i job Cloud Run e puoi utilizzare Workflows per gestire i servizi. In questo modo puoi combinare i vantaggi ed eseguire il provisioning e l'orchestrazione dell'intero processo in modo efficiente.
Batch è un servizio completamente gestito che consente di pianificare, inserire in coda ed eseguire workload batch su istanze di macchine virtuali (VM) Compute Engine. Puoi utilizzare il connettore Workflows per Batch per pianificare ed eseguire un job Batch. Per maggiori dettagli, prova il tutorial.
I job Cloud Run vengono utilizzati per eseguire il codice che svolge un'attività (un job) ed esce al termine dell'attività. Workflows consente di eseguire job Cloud Run all'interno di un flusso di lavoro per portare a termine elaborazioni di dati più complesse o orchestrare un sistema di job esistenti. Prova il tutorial che mostra come utilizzare Workflows per eseguire un job Cloud Run.
Allinea i timeout e le dimensioni dei payload tra i servizi
Quando Workflows chiama servizi Google Cloud downstream,
le differenze nei timeout delle richieste, nei limiti delle risposte HTTP e nei limiti di memoria possono
causare errori TimeoutError, ValueError o MemoryLimitExceededError.
Confronta i
limiti delle risorse di Workflows
con i limiti del servizio di destinazione e scegli un pattern di integrazione che
corrisponda alla durata e alle dimensioni del payload del tuo workload. Ad esempio:
| Scenario di integrazione | Limiti di Workflows | Limiti del servizio di destinazione | Pattern consigliato |
|---|---|---|---|
Chiamate HTTP sincrone
(http.get,
http.post,
http.request)
ai servizi Cloud Run o Cloud Run Functions
|
|
Consulta Configura il timeout delle richieste per i servizi e Limiti delle risorse per Cloud Run. |
Per i workload che vengono eseguiti per più di 30 minuti, non utilizzare chiamate Esegui invece i job Cloud Run utilizzando il connettore API Cloud Run Admin o utilizza un endpoint di callback Workflows asincrono. Il connettore API Cloud Run Admin supporta il polling delle operazioni a lunga esecuzione (LRO), che per impostazione predefinita scade dopo 30 minuti (1800 secondi). Per i job che vengono eseguiti per più di 30 minuti, configura sia il timeout dell'attività del job Cloud Run (10 minuti per impostazione predefinita, configurabile fino a 168 ore o 7 giorni) sia |
Query BigQuery e payload API di grandi dimensioni
(googleapis.
e risposte REST)
|
|
I risultati delle query BigQuery e i payload dell'API REST possono superare diversi megabyte o gigabyte. Consulta Quote e limiti dei job di query BigQuery. |
Evita di inserire set di risultati di grandi dimensioni nelle variabili del workflow. Utilizza l'impaginazione di |
Containerizza le attività di lunga durata
Puoi automatizzare l'esecuzione di un container a lunga esecuzione utilizzando Workflows e Compute Engine. Ad esempio, puoi containerizzare un'attività a lunga esecuzione in modo che possa essere eseguita ovunque, quindi eseguire il container su una VM di Compute Engine per la durata massima di un'esecuzione del workflow (un anno).
Utilizzando Workflows, puoi automatizzare la creazione della VM, l'esecuzione del container sulla VM e l'eliminazione della VM. In questo modo puoi utilizzare un server ed eseguire un container, ma la complessità della gestione di entrambi viene astratta. Questo può essere utile se riscontri limiti di tempo quando utilizzi un servizio come Cloud Run Functions o Cloud Run. Prova il tutorial Container a lunga esecuzione con Workflows e Compute Engine su GitHub.
Esegui strumenti a riga di comando da Workflows
Cloud Build è un servizio che esegue le tue build su Google Cloud come una serie di passaggi di build, dove ogni passaggio viene eseguito in un container Docker. L'esecuzione di passaggi di build è analoga all'esecuzione di comandi in uno script.
Google Cloud CLI include gli strumenti a riga di comando gcloud, bq e kubectl, ma non esiste un modo diretto per eseguire i comandi gcloud CLI da Workflows. Tuttavia, Cloud Build fornisce immagini container che includono gcloud CLI. Puoi eseguire i comandi di gcloud CLI in questi container da un passaggio di Cloud Build e puoi creare questo passaggio in Workflows utilizzando il connettore Cloud Build.
Esempio
Esegui gcloud in un workflow:
Run kubectl in a workflow:
Utilizza Terraform per creare il workflow
Terraform è uno strumento Infrastructure as Code che consente di creare, modificare e migliorare l'infrastruttura cloud in modo prevedibile utilizzando il codice.
Puoi definire ed eseguire il deployment di un workflow utilizzando la risorsa Terraform google_workflows_workflow. Per saperne di più, consulta Crea un workflow utilizzando Terraform.
Per aiutarti a gestire e mantenere workflow di grandi dimensioni, puoi creare il workflow in un file YAML separato e importarlo in Terraform utilizzando la funzione templatefile, che legge un file in un percorso specifico e ne esegue il rendering dei contenuti come modello.
Esempio
# Define a workflow resource "google_workflows_workflow" "workflows_example" { name = "sample-workflow" region = var.region description = "A sample workflow" service_account = google_service_account.workflows_service_account.id # Import main workflow YAML file source_contents = templatefile("${path.module}/workflow.yaml",{}) }
Analogamente, se hai un workflow principale che chiama più subworkflow, puoi definire il workflow principale e i subworkflow in file separati e utilizzare la funzione templatefile per importarli.
Esempio
# Define a workflow resource "google_workflows_workflow" "workflows_example" { name = "sample-workflow" region = var.region description = "A sample workflow" service_account = google_service_account.workflows_service_account.id # Import main workflow and subworkflow YAML files source_contents = join("", [ templatefile( "${path.module}/workflow.yaml",{} ), templatefile( "${path.module}/subworkflow.yaml",{} )]) }
Tieni presente che se fai riferimento ai numeri di riga durante il debug di un workflow, tutti i file YAML importati tramite il file di configurazione Terraform vengono uniti e viene eseguito il deployment come un unico workflow.
Esegui il deployment di un workflow da un repository Git
Cloud Build utilizza i trigger di build per abilitare l'automazione CI/CD. Puoi configurare i trigger in modo che rimangano in ascolto degli eventi in arrivo, ad esempio quando viene eseguito il push di un nuovo commit in un repository o quando viene avviata una richiesta di pull, quindi eseguire automaticamente una build quando arrivano nuovi eventi.
Puoi utilizzare un trigger di Cloud Build per avviare automaticamente una build ed eseguire il deployment di un workflow da un repository Git. Puoi configurare il trigger per eseguire il deployment del workflow per ogni modifica al repository di codice sorgente o solo quando la modifica soddisfa criteri specifici.
Questo approccio può aiutarti a gestire il ciclo di vita del deployment. Ad esempio, puoi eseguire il deployment delle modifiche a un workflow in un ambiente di gestione temporanea, eseguire test in quell'ambiente e poi lanciare in modo incrementale queste modifiche nell'ambiente di produzione. Per saperne di più, consulta Esegui il deployment di un workflow da un repository Git utilizzando Cloud Build.
Ottimizza l'utilizzo
Il costo per l'esecuzione di un workflow è minimo. Tuttavia, per un utilizzo con volumi elevati, applica le seguenti linee guida per ottimizzare l'utilizzo e ridurre i costi:
Anziché utilizzare domini personalizzati, assicurati che tutte le chiamate ai servizi Google Cloudutilizzino
*.appspot.com,*.cloud.goog,*.cloudfunctions.neto*.run.appin modo che ti vengano addebitati i passaggi interni e non quelli esterni.Applica una policy di ripetizione personalizzata che bilanci le tue esigenze di latenza e affidabilità con i costi. Tentativi più frequenti riducono la latenza e aumentano l'affidabilità, ma possono anche aumentare i costi.
Quando utilizzi connettori che attendono operazioni a lunga esecuzione, imposta una policy di polling personalizzata che ottimizza la latenza in base ai costi. Ad esempio, se prevedi che un'operazione richieda più di un'ora, potresti voler utilizzare una policy che esegua il polling inizialmente dopo un minuto in caso di errore immediato e, successivamente, ogni 15 minuti.
Combina i compiti in un unico passaggio.
Evita un uso eccessivo dei passaggi
sys.log. Ti consigliamo di utilizzare invece la registrazione delle chiamate.Scopri quali operazioni sono considerate un passaggio. Le operazioni che non vengono conteggiate come passaggi a sé stanti vengono conteggiate quando vengono utilizzate all'interno di un passaggio applicabile. Ad esempio, quanto segue viene conteggiato come un passaggio:
- type_check: return: if(get_type((int("6"))) == integer, 1, 2)Le operazioni chiave che vengono conteggiate e non vengono conteggiate ai fini del limite massimo di passaggi sono classificate nella seguente tabella:
Categoria Operazione Conteggiato come un passo - Operazioni sui dati: assegnazione, restituzione di valori
- Controllo del flusso: salti (
next), switch, avvio di un ciclofore ogni iterazione di un ciclofor - Chiamate: richiamo di
sys.get_envo di un'altra funzione della libreria standard, di un altro workflow o di un connettore - Concorrenza: generazione di thread ed esecuzione parallela
- Gestione degli errori: ogni blocco
raise,try,retryeexceptviene conteggiato come un passaggio separato, anche se altre operazioni fanno parte dello stesso passaggio più grande.Ad esempio, un passaggio che include un blocco
trycon un'operazione di chiamata viene conteggiato come tre passaggi: uno per il passaggio principale, uno per il tentativo e uno per la chiamata. L'aggiunta di un bloccoretryaggiunge altri tre passaggi (uno per il nuovo tentativo, uno per il tentativo e uno per la chiamata), per un totale di sei passaggi.
Non viene conteggiato come passaggio - Lettura e scrittura di elenchi, mappe e variabili
Anche se una singola ricerca non aggiunge un passaggio aggiuntivo, un passaggio che contiene la ricerca, ad esempio un passaggio
assign, viene conteggiato come un passaggio. - Funzioni helper delle espressioni integrate specifiche:
len(),int()eget_type() - Operazioni di confronto e aritmetiche
- Concatenazione di stringhe
- Operazioni booleane
Riepilogo delle best practice
La tabella seguente riassume i suggerimenti generali e le best practice consigliate in questo documento.