Compartir a través de


Patrón de coreografía

Azure Event Grid
Azure Service Bus

Descentralice la lógica del flujo de trabajo y distribuya las responsabilidades a otros componentes dentro de un sistema.

Contexto y problema

Una aplicación basada en la nube se suele dividir en varios servicios pequeños que trabajan conjuntamente para procesar una transacción empresarial de un extremo a otro. Incluso una única operación (dentro de una transacción) puede dar lugar a varias llamadas punto a punto entre todos los servicios. Lo ideal sería que esos servicios tuvieran un acoplamiento flexible. Es difícil diseñar un flujo de trabajo distribuido, eficaz y escalable, ya que a menudo implica una comunicación entre servicios compleja.

Un patrón común para la comunicación es usar un servicio centralizado o un orquestador. Las solicitudes entrantes fluyen a través del orquestador a medida que delega las operaciones a los servicios respectivos. Cada servicio se limita a cumplir con su responsabilidad y no es consciente del flujo de trabajo global.

Diagrama de un flujo de trabajo que procesa las solicitudes mediante un orquestador central.

El patrón de orquestador se implementa normalmente como software a medida y tiene conocimiento específico del dominio sobre las responsabilidades de esos servicios. Una ventaja es que el orquestador puede consolidar el estado de una transacción en función de los resultados de las operaciones individuales realizadas por los servicios descendentes.

No obstante, hay algunos inconvenientes. Agregar o quitar servicios puede romper la lógica existente porque hay que reorganizar partes de la ruta de comunicación. Esta dependencia hace que la implementación del orquestador sea compleja y difícil de mantener. El orquestador podría tener un impacto negativo en la fiabilidad de la carga de trabajo. Bajo carga, puede introducir cuellos de botella en el rendimiento y ser el único punto de fallo. También puede provocar errores en cascada en los servicios descendentes.

Solution

Delegue la lógica de control de transacciones entre los servicios. Deje que cada servicio decida y participe en el flujo de trabajo de comunicación para una operación empresarial.

El patrón es una manera de minimizar la dependencia del software personalizado que centraliza el flujo de trabajo de comunicación. Los componentes implementan lógica común a medida que organizan el flujo de trabajo entre sí sin tener comunicación directa entre sí.

Una manera común de implementar la coreografía es usar un agente de mensajes que almacena en búfer las solicitudes hasta que los componentes descendentes las reclaman y procesan. En la imagen se muestra el control de solicitudes a través de un modelo de publicador-suscriptor.

Diagrama que muestra el procesamiento de una solicitud mediante un agente de mensajes.

  1. Las solicitudes de clientes se ponen en cola como mensajes en un broker de mensajes.

  2. Los servicios o el suscriptor sondean al bróker para determinar si pueden procesar ese mensaje en función de su lógica empresarial implementada. El agente también puede enviar mensajes a los suscriptores interesados en ese mensaje.

  3. Cada servicio suscrito realiza su operación como se indica en el mensaje y responde al agente con éxito o error de la operación.

  4. En caso de éxito, el servicio puede volver a insertar un mensaje en la misma cola o en una diferente para que otro servicio pueda continuar con el flujo de trabajo si es necesario. Si la operación falla, el agente de mensajes trabaja con otros servicios para compensar esa operación o toda la transacción.

Problemas y consideraciones

La descentralización del orquestador puede producir problemas mientras administra el flujo de trabajo.

  • El control de errores puede ser difícil. Los componentes de una aplicación pueden realizar tareas atómicas, pero aún así pueden tener un nivel de dependencia. Un error en un componente puede afectar a otros, lo que puede provocar retrasos en completar la solicitud general.

    Para controlar los errores correctamente, la implementación de transacciones de compensación podría presentar complejidad. La lógica de control de errores, como las transacciones compensatorias, también es propensa a errores.

    Diagrama de flujo que muestra la gestión de errores en el patrón de coreografía.

  • El patrón es adecuado para un flujo de trabajo en el que las operaciones empresariales independientes se procesan en paralelo. El flujo de trabajo se puede complicar cuando la coreografía debe ocurrir en una secuencia. Por ejemplo, el servicio D puede iniciar su operación solo después de que el servicio B y el servicio C hayan completado sus operaciones correctamente.

    Diagrama de flujo de trabajo en un sistema de mensajería que implementa el patrón de coreografía en paralelo y posteriormente.

  • El patrón se convierte en un desafío si el número de servicios crece rápidamente. Dado el gran número de elementos móviles independientes, el flujo de trabajo entre servicios tiende a ser complejo. El seguimiento distribuido también resulta difícil, pero las herramientas como ServiceInsight junto con NServiceBus pueden ayudar a reducir estos desafíos.

  • En un diseño liderado por un orquestador, el componente central puede participar parcialmente y delegar la lógica de resiliencia a otro componente que reintenta los errores transitorios, no transitorios y de tiempo de espera, de manera coherente. Con la disolución del orquestador en el patrón de coreografía, los componentes posteriores no deberían asumir esas tareas de resiliencia. El controlador de resiliencia debe gestionar esas tareas. Pero ahora, los componentes aguas abajo deben comunicarse directamente con el gestor de resiliencia, lo que aumenta la comunicación de punto a punto.

