El patrón SAGA es un patrón de diseño utilizado en la arquitectura de microservicios para gestionar transacciones complejas que involucran múltiples servicios. En una arquitectura de microservicios, cada servicio es responsable de sus propios datos y realiza una función empresarial específica. Sin embargo, hay algunas transacciones que requieren coordinación entre múltiples servicios, lo que puede resultar difícil de gestionar.

El patrón SAGA es un enfoque para gestionar transacciones distribuidas que implica dividir la transacción en una serie de transacciones individuales más pequeñas, cada una de las cuales es manejada por un microservicio diferente. Cada transacción individual se ejecuta en un orden específico y los resultados se almacenan en un repositorio central.

El nombre SAGA significa “Saga de Transacciones”. Una saga es una secuencia de transacciones locales, donde cada transacción local actualiza los datos dentro de un único servicio y un coordinador gestiona el flujo general de la saga. El coordinador es responsable de asegurarse de que cada paso de la saga se ejecute en el orden correcto y de manejar cualquier error que pueda ocurrir.

El patrón SAGA utiliza un mecanismo de transacción de compensación para manejar los errores que pueden ocurrir durante la ejecución de la saga. Si ocurre un error durante una de las transacciones locales, la transacción de compensación se ejecuta para deshacer los cambios realizados por las transacciones locales anteriores. Esto garantiza que el sistema permanezca en un estado consistente incluso si falla una transacción.

El patrón SAGA es un enfoque útil para gestionar transacciones distribuidas complejas en arquitectura de microservicios. Permite una mayor flexibilidad y escalabilidad al dividir la transacción en pasos más pequeños y manejables, y proporciona un mecanismo para manejar errores y mantener la coherencia de los datos. Sin embargo, también puede agregar complejidad al sistema y requiere una coordinación cuidadosa entre los servicios. Por lo tanto, debe utilizarse con prudencia y sólo para transacciones que realmente lo requieran.

Tipo de patrones SAGA:

Hay dos tipos principales de patrones SAGA comúnmente utilizados en la arquitectura de microservicios: los basados ​​en coreografía y los basados ​​en orquestación.

Patrón SAGA basado en coreografía: en un patrón SAGA basado en coreografía, cada servicio en la transacción se comunica con otros servicios directamente para coordinar sus acciones. No existe un coordinador central o controlador para gestionar la transacción. En cambio, cada servicio publica eventos para notificar a otros servicios sobre sus acciones y se suscribe a eventos para recibir notificaciones de otros servicios. De esta manera, cada servicio sabe qué acciones tomar en función de los eventos que recibe de otros servicios. Patrón SAGA basado en orquestación: En un patrón SAGA basado en orquestación, un coordinador central o servicio de controlador gestiona la transacción. El coordinador envía mensajes a cada servicio para indicarle qué acciones tomar y en qué orden. El coordinador es responsable de gestionar el flujo de la transacción y coordinar la ejecución de cada paso de la saga.

Tanto los patrones SAGA basados ​​en coreografía como en orquestación tienen sus propias ventajas y desventajas. Los patrones SAGA basados ​​en coreografías están más descentralizados, ya que no hay un coordinador central y los servicios pueden actuar de forma independiente, lo que hace que el sistema sea más escalable. Sin embargo, puede resultar más complejo de gestionar y depurar, ya que puede resultar difícil determinar el orden de los eventos y qué servicio es responsable de cada acción. Los patrones SAGA basados ​​en orquestación están más centralizados, lo que facilita la gestión y coordinación de la transacción. Sin embargo, puede ser menos flexible, ya que cualquier cambio en la transacción requiere cambios en el coordinador y puede convertirse en un cuello de botella a medida que el sistema escala.

En la práctica, la elección entre los dos patrones SAGA depende de los requisitos específicos de la transacción y de la arquitectura del sistema.

Patrón de coreografía:

El patrón de coreografía es una forma de coordinar el comportamiento de múltiples microservicios sin el uso de un orquestador centralizado. En cambio, cada microservicio es responsable de realizar sus propias acciones en función de los mensajes recibidos de otros microservicios.

