Las traducciones son generadas a través de traducción automática. En caso de conflicto entre la traducción y la version original de inglés, prevalecerá la version en inglés.
Patrón de orquestación de la saga
Intención
El patrón de orquestación de la saga utiliza un coordinador central (orquestador) para ayudar a preservar la integridad de los datos en las transacciones distribuidas que abarcan varios servicios. En una transacción distribuida, se puede llamar a varios servicios antes de que se complete la transacción. Cuando los servicios almacenan datos en diferentes almacenes de datos, puede resultar difícil mantener la coherencia de datos entre estos almacenes de datos.
Motivación
Una transacción es una sola unidad de trabajo que puede implicar varios pasos, donde todos los pasos se ejecutan por completo o no se ejecuta ningún paso, lo que da como resultado un almacén de datos que conserva su estado coherente. Los términos atomicidad, coherencia, aislamiento y durabilidad (ACID, por sus siglas en inglés) definen las propiedades de una transacción. Las bases de datos relacionales proporcionan transacciones ACID para mantener la coherencia de datos.
Para mantener la coherencia en una transacción, las bases de datos relacionales utilizan el método de confirmación en dos fases (2PC). Consiste en una fase de preparación y una fase de confirmación.
-
En la fase de preparación, el proceso de coordinación solicita a los procesos participantes en la transacción (participantes) que se comprometan a confirmar o anular la transacción.
-
En la fase de confirmación, el proceso de coordinación solicita a los participantes que confirmen la transacción. Si los participantes no pueden ponerse de acuerdo para realizar la confirmación en la fase de preparación, la transacción se anula.
En los sistemas distribuidos que siguen un patrón de database-per-service diseño, la confirmación en dos fases no es una opción. Esto se debe a que cada transacción se distribuye en varias bases de datos y no existe un único controlador que pueda coordinar un proceso similar a la confirmación en dos fases de los almacenes de datos relacionales. En este caso, una solución es utilizar el patrón de orquestación de la saga.
Aplicabilidad
Use el patrón de orquestación de la saga cuando:
-
El sistema requiere integridad y coherencia de los datos en las transacciones distribuidas que abarcan varios almacenes de datos.
-
El almacén de datos no proporciona la confirmación en dos fases para proporcionar transacciones ACID, y la implementación de la confirmación en dos fases dentro de los límites de las aplicaciones es una tarea compleja.
-
Tiene bases de datos NoSQL, que no proporcionan transacciones ACID, y necesita actualizar varias tablas dentro de una sola transacción.
Problemas y consideraciones
-
Complejidad: las transacciones y los reintentos de compensación agregan complejidad al código de la aplicación, lo que puede provocar una sobrecarga de mantenimiento.
-
Coherencia final: el procesamiento secuencial de las transacciones locales da como resultado una coherencia final, lo que puede ser un desafío en los sistemas que requieren una gran coherencia. Para abordar este problema, establezca las expectativas de sus equipos empresariales con respecto al modelo de coherencia o cambie a un almacén de datos que ofrezca una coherencia sólida.
-
Idempotencia: los participantes de la saga tienen que ser idempotentes para permitir la ejecución repetida en caso de que se produzcan errores transitorios provocados por bloqueos inesperados o errores del orquestador.
-
Aislamiento de transacciones: la saga carece de aislamiento de transacciones. La orquestación simultánea de las transacciones puede provocar datos obsoletos. Recomendamos utilizar el bloqueo semántico para gestionar estos escenarios.
-
Observabilidad: la observabilidad se refiere al registro y el seguimiento detallados para solucionar problemas en el proceso de ejecución y orquestación. Esto se vuelve importante cuando aumenta el número de participantes de la saga, lo que dificulta la depuración.
-
Problemas de latencia: las transacciones compensatorias pueden agregar latencia al tiempo de respuesta total cuando la saga consta de varios pasos. Evite las llamadas sincrónicas en estos casos.
-
Punto único de error: el orquestador puede convertirse en un punto único de error porque coordina toda la transacción. En algunos casos, se prefiere el patrón de coreografía de la saga debido a este problema.
Implementación
Arquitectura de alto nivel
En el siguiente diagrama de arquitectura, la orquestador de la saga tiene tres participantes: el servicio de pedidos, el servicio de inventario y el servicio de pago. Se requieren tres pasos para completar la transacción: T1, T2 y T3. El orquestador de la saga conoce los pasos y los ejecuta en el orden requerido. Cuando se produce un error en el paso T3 (falta de pago), el orquestador ejecuta las transacciones de compensación C1 y C2 para restaurar los datos al estado inicial.
Puede utilizar AWS Step Functions
Implementación mediante los servicios de AWS
La solución de ejemplo utiliza el flujo de trabajo estándar de Step Functions para implementar el patrón de orquestación de la saga.
Cuando un cliente llama a la API, se invoca la función de Lambda y el preprocesamiento se realiza en la función de Lambda. La función inicia el flujo de trabajo de Step Functions para empezar a procesar la transacción distribuida. Si no es necesario preprocesar, puede iniciar el flujo de trabajo de Step Functions directamente
El uso de Step Functions mitiga el problema del punto único de error, que es inherente a la implementación del patrón de orquestación de la saga. Step Functions tiene una tolerancia a errores integrada y mantiene la capacidad de servicio en varias zonas de disponibilidad de cada región de AWS para proteger las aplicaciones contra los errores de máquinas individuales o del centro de datos. Esto ayuda a garantizar una alta disponibilidad tanto para el servicio en sí como para el flujo de trabajo de la aplicación que opera.
Flujo de trabajo de Step Functions
La máquina de estados de Step Functions le permite configurar los requisitos de flujo de control basados en decisiones para la implementación del patrón. El flujo de trabajo de Step Functions llama a los servicios individuales de realización de pedidos, actualización del inventario y procesamiento de pagos para completar la transacción y envía una notificación de evento para su posterior procesamiento. El flujo de trabajo de Step Functions actúa como el orquestador para coordinar las transacciones. Si el flujo de trabajo contiene algún error, el orquestador ejecuta las transacciones compensatorias para garantizar que la integridad de los datos se mantenga en todos los servicios.
En el siguiente diagrama se muestran los pasos que se ejecutan en el flujo de trabajo de Step Functions. Los pasos Place Order
, Update Inventory
y Make Payment
indican la ruta correcta. Se realiza el pedido, se actualiza el inventario y se procesa el pago antes de que se devuelva el estado Success
al intermediario.
Las funciones de Lambda Revert Payment
, Revert Inventory
y Remove
Order
indican las transacciones compensatorias que el orquestador ejecuta cuando se produce un error en algún paso del flujo de trabajo. Si se produce un error en el flujo de trabajo en el paso Update Inventory
, el orquestador llama a los pasos Revert
Inventory
y Remove Order
antes de devolver el estado Fail
al intermediario. Estas transacciones compensatorias garantizan que se mantenga la integridad de los datos. El inventario vuelve a su nivel original y el pedido se revierte.
Código de muestra
El siguiente código de ejemplo muestra cómo puede crear un orquestador de saga mediante Step Functions. Para ver el código completo, consulta el GitHubrepositorio
Definiciones de tareas
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);
Definiciones de función de paso y máquina de estados
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 repositorio
Para obtener una implementación completa de la arquitectura de ejemplo para este patrón, consulte el GitHub repositorio en https://github.com/aws-samples/ saga-orchestration-netcore-blog
Referencias de blogs
Contenido relacionado
Videos
El siguiente vídeo explica cómo implementar el patrón de orquestación de la saga mediante el uso AWS Step Functions de.