Modello di orchestrazione saga - AWS Guida prescrittiva

Le traduzioni sono generate tramite traduzione automatica. In caso di conflitto tra il contenuto di una traduzione e la versione originale in Inglese, quest'ultima prevarrà.

Modello di orchestrazione saga

Intento

Il modello di orchestrazione saga utilizza un coordinatore centrale (orchestratore) per aiutare a preservare l'integrità dei dati nelle transazioni distribuite che si estendono su più servizi. In una transazione distribuita, è possibile chiamare più servizi prima del completamento di una transazione. Quando i servizi archiviano i dati in datastore diversi, può essere difficile mantenere la coerenza dei dati tra questi.

Motivazione

Una transazione è una singola unità di lavoro che può comportare più passaggi, in cui tutti i passaggi vengono eseguiti completamente o non viene eseguito alcun passaggio, con il risultato di un datastore che mantiene lo stato coerente. I termini atomicità, consistenza, isolamento e durabilità (ACID) definiscono le proprietà di una transazione. I database relazionali forniscono transazioni ACID per mantenere la coerenza dei dati.

Per mantenere la coerenza in una transazione, i database relazionali utilizzano il metodo di commit a due fasi (2PC). Tale metodo consiste in una fase di preparazione e una fase di commit.

  • Nella fase di preparazione, il processo di coordinamento richiede che i processi partecipanti alla transazione (partecipanti) si impegnino a confermare o annullare la transazione.

  • Nella fase di commit, il processo di coordinamento richiede ai partecipanti di confermare la transazione. Se i partecipanti non riescono ad accettare di impegnarsi nella fase di preparazione, la transazione viene annullata.

Nei sistemi distribuiti che seguono uno schema di database-per-service progettazione, il commit in due fasi non è un'opzione. Questo perché ogni transazione è distribuita su diversi database e non esiste un unico controller in grado di coordinare un processo simile al commit in due fasi nei datastore relazionali. In questo caso, una soluzione consiste nell'utilizzare il modello di orchestrazione saga.

Applicabilità

Usa il modello di orchestrazione saga quando:

  • Il sistema richiede l'integrità e la coerenza dei dati nelle transazioni distribuite che si estendono su più datastore.

  • Il datastore non fornisce 2PC per fornire transazioni ACID e implementare 2PC entro i confini dell'applicazione è un'attività complessa.

  • Disponi di database NoSQL, che non forniscono transazioni ACID, e devi aggiornare più tabelle all'interno di una singola transazione.

Problemi e considerazioni

  • Complessità: le transazioni compensative e i nuovi tentativi aggiungono complessità al codice dell'applicazione, il che può comportare costi di manutenzione.

  • Coerenza finale: l'elaborazione sequenziale delle transazioni locali si traduce in una coerenza finale, il che può rappresentare una sfida nei sistemi che richiedono una forte coerenza. È possibile risolvere questo problema impostando le aspettative dei team aziendali in merito al modello di consistenza o passando a un datastore che garantisca una forte coerenza.

  • Idempotenza: i partecipanti a saga devono essere idempotenti per consentire l'esecuzione ripetuta in caso di guasti transitori causati da arresti imprevisti e guasti dell'orchestratore.

  • Isolamento delle transazioni: la saga non dispone dell'isolamento delle transazioni. L'orchestrazione simultanea delle transazioni può portare a dati obsoleti. Consigliamo di utilizzare il blocco semantico per gestire tali scenari.

  • Osservabilità: l'osservabilità si riferisce alla registrazione e al tracciamento dettagliati per risolvere i problemi durante il processo di esecuzione e orchestrazione. Ciò diventa importante quando il numero di partecipanti alla saga aumenta, con conseguenti complessità nel debug.

  • Problemi di latenza: le transazioni compensative possono aggiungere latenza al tempo di risposta complessivo quando la saga è composta da più passaggi. In questi casi, evita le chiamate sincrone.

  • Singolo punto di errore: l'orchestratore può diventare un singolo punto di errore perché coordina l'intera transazione. In alcuni casi, a causa di questo problema, si preferisce il modello coreografico della saga.

Implementazione

Architettura di alto livello

Nel seguente diagramma di architettura, l'orchestratore saga ha tre partecipanti: il servizio ordini, il servizio di inventario e il servizio di pagamento. Per completare la transazione sono necessari tre passaggi: T1, T2 e T3. L'orchestratore saga conosce i passaggi e li esegue nell'ordine richiesto. Quando la fase T3 non riesce (errore di pagamento), l'orchestratore esegue le transazioni compensative C1 e C2 per ripristinare i dati allo stato iniziale.

Architettura di alto livello dell'orchestratore saga

Puoi usare AWS Step Functions per implementare l'orchestrazione saga quando la transazione viene distribuita su più database.

Implementazione tramite servizi AWS

La soluzione di esempio utilizza il flusso di lavoro standard di Step Functions per implementare il modello di orchestrazione saga.

Implementazione del flusso di lavoro saga con Step Functions

Quando un cliente chiama l'API, viene richiamata la funzione Lambda, dove avviene la fase di pre-elaborazione. La funzione avvia il flusso di lavoro Step Functions per avviare l'elaborazione della transazione distribuita. Se la pre-elaborazione non è richiesta, puoi avviare il flusso di lavoro Step Functions direttamente da Gateway API senza utilizzare la funzione Lambda.

L'uso di Step Functions mitiga il problema del singolo punto di errore, relativo all'implementazione del modello di orchestrazione saga. Step Functions ha una tolleranza agli errori integrata e mantiene la capacità di servizio in più zone di disponibilità in ogni Regione AWS per proteggere le applicazioni dai guasti di singoli computer o data center. Ciò contribuisce a garantire un'elevata disponibilità sia per il servizio stesso che per il flusso di lavoro dell'applicazione su cui opera.

Il flusso di lavoro Step Functions

La macchina a stati Step Functions consente di configurare i requisiti del flusso di controllo basato sulle decisioni per l'implementazione del modello. Il flusso di lavoro Step Functions richiama i singoli servizi per l'inserimento degli ordini, l'aggiornamento dell'inventario e l'elaborazione dei pagamenti per completare la transazione e invia una notifica dell'evento per un'ulteriore elaborazione. Il flusso di lavoro Step Functions funge da orchestratore per coordinare le transazioni. Se il flusso di lavoro contiene errori, l'orchestratore esegue le transazioni compensative per garantire che l'integrità dei dati sia mantenuta tra i servizi.

Il seguente diagramma mostra i passaggi eseguiti all'interno del flusso di lavoro Step Functions. I passaggi Place Order, Update Inventory e Make Payment indicano il percorso riuscito. L'ordine viene effettuato, l'inventario viene aggiornato e il pagamento viene elaborato prima che al chiamante venga restituito lo stato Success.

Le funzioni Lambda Revert Payment, Revert Inventory e Remove Order indicano le transazioni compensative che l'orchestratore esegue quando una qualsiasi fase del flusso di lavoro non riesce. Se il flusso di lavoro fallisce durante la fase Update Inventory, l'orchestratore chiama le fasi Revert Inventory e Remove Order prima di restituire uno stato Fail al chiamante. Queste transazioni compensative garantiscono il mantenimento dell'integrità dei dati. L'inventario torna al livello originale e l'ordine viene ripristinato.

Flusso di lavoro Step Functions per la saga

Codice di esempio

Il seguente codice di esempio mostra come è possibile creare un orchestratore saga utilizzando Step Functions. Per visualizzare il codice completo, consultate il GitHubrepository di questo esempio.

Definizioni di processi

var successState = new Succeed(this,"SuccessState"); var failState = new Fail(this, "Fail"); var placeOrderTask = new LambdaInvoke(this, "Place Order", new LambdaInvokeProps { LambdaFunction = placeOrderLambda, Comment = "Place Order", RetryOnServiceExceptions = false, PayloadResponseOnly = true }); var updateInventoryTask = new LambdaInvoke(this,"Update Inventory", new LambdaInvokeProps { LambdaFunction = updateInventoryLambda, Comment = "Update inventory", RetryOnServiceExceptions = false, PayloadResponseOnly = true }); var makePaymentTask = new LambdaInvoke(this,"Make Payment", new LambdaInvokeProps { LambdaFunction = makePaymentLambda, Comment = "Make Payment", RetryOnServiceExceptions = false, PayloadResponseOnly = true }); var removeOrderTask = new LambdaInvoke(this, "Remove Order", new LambdaInvokeProps { LambdaFunction = removeOrderLambda, Comment = "Remove Order", RetryOnServiceExceptions = false, PayloadResponseOnly = true }).Next(failState); var revertInventoryTask = new LambdaInvoke(this,"Revert Inventory", new LambdaInvokeProps { LambdaFunction = revertInventoryLambda, Comment = "Revert inventory", RetryOnServiceExceptions = false, PayloadResponseOnly = true }).Next(removeOrderTask); var revertPaymentTask = new LambdaInvoke(this,"Revert Payment", new LambdaInvokeProps { LambdaFunction = revertPaymentLambda, Comment = "Revert Payment", RetryOnServiceExceptions = false, PayloadResponseOnly = true }).Next(revertInventoryTask); var waitState = new Wait(this, "Wait state", new WaitProps { Time = WaitTime.Duration(Duration.Seconds(30)) }).Next(revertInventoryTask);

Step Functions e definizioni macchine a stati

var stepDefinition = placeOrderTask .Next(new Choice(this, "Is order placed") .When(Condition.StringEquals("$.Status", "ORDER_PLACED"), updateInventoryTask .Next(new Choice(this, "Is inventory updated") .When(Condition.StringEquals("$.Status", "INVENTORY_UPDATED"), makePaymentTask.Next(new Choice(this, "Is payment success") .When(Condition.StringEquals("$.Status", "PAYMENT_COMPLETED"), successState) .When(Condition.StringEquals("$.Status", "ERROR"), revertPaymentTask))) .When(Condition.StringEquals("$.Status", "ERROR"), waitState))) .When(Condition.StringEquals("$.Status", "ERROR"), failState)); var stateMachine = new StateMachine(this, "DistributedTransactionOrchestrator", new StateMachineProps { StateMachineName = "DistributedTransactionOrchestrator", StateMachineType = StateMachineType.STANDARD, Role = iamStepFunctionRole, TracingEnabled = true, Definition = stepDefinition });

GitHub repository

Per un'implementazione completa dell'architettura di esempio per questo pattern, consultate il GitHub repository all'indirizzo https://github.com/aws-samples/. saga-orchestration-netcore-blog

Riferimenti del blog

Contenuti correlati

Video

Il video seguente illustra come implementare il pattern di orchestrazione della saga utilizzando. AWS Step Functions