En el contexto de una arquitectura de microservicios Spring Boot que utiliza Kafka, el patrón de coreografía se puede implementar haciendo que cada microservicio publique mensajes en temas de Kafka cuando ocurren ciertos eventos y haciendo que otros microservicios consuman estos mensajes para realizar sus propias acciones.

Digamos que tenemos dos microservicios: OrderService e InventoryService. Cuando se crea un nuevo pedido en OrderService, queremos que se notifique a InventoryService para que pueda ajustar sus niveles de inventario. Así es como podríamos implementar esto usando el patrón de coreografía con Kafka:

OrderService publica un mensaje en un tema de Kafka llamado pedido creado con detalles sobre el nuevo pedido.// ServicioPedido.java

@Servicio
servicio de pedido de clase pública {

KafkaTemplate final privado kafkaTemplate;

servicio de pedido público (KafkaTemplate kafkaTemplate) {
this.kafkaTemplate = kafkaTemplate;
}

@Transaccional
Orden pública createOrder(Orden de pedido) {
// Guarda el pedido en la base de datos.
Orden guardadaOrder = orderRepository.save(orden);

// Publicar un mensaje en Kafka para notificar al InventoryService
kafkaTemplate.send(“pedido creado”, saveOrder.getId(), saveOrder);

devolver orden guardada;
}
}

En esta implementación, el método createOrder está marcado como @Transactional para garantizar que el pedido se guarde en la base de datos antes de que se publique el mensaje de Kafka. Esto ayuda a mantener la coherencia de los datos en caso de fallas durante la transacción.

2. InventoryService escucha mensajes sobre el tema creado por el pedido y actualiza sus niveles de inventario en función de los detalles del pedido.

// Servicio de inventario.java

@Servicio
servicio de inventario de clase pública {

@KafkaListener(temas = “pedido creado”)
@Transaccional
handleOrderCreated public void(@orden de pedido de carga útil) {
// Actualiza los niveles de inventario según los detalles del pedido.
para (artículo de artículo de pedido: pedido.getItems()) {
Producto producto = productService.getProductById(item.getProductId());
product.setInventory(product.getInventory() – item.getQuantity());
productService.saveProduct(producto);
}
}
}

En esta implementación, el método handleOrderCreated también está marcado como @Transactional para garantizar que los niveles de inventario se actualicen atómicamente con las actualizaciones de la base de datos. En este ejemplo, asumimos que ProductService es responsable de gestionar los productos y sus niveles de inventario.

Tenga en cuenta que tanto el método createOrder como el handleOrderCreated son transaccionales, lo que garantiza que las actualizaciones de la base de datos y la publicación de mensajes de Kafka sean atómicas y coherentes. Esto es importante en las transacciones distribuidas para mantener la coherencia de los datos en todos los microservicios.

Aquí, OrderService e InventoryService están completamente desacoplados entre sí. OrderService no necesita saber nada sobre InventoryService, e InventoryService no necesita saber nada sobre OrderService. En cambio, se comunican entre sí indirectamente a través de mensajes Kafka.

Este enfoque tiene varios beneficios, que incluyen:

Acoplamiento flexible: cada microservicio es responsable de su propio comportamiento y no necesita saber nada sobre el funcionamiento interno de otros microservicios. Escalabilidad: Kafka proporciona una infraestructura de mensajería escalable y tolerante a fallas que puede manejar grandes volúmenes de mensajes. Flexibilidad: Los mismos mensajes pueden ser consumidos por múltiples microservicios, lo que permite un enrutamiento de mensajes flexible y dinámico.

Patrón de orquestación:

Primero, crearemos tres servicios Spring Boot:

Servicio de gestión de pedidosServicio de pagoServicio de cumplimiento de pedidos

También crearemos un tema de Kafka llamado “eventos de pedido” para la comunicación entre los servicios.

Este servicio es responsable de crear nuevos pedidos y publicar un evento de “pedido creado” en el tema de Kafka “eventos de pedido”.

@Servicio
servicio de pedido de clase pública {

@autocableado
private KafkaTemplate kafkaTemplate;

public void createOrder (orden de pedido) {
//guarda el pedido en la base de datos
Orden guardadaOrder = orderRepository.save(orden);

// publica un evento de “pedido creado” en Kafka
kafkaTemplate.send(“eventos de pedido”, “pedido creado”, pedido guardado);
}

}

Este servicio es responsable de procesar pagos y publicar un evento de “pago procesado” en el tema de Kafka “eventos de pedido”.

@Servicio
Servicio de pago de clase pública {

@KafkaListener(temas = “eventos-pedido”, groupId = “servicio-pago”)
handleOrderCreatedEvent público vacío (orden de pedido) {
//procesar el pago
pago booleanoSuccessful = pagoProcesador.procesoPago(orden);

// publicar un evento de “pago procesado” en Kafka
si (pago exitoso) {
kafkaTemplate.send(“evento-pedido”, “pago-procesado”, pedido);
}
}

}

Este servicio se encarga de coordinar la interacción entre los servicios de gestión de pedidos y de pago. Escucha los eventos de “pedido creado” y “pago procesado” del tema de Kafka “evento-pedido” y publica un evento de “pedido cumplido” en el tema cuando se han recibido ambos eventos.

@Servicio
clase pública OrderFulfillmentService {

@KafkaListener(temas = “eventos-pedido”, groupId = “servicio-cumplimiento-pedido”)
handleOrderCreatedEvent público vacío (orden de pedido) {
//guarda el pedido en la base de datos
Orden guardadaOrder = orderRepository.save(orden);

// comprobar si el pago ha sido procesado
si (pagoRepository.existsById(order.getId())) {
// el pago ya ha sido procesado, así que publique un evento de “pedido cumplido” en Kafka
kafkaTemplate.send(“eventos de pedido”, “pedido cumplido”, pedido guardado);
}
}

@KafkaListener(temas = “eventos-pedido”, groupId = “servicio-cumplimiento-pedido”)
handlePaymentProcessedEvent público vacío (orden de pedido) {
//guarda el pago en la base de datos
pagoRepository.save(order.getId());

//comprobar si el pedido ya ha sido creado
si (orderRepository.existsById(order.getId())) {
// el pedido ya ha sido creado, así que publique un evento de “pedido cumplido” en Kafka
kafkaTemplate.send(“evento-pedido”, “pedido-cumplido”, pedido);
}
}

}

En este ejemplo, el Servicio de gestión de pedidos publica un evento de “pedido creado” en Kafka cuando se crea un nuevo pedido. El Servicio de Pago escucha este evento, procesa el pago y publica un evento de “pago procesado” en Kafka si el pago se realizó correctamente. El Servicio de cumplimiento de pedidos escucha ambos eventos y coordina la interacción entre los servicios guardando el pedido y el pago en la base de datos y publicando un evento de “pedido cumplido” en Kafka cuando se hayan recibido ambos eventos.

Diferencias entre patrones de coreografía y orquestación:

Aquí hay una comparación entre el patrón de coreografía y el patrón de orquestación:

El patrón de coreografía y el patrón de orquestación son dos enfoques diferentes para coordinar sistemas distribuidos en la arquitectura de microservicios. Si bien ambos patrones apuntan a lograr el mismo objetivo de gestionar transacciones complejas que involucran múltiples servicios, difieren en la forma en que logran este objetivo. Estas son las diferencias clave entre el patrón de coreografía y el patrón de orquestación:

Control: En el patrón de coreografía, cada servicio se comunica con otros servicios directamente para coordinar sus acciones. No existe un controlador o coordinador central. Cada servicio publica eventos para notificar a otros servicios sobre sus acciones y se suscribe a eventos para recibir notificaciones de otros servicios. Por el contrario, en el patrón de orquestación, un controlador central o servicio coordinador gestiona la transacción. El coordinador envía mensajes a cada servicio para instruirle sobre qué acciones tomar y en qué…