Cuándo usar este patrón

Use este patrón en los siguientes supuestos:

  • Los componentes descendentes controlan las operaciones atómicas de forma independiente. Piense en ello como un mecanismo de "apuntar y olvidar". Un componente es responsable de una tarea que no necesita administrarse activamente. Una vez completada la tarea, envía una notificación a los demás componentes.

  • Espera que los componentes se actualicen y reemplacen con frecuencia. El patrón permite modificar la aplicación con menos esfuerzo y una interrupción mínima de los servicios existentes.

  • Puede usar arquitecturas sin servidor para flujos de trabajo simples. Los componentes pueden ser efímeros y estar basados en eventos. Cuando se produce un evento, los componentes se activan, realizan sus tareas y se quitan una vez completada la tarea.

  • La comunicación entre contextos limitados requiere un acoplamiento flexible a través de los límites del dominio. En el caso de las comunicaciones dentro de un único contexto delimitado, aplique un patrón de orquestador en su lugar.

  • Existe un cuello de botella de rendimiento causado por el orquestador central.

Este modelo podría no ser útil en las situaciones siguientes:

  • La aplicación es compleja y requiere un componente central que controle la lógica compartida para mantener ligeros los componentes descendentes.

  • Hay situaciones en las que la comunicación de punto a punto entre los componentes es inevitable.

  • Debe consolidar todas las operaciones que manejan los componentes posteriores mediante la lógica empresarial.

Diseño de cargas de trabajo

Un arquitecto debe evaluar cómo se puede usar el patrón Choreography en el diseño de su carga de trabajo para abordar los objetivos y principios descritos en los pilares del Marco de buena arquitectura de Azure. Por ejemplo:

Pillar Cómo apoya este patrón los objetivos de los pilares
La excelencia operativa ayuda a ofrecer calidad de carga de trabajo a través de procesos estandarizados y cohesión de equipos. Dado que los componentes distribuidos de este patrón son autónomos y están diseñados para poderlos reemplazar, puede modificar la carga de trabajo con menos cambios generales en el sistema.

- OE:04 Herramientas y procesos
La eficiencia del rendimiento ayuda a que la carga de trabajo satisfaga eficazmente las demandas mediante optimizaciones en el escalado, los datos y el código. Este patrón proporciona una alternativa cuando se producen cuellos de botella en el rendimiento de una topología de orquestación centralizada.

- PE:02 Planeamiento de capacidad
- PE:05 Escalado y particionamiento

Al igual que con cualquier decisión de diseño, hay que tener en cuenta las ventajas y desventajas con respecto a los objetivos de los otros pilares que podrían introducirse con este patrón.

Example

En este ejemplo se muestra el patrón de coreografía mediante la creación de funciones de ejecución de cargas de trabajo nativas de la nube controladas por eventos junto con microservicios. Cuando un cliente solicita que se envíe un paquete, la carga de trabajo asigna un dron. Una vez que el paquete está listo para ser recogido por el dron programado, se inicia el proceso de entrega. Mientras está en tránsito, la carga de trabajo gestiona la entrega hasta que adquiere el estado de enviado.

Diagrama de una carga de trabajo nativa de nube controlada por eventos que implementa el patrón de coreografía

El servicio de ingesta controla las solicitudes del cliente y las convierte en mensajes, incluidos los detalles de entrega. Las transacciones empresariales se inician después de consumir esos nuevos mensajes.

Una sola transacción empresarial de cliente requiere tres operaciones empresariales distintas:

  1. Crear o actualizar un paquete
  2. Asignar un dron para entregar el paquete
  3. Gestionar la entrega que implica comprobar e informar sobre el estado cuando el envío se realiza.

Tres microservicios desempeñan el procesamiento empresarial: Servicios de Paquete, Planificador de Drones y Entrega. En lugar de un orquestador central, los servicios usan mensajería para comunicarse entre ellos. Cada servicio sería responsable de implementar un protocolo de antemano que coordine de forma descentralizada el flujo de trabajo empresarial.

Design

La transacción empresarial se procesa en una secuencia a través de varios saltos. Cada salto comparte un bus único de mensajes entre todos los servicios empresariales.

Cuando un cliente envía una solicitud de entrega a través de un punto de conexión HTTP, el servicio de ingesta lo recibe, convierte la solicitud en un mensaje y, a continuación, publica el mensaje en el bus de mensajes compartido. Los servicios empresariales suscritos van a consumir nuevos mensajes añadidos al bus. Al recibir el mensaje, los servicios empresariales pueden completar la operación con éxito, con fallo, o la solicitud puede agotar el tiempo de espera. Si se realiza con éxito, los servicios responden al bus de mensajes con el código de estado Ok, generan un nuevo mensaje de operación y lo envían al bus de mensajes. Si se produce un error o se agota el tiempo de espera, el servicio notifica el error enviando el código de motivo al bus de mensajes. Además, el mensaje se agrega a una cola de mensajes no entregados. Los mensajes que no se pudieron recibir o procesar dentro de un período razonable y adecuado de tiempo también se mueven al DLQ.

El diseño utiliza varios buses de mensajes para procesar toda la transacción empresarial. Microsoft Azure Service Bus y Microsoft Azure Event Grid se crean para proporcionar la plataforma del servicio de mensajería para este diseño. La carga de trabajo se implementa en Azure Container Apps que hospeda Azure Functions para la ingesta y las aplicaciones que controlan el procesamiento controlado por eventos que ejecuta la lógica empresarial.

El diseño garantiza que la coreografía se produzca en una secuencia. Un solo espacio de nombres de Azure Service Bus contiene un tópico con dos suscripciones y una cola con reconocimiento de sesiones. El servicio de incorporación de datos publica mensajes en el tópico. El servicio de gestión de paquetes y el servicio Drone Scheduler se suscriben al tópico y publican mensajes que comunican el éxito en la cola. La inclusión de un identificador de sesión común con un GUID asociado al identificador de entrega permite el control ordenado de secuencias sin enlazar de mensajes relacionados. El servicio de entrega espera dos mensajes relacionados por transacción. El primer mensaje indica que el paquete está listo para enviarse y el segundo indica que se programa un dron.

Este diseño usa Azure Service Bus para controlar mensajes de alto valor que no se pueden perder ni duplicar durante todo el proceso de entrega. Cuando se envía el paquete, también se publica un cambio de estado en Azure Event Grid. En este diseño, el emisor del evento no tiene ninguna expectativa sobre cómo se controla el cambio de estado. Los servicios de organización descendentes que no se incluyen como parte de este diseño podrían estar escuchando este tipo de evento y reaccionar ejecutando lógica de propósito empresarial específica (es decir, enviar por correo electrónico el estado del pedido enviado al usuario).

Si planea implementarlo en otro servicio de proceso, como AKS, el patrón de aplicación pub-sub como base se puede implementar con dos contenedores en el mismo pod. Un contenedor ejecuta el embajador que interactúa con el bus de mensajes de preferencia mientras que el otro ejecuta la lógica empresarial. El enfoque con dos contenedores en el mismo pod mejora el rendimiento y la escalabilidad. El embajador y el servicio empresarial comparten la misma red, lo que permite una baja latencia y un alto rendimiento.

Para evitar las operaciones de reintento en cascada que pueden dar lugar a varios esfuerzos, los servicios empresariales deben marcar inmediatamente los mensajes inaceptables. Es posible enriquecer esos mensajes usando códigos de motivo bien conocidos o un código de aplicación definido, para que pueda moverse a una cola de letras muertas (DLQ). Considere gestionar problemas de coherencia al implementar Saga desde servicios descendentes. Por ejemplo, otro servicio podría controlar los mensajes fallidos con fines de corrección solo mediante la ejecución de una transacción dinámica, de reintento o de compensación.

Los servicios empresariales son idempotentes para evitar que las operaciones de reintento produzcan la creación de recursos duplicados. Por ejemplo, el Servicio de Paquete utiliza operaciones de inserción o actualización para agregar datos al almacén de datos.

Tenga en cuenta estos patrones en su diseño para la coreografía.