Patrón de coreografía

El patrón coreográfico descentraliza la lógica del flujo de trabajo y distribuye las responsabilidades a otros componentes dentro de un sistema. En lugar de depender de un orquestador central, los servicios deciden cuándo y cómo procesar una operación empresarial.

Contexto y problema

Normalmente, se divide una aplicación basada en la nube en varios servicios pequeños que funcionan conjuntamente para procesar una transacción empresarial de un extremo a otro. Una sola operación dentro de una transacción puede dar lugar a varias llamadas de punto a punto entre todos los servicios. Idealmente, esos servicios están acoplados de forma flexible. Es difícil diseñar un flujo de trabajo distribuido, eficaz y escalable, ya que 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 completa su responsabilidad y no es consciente del flujo de trabajo general.

Diagrama de un flujo de trabajo que usa un orquestador central para procesar solicitudes.

Normalmente, se implementa el patrón de orquestación como software personalizado que tiene conocimiento especializado sobre las responsabilidades de los servicios dentro del sistema. Una ventaja de este enfoque es que el orquestador puede consolidar el estado de una transacción en función de los resultados de las operaciones individuales que realizan los servicios descendentes.

Este enfoque también crea algunos obstáculos. 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 afectar negativamente a la confiabilidad de la carga de trabajo. Bajo carga, puede introducir cuellos de botella de rendimiento y ser el punto único de falla (SPoF). También puede provocar errores en cascada en los servicios descendentes.

Solución

Delegue la lógica de control de transacciones entre los servicios. Permitir que cada servicio participe en el flujo de trabajo de comunicación de una operación empresarial y decida cuándo y cómo procesarlo.

El patrón de coreografía minimiza la dependencia del software personalizado que centraliza el flujo de trabajo de comunicación. Los componentes implementan lógica común a medida que coreografían el flujo de trabajo entre sí sin comunicarse directamente 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 siguiente se muestra el control de solicitudes a través de un modelo de publicador-suscriptor.

Diagrama que muestra cómo un agente de mensajes procesa una solicitud.

  1. El cliente encola solicitudes como mensajes en un intermediario de mensajes.

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

  3. Cada servicio suscrito realiza su operación como indica el mensaje y responde al agente con un mensaje de operación correcta o de error.

  4. Si la operación se realiza correctamente, el servicio puede devolver un mensaje a la misma cola o a una cola de mensajes diferente para que otro servicio pueda continuar 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

Tenga en cuenta los siguientes puntos a medida que decida cómo implementar este patrón:

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 este patrón como un mecanismo de disparar y olvidar, en el que un componente realiza una tarea que no necesita administración activa. Una vez completada la tarea, el componente envía una notificación a los demás componentes.

  • Espera actualizar y reemplazar los componentes con frecuencia. Este patrón le permite modificar la aplicación con menos esfuerzo y una interrupción mínima en 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, el servicio crea componentes que realizan una tarea y el servicio quita los componentes después de completar esa tarea.

  • La comunicación entre contextos limitados requiere un acoplamiento flexible a través de los límites del dominio. Para la comunicación dentro de un único contexto delimitado, utilice un patrón de orquestador.

  • El orquestador central genera un cuello de botella de rendimiento.

Este patrón podría no ser adecuado cuando:

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

  • La comunicación de punto a punto entre los componentes es inevitable.

  • Debe usar la lógica empresarial para consolidar todas las operaciones que manejan los componentes descendentes.

Diseño de cargas de trabajo

Evalúe cómo usar el patrón de coreografía en el diseño de una carga de trabajo para abordar los objetivos y principios descritos en los pilares de Azure Well-Architected Framework. En la tabla siguiente se proporciona una guía sobre cómo este patrón apoya los objetivos de cada pilar.

Fundamento 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. Los componentes distribuidos de este patrón son autónomos y están diseñados para ser reemplazables, por lo que puede modificar la carga de trabajo con menos cambios generales en el sistema.

- OE:04 Herramientas y procesos
Eficiencia del rendimiento ayuda a su carga de trabajo a satisfacer eficientemente 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

Si este patrón introduce concesiones dentro de un pilar, considérelas en relación con los objetivos de los otros pilares.

Ejemplo

En este ejemplo se muestra el patrón de coreografía mediante la creación de una carga de trabajo nativa de la nube controlada por eventos que ejecuta funciones junto con microservicios. Cuando un cliente solicita enviar un paquete, la carga de trabajo asigna un dron. Después de que el paquete esté listo para la recogida por el dron programado, se inicia el proceso de entrega. Mientras el paquete está en tránsito, el sistema de gestión gestiona la entrega hasta que recibe el estado de enviado.

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

El servicio de ingesta recibe solicitudes de cliente y los convierte en mensajes que incluyen los detalles de entrega. Las transacciones empresariales se inician después de que los servicios consuman esos nuevos mensajes.

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

  • Cree o actualice un paquete.

  • Asigne un dron para entregar el paquete.

  • Controle la entrega, incluida la comprobación y el envío de una notificación cuando el paquete se envíe.

Los microservicios de paquete, programador de drones y entrega realizan el procesamiento empresarial. Los servicios usan mensajería en lugar de un orquestador central para comunicarse entre sí. Cada servicio debe implementar un protocolo de antemano que coordina el flujo de trabajo empresarial de forma descentralizada.

Design

Los servicios procesan transacciones empresariales en una secuencia a través de varios saltos. Cada nodo comparte un único bus de mensajes entre todos los servicios de negocio.

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, lo convierte en un mensaje y, a continuación, publica el mensaje en el bus de mensajes compartido. Los servicios empresariales suscritos consumen nuevos mensajes agregados al bus. Cuando un servicio empresarial recibe el mensaje, completa correctamente la operación o se produce un error en la solicitud o se agota el tiempo de espera. Si la solicitud se realiza correctamente, el servicio responde al bus con el Ok código de estado, genera un nuevo mensaje de operación y lo envía al bus de mensajes. Si se produce un error en la solicitud o se agota el tiempo de espera, el servicio notifica el error enviando el código de motivo al bus de mensajes y, a continuación, agrega el mensaje a una cola de mensajes fallidos (DLQ). El servicio también mueve los mensajes que no puede recibir o procesar dentro de un período de tiempo específico al DLQ.

Este diseño usa varios buses de mensajes para procesar toda la transacción empresarial. Azure Service Bus y Azure Event Grid proporcionan la plataforma del servicio de mensajería para este diseño. La carga de trabajo se ejecuta en Azure Container Apps, que hospeda Azure Functions para la ingesta. Container Apps controla el procesamiento controlado por eventos que ejecuta la lógica de negocios.

Este diseño también garantiza que la coreografía se produzca en una secuencia. Un único espacio de nombres de Service Bus contiene un tema que tiene dos suscripciones y una cola sensible a la sesión. El servicio de ingestión publica mensajes en el tópico. El servicio de paquetes y el servicio de programación de drones se suscriben al tópico y publican mensajes que notifican a la cola sobre solicitudes exitosas. Incluya un identificador de sesión común que asocie un GUID con el identificador de entrega para que los servicios puedan gestionar secuencias ilimitadas de mensajes relacionados en orden. El servicio de entrega espera dos mensajes relacionados para cada transacción. El primer mensaje indica que el paquete está listo para enviarse y el segundo mensaje indica que un dron está programado.

En este diseño, Service Bus controla mensajes de alto valor que no se deben perder ni duplicar durante todo el proceso de entrega. Cuando el paquete se distribuye, se publica un cambio de estado en Event Grid. El remitente del evento no tiene ninguna expectativa sobre cómo se controla el cambio de estado. Los servicios de organizaciones descendentes que este diseño no incluye pueden escuchar este tipo de evento y ejecutar lógica empresarial específica, como enviar un correo electrónico con el estado del pedido al usuario.

Si despliegas este patrón en otro servicio de proceso, como AKS, puedes implementar la aplicación boilerplate del patrón publicador-suscriptor con dos contenedores en el mismo pod. Un contenedor ejecuta el embajador que interactúa con el bus de mensajes que elija mientras el otro contenedor ejecuta la lógica de negocios. Este enfoque mejora el rendimiento y la escalabilidad. El embajador y el servicio empresarial comparten la misma red, lo que reduce la latencia y aumenta el rendimiento.

Para evitar operaciones de reintento en cascada que pueden provocar varios intentos, los servicios empresariales deben marcar inmediatamente mensajes inaceptables. Mejorar estos mensajes utilizando códigos de razón comunes o un código de aplicación definido para que los servicios puedan moverlos a un DLQ. Considere implementar el patrón Saga para administrar problemas de coherencia de los servicios aguas abajo. Por ejemplo, otro servicio maneja los mensajes de dead-letter solo con fines de corrección mediante la ejecución de una transacción de compensación, reintento o pivote.

Los servicios empresariales son idempotentes para asegurarse de que las operaciones de reintento no creen recursos duplicados. Por ejemplo, el servicio de paquetes utiliza operaciones upsert para agregar datos al almacén de datos.

Pasos siguientes

Tenga en cuenta estos patrones en el diseño para la coreografía:

  • Modularice el servicio empresarial mediante el patrón Ambassador.

  • Implemente el patrón de nivelación de carga basado en colas para controlar los picos de la carga de trabajo.

  • Use la mensajería distribuida asincrónica a través del patrón Publisher-Subscriber.

  • Use transacciones de compensación para deshacer una serie de operaciones exitosas si una o más operaciones relacionadas fallan.