Quando orchestri i tuoi servizi utilizzando Workflows, puoi fare riferimento alle best practice elencate qui.
Non si tratta di un elenco esaustivo di consigli e non ti insegna le nozioni di base su come utilizzare Workflows. Questo documento presuppone che tu abbia già una conoscenza generale del panorama complessivo e Google Cloud di Workflows. Per saperne di più, consulta il Google Cloud framework Well-Architected 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 modelli di comunicazione:
Comunicazione diretta service-to-service
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 di selezionare un modello ottimale per il tuo caso d'uso. Ad esempio, la comunicazione diretta service-to-service potrebbe essere più semplice da implementare rispetto ad altre opzioni, ma accoppia strettamente i tuoi servizi. Al contrario, un' architettura basata su eventi consente di accoppiare in modo lasco i servizi; 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 service-to-service o la complessità degli eventi coreografati.
Puoi anche combinare i modelli di comunicazione. Ad esempio, nell'orchestrazione basata su eventi, i servizi strettamente correlati vengono gestiti in un'orchestrazione che è attivata da un evento. Allo stesso modo, potresti progettare un sistema in cui un'orchestrazione genera un messaggio Pub/Sub a un altro sistema orchestrato.
Suggerimenti di carattere generale
Dopo aver deciso di utilizzare Workflows come orchestratore di servizi, tieni presente i seguenti suggerimenti utili.
Evita di codificare gli URL
Puoi supportare workflow portatili in più ambienti e più facili da gestire evitando gli URL 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, questa operazione 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 dinamicamente a seconda dell'ambiente in cui viene eseguito il deployment. In alternativa, crea un workflow che può essere riutilizzato come modello e configurato in base alle variabili di ambiente gestite separatamente.
Utilizza una tecnica di sostituzione che ti consente di creare un singolo 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 dei 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 compilazione. Ad esempio:
gcloud builds submit --config cloudbuild.yaml \ --substitutions=_ENV=staging,_URL1="URL_ONE",_URL2="URL_TWO"
Per saperne di più, consulta Inviare 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, è possibile assegnare loro 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 finché non sono stati eseguiti tutti. Dal punto di vista logico, alcuni passaggi devono essere raggruppati e puoi utilizzare un blocco steps per nidificare una serie di passaggi. Questo è utile perché ti consente di puntare 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]}
Aggrega le espressioni
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 i due punti possono causare un comportamento imprevisto quando i due punti vengono interpretati come definizione di una mappa. Puoi risolvere questo problema racchiudendo l'espressione YAML tra virgolette singole:
'${"Name: " + myVar}'
Puoi anche utilizzare espressioni che si estendono su più righe. Ad esempio, potresti dover 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 Eseguire 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 i servizi, analizzare le risposte e creare input per altri servizi connessi. La chiamata a un servizio consente di evitare le complicazioni di chiamate aggiuntive, dipendenze aggiuntive e servizi che chiamano altri 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 attività troppo complessa per Workflows, ad esempio l'implementazione di logica di business riutilizzabile, calcoli complessi o trasformazioni non supportate da 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 superare
i limiti delle risorse o riscontrare un errore che indica
questo, ad esempio ResourceLimitError, MemoryLimitExceededError, o
ResultSizeLimitExceededError.
Seleziona attentamente ciò che archivi nelle variabili, filtrando e archiviando solo ciò che ti serve. Se un servizio restituisce un payload troppo grande, utilizza una funzione separata per effettuare la chiamata e restituire solo ciò che è necessario.
Puoi liberare memoria cancellando le variabili. Ad esempio, potresti voler liberare la memoria necessaria per i passaggi successivi. In alternativa, potresti avere chiamate con risultati che non ti interessano e puoi ometterli completamente.
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 modo sicuro.
Esempio
- step: assign: - bigVar:
Utilizza i workflow secondari e i workflow esterni
Puoi utilizzare i workflow secondari per definire una parte di logica o un insieme di passaggi che vuoi chiamare più volte, semplificando la definizione del workflow. I workflow secondari 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 workflow secondari sono locali 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 Google Cloud prodotti all'interno di un workflow. I connettori semplificano la chiamata ai servizi perché gestiscono la formattazione delle richieste, fornendo metodi e argomenti in modo che tu non debba conoscere i dettagli di un' Google Cloud API. I connettori hanno anche un comportamento integrato per la gestione dei nuovi tentativi e delle operazioni a lunga esecuzione, in modo da evitare di eseguire l'iterazione e attendere il completamento delle chiamate; i connettori si occupano di questo.
Se devi chiamare un' Google Cloud API, controlla prima se esiste un connettore Workflows per questa. Se non vedi un connettore per un Google Cloud prodotto, puoi richiederlo.
Scopri come utilizzare un connettore e, per un riferimento dettagliato dei connettori disponibili, consulta la documentazione di 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ò accelerare notevolmente l'esecuzione del workflow. Per saperne di più, consulta Eseguire i passaggi del workflow in parallelo.
Applica i nuovi tentativi e il modello Saga
Progetta workflow resilienti in grado di gestire sia gli errori di servizio temporanei che quelli 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 il fallimento dell'intero workflow.
- Puoi generare errori personalizzati
utilizzando la sintassi
raise. - Puoi rilevare gli errori utilizzando
un
try/exceptblocco. - Puoi riprovare a eseguire i passaggi utilizzando un
try/retryblocco e definire il numero massimo di tentativi.
Alcune transazioni aziendali interessano più servizi, quindi è necessario un meccanismo per implementare transazioni che interessano più servizi. Il modello 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 riesce, la saga esegue transazioni di compensazione che contrastano gli errori precedenti nella sequenza. Prova il tutorial Nuovi tentativi e modello Saga in Workflows su GitHub.
Utilizza i callback per attendere
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 eseguire il polling. Ad esempio, puoi creare un workflow che ti avvisa quando un prodotto è di nuovo disponibile o quando un articolo è stato spedito oppure che attende di 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 di Eventarc.
Orchestra i job a lunga esecuzione
Se devi eseguire carichi di lavoro 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 carichi di lavoro batch su istanze di macchine virtuali (VM) Compute Engine. Puoi utilizzare il connettore Workflows per Batch per pianificare ed eseguire un job Batch. Per i dettagli, prova out il tutorial.
I job Cloud Run vengono utilizzati per eseguire codice che svolge un'attività (un job) e si chiude al termine dell'attività. Workflows consente di eseguire job Cloud Run all'interno di un workflow 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.
Containerizza le attività a lunga esecuzione
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 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 e può essere utile se riscontri limiti di tempo quando utilizzi un servizio come le funzioni Cloud Run 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 build come una serie di passaggi di build, dove ogni passaggio viene eseguito in un container Docker. Google Cloud L'esecuzione di passaggi di build è analoga all'esecuzione di comandi in uno script.
La 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 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 in modo prevedibile l'infrastruttura cloud utilizzando il codice.
Puoi definire ed eseguire il deployment di un workflow utilizzando la risorsa Terraform
google_workflows_workflow. Per saperne di più, consulta
Creare un workflow utilizzando Terraform.
Per aiutarti a gestire e gestire i workflow di grandi dimensioni, puoi creare il workflow
in un file YAML separato e importarlo in Terraform utilizzando la
templatefile funzione
che legge un file in un determinato percorso e ne esegue il rendering del contenuto 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",{}) }
Allo stesso modo, se hai un workflow principale che chiama più workflow secondari, puoi definire il workflow principale e i workflow secondari 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 di Terraform vengono uniti ed eseguiti come un singolo 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 ascoltino gli eventi in entrata, ad esempio quando viene eseguito il push di un nuovo commit in un repository o quando viene avviata una richiesta di pull, e 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 in modo che esegua il deployment del workflow per ogni modifica al repository di codice sorgente oppure 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 staging, eseguire test su questo ambiente e quindi avviare in modo incrementale queste modifiche nell'ambiente di produzione. Per saperne di più, consulta Eseguire il deployment di un workflow da un repository Git utilizzando Cloud Build.
Ottimizza l'utilizzo
Il costo di esecuzione di un workflow è minimo. Tuttavia, per un utilizzo di 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 Google Cloud servizi utilizzino
*.appspot.com,*.cloud.goog,*.cloudfunctions.net, o*.run.appin modo che ti vengano addebitati i passaggi interni e non quelli esterni.Applica una policy di nuovi tentativi personalizzata che bilanci le esigenze di latenza e affidabilità con i costi. I nuovi tentativi più frequenti riducono la latenza e aumentano l'affidabilità, ma possono anche aumentare i costi.
Quando utilizzi i connettori che attendono operazioni a lunga esecuzione, imposta una policy di polling personalizzata che ottimizzi la latenza per i 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 poi ogni 15 minuti.
Combina le assegnazioni in un unico passaggio.
Evita un utilizzo eccessivo dei passaggi
sys.log. Valuta la possibilità di utilizzare il logging delle chiamate invece.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 conteggiate per il limite massimo di passaggi sono classificate nella tabella seguente:
Categoria Operazione Conteggiato come passaggio - Operazioni sui dati: assegnazione, restituzione di valori
- Controllo del flusso: salti (
next), switch, avvio di unforciclo e ogni iterazione di unforciclo - Chiamate: richiamo di
sys.get_envo di un'altra funzione della libreria standard funzione, di un altro workflow o di un connettore - Contemporaneità: 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 conteggiato come passaggio - Lettura e scrittura in
elenchi,
mappe, e
variabili
Sebbene una singola ricerca non aggiunga un passaggio aggiuntivo, un passaggio che contiene la ricerca, ad esempio un
assignpassaggio, viene conteggiato come un passaggio. -
Funzioni helper di 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.