Nota
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Hacer que cada servicio decida cuándo y cómo procesar una operación empresarial, en lugar de depender de un orquestador central. Este enfoque descentraliza la lógica del flujo de trabajo y distribuye las responsabilidades entre los componentes de un sistema.
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.
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 provocar cuellos de botella en el rendimiento y convertirse en un punto único de fallo (SPoF). Cuando el orquestador falla o se sobrecarga, el fallo puede propagarse a todos los servicios dependientes aguas abajo.
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.
Las solicitudes de los clientes se ponen en cola como mensajes en un intermediario de mensajes.
Los servicios o el suscriptor consultan al intermediario para determinar si pueden procesar ese mensaje en función de su lógica de negocio implementada. El intermediario también puede enviar mensajes a los suscriptores interesados en ese mensaje.
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.
Si la operación se realiza correctamente, el servicio puede publicar un mensaje en la misma cola o en otra cola de mensajes para que otro servicio pueda continuar el flujo de trabajo si es necesario. Si se produce un error en la operación, el servicio publica un mensaje de error. Los servicios que se suscriben a ese mensaje pueden ejecutar acciones de compensación predefinidas para la operación con error o toda la transacción.
Problemas y consideraciones
Tenga en cuenta los siguientes puntos al decidir cómo implementar este patrón:
Complejidad del control de errores. Los componentes de una aplicación pueden administrar tareas atómicas y depender de otras partes del sistema. Un error en un componente puede afectar a otros componentes, lo que puede provocar retrasos en completar la solicitud general.
Para controlar los errores correctamente, implemente la lógica de control de errores, lo que introduce complejidad. La lógica de control de errores, como la compensación de transacciones, también es propensa a errores.
Procesos secuenciales. Este patrón se adapta a un flujo de trabajo que procesa operaciones empresariales independientes en paralelo. El flujo de trabajo se puede complicar cuando la coreografía debe ocurrir en una secuencia. Por ejemplo, el servicio D solo puede iniciar su operación después de que el servicio B y el servicio C completen correctamente sus operaciones.
Observabilidad a escala. Este patrón presenta desafíos si el número de servicios crece rápidamente. Muchas partes móviles independientes complican el flujo de trabajo entre los servicios. Sin un coordinador central que mantenga el estado completo de la transacción, ningún componente por sí solo tiene una visión completa de una operación empresarial en curso. Debe usar de forma coherente los identificadores de seguimiento y correlación distribuidos para mantener la observabilidad.
Comunicación del manejador de resiliencia. En un diseño basado en un orquestador, el componente central puede delegar responsabilidades de resiliencia, como la gestión de reintentos para fallos transitorios, no transitorios y por tiempo de espera, en un manejador de resiliencia dedicado.
Al eliminar el orquestador en un diseño basado en coreografía, los componentes posteriores no asumen responsabilidades de resiliencia. Estas permanecen centralizadas en el gestor de resiliencia. Pero los componentes posteriores deben comunicarse directamente con ese gestor, lo que aumenta las comunicaciones punto a punto.
Evolución del esquema de eventos. La evolución del esquema de eventos puede provocar cambios importantes en los consumidores a lo largo del tiempo. En este patrón, varios servicios independientes consumen los mismos eventos. Si un productor cambia la estructura de datos de un evento, puede afectar a los consumidores finales que dependen del esquema anterior. Utilice un registro de esquemas para gestionar los contratos de eventos y aplicar la evolución compatible hacia atrás a medida que los servicios evolucionan de forma independiente.
Idempotencia y ordenación de eventos. La entrega al menos una vez y los reintentos pueden generar mensajes duplicados, y los consumidores concurrentes pueden procesar los mensajes fuera de orden. Diseñe los consumidores para que sean idempotentes mediante el seguimiento de identificadores de mensajes estables. Cuando se requiera un procesamiento ordenado, utiliza características del intermediario como las sesiones de Service Bus o incluye datos de secuencia o versión que permitan a los consumidores rechazar eventos obsoletos y detectar lagunas.
Publicación atómica de estados y eventos. Un servicio que actualiza su almacén de datos y publica un evento en operaciones separadas puede confirmar una operación mientras que la otra falla. Utiliza el patrón Transactional Outbox o un mecanismo atómico equivalente para persistir el cambio de estado y el evento juntos antes de que un proceso independiente publique el evento.
Comportamiento emergente y tormentas de eventos. Las topologías de eventos descentralizados pueden crear un comportamiento emergente a escala. Cuando muchos servicios reaccionan a los eventos entre sí, el sistema puede generar involuntariamente bucles de retroalimentación o tormentas de eventos. Un evento menor podría desencadenar una cascada de reacciones descendentes. Para evitar cadenas circulares de eventos, utilice medidas de protección como el filtrado de eventos, los límites de concurrencia de los consumidores, la limitación de tráfico y las reglas explícitas.
Cuándo usar este patrón
Use este patrón en los siguientes supuestos:
Los componentes posteriores administran las operaciones atómicas de forma independiente siguiendo un enfoque disparar y olvidar. Cada componente completa una tarea y, a continuación, señala la finalización a otros componentes a través del agente de mensajes. El servicio iniciador no administra ni realiza un seguimiento activo de la tarea después de enviarlo, pero los servicios de bajada siguen comunicando los resultados a través de eventos.
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, considere en su lugar un patrón de orquestación, según la complejidad y las preferencias del equipo.
El orquestador central introduce un cuello de botella en el 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 |
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.
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, la carga de trabajo se encarga de la entrega hasta que recibe el estado enviado. Para obtener la arquitectura de referencia completa, consulte Microservicios con Azure Container Apps.
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 salto comparte un único bus 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, 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 la solicitud falla o se agota el tiempo de espera, el servicio comunica el código de motivo del fallo al bus de mensajes y envía el mensaje a la cola de mensajes no entregados a través de Azure Service Bus. El servicio también envía a la cola de mensajes no entregados aquellos que no puede recibir o procesar en un plazo de tiempo específico.
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. El servicio de ingesta se ejecuta como una función de Azure hospedada en Container Apps, mientras que el paquete, el programador de drones y los servicios de entrega se ejecutan como microservicios en el mismo entorno de Container Apps. 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 con reconocimiento de sesión. El servicio de ingesta publica mensajes en el tema. El servicio de paquetes y el servicio de programación de drones se suscriben al tema y publican mensajes que notifican a la cola las solicitudes completadas con éxito. Incluya un identificador de sesión común que asocie un GUID con el identificador de entrega para que el servicio de entrega pueda correlacionar los dos mensajes que necesita para cada transacción. Un mensaje confirma que el paquete está listo, el otro mensaje confirma que se programa un dron. Sin esta correlación basada en sesión, el servicio de entrega no tiene forma de asociar mensajes relacionados entre saltos independientes, ya que ningún coordinador central realiza un seguimiento del estado de la transacción. 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 se implementa este patrón en otro servicio de proceso, como AKS, se puede implementar un embajador como sidecar en el mismo pod que la aplicación empresarial. La colocalización minimiza la latencia de la comunicación, pero el proxy añade una sobrecarga de procesamiento y recursos, y se escala con la aplicación. Use este enfoque cuando necesite problemas de conectividad independientes del lenguaje que la plataforma no proporcione.
Para evitar operaciones de reintento en cascada que pueden provocar varios intentos, los servicios empresariales deben marcar inmediatamente mensajes inaceptables. Enriquece estos mensajes utilizando códigos de motivo comunes o un código de aplicación definido, de modo que los servicios puedan trasladarlos a una DLQ. Considere implementar el patrón Saga para administrar problemas de coherencia de los servicios aguas abajo. Por ejemplo, otro servicio administra los mensajes de carta muerta con fines de corrección, ejecutando únicamente 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.
Paso siguiente
- Revise las opciones de mensajería asincrónica en Azure para obtener información sobre las distintas opciones de infraestructura disponibles para implementar un flujo de trabajo descentralizado.
Recursos relacionados
Tenga en cuenta estos patrones en el diseño para la coreografía:
Utilice el patrón Ambassador para modularizar la comunicación de los servicios empresariales con el bus de mensajes.
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.