Es hora de hablar de cómo esos científicos autónomos —los microservicios— se "comunican" entre sí. Y aquí, como en la vida real, hay dos formas populares: hablar directamente (síncrono) o enviar cartas/mensajes (asíncrono).
Imagina un flujo de trabajo típico en una oficina. Cuando necesitas información urgentemente de un colega, vas a preguntarle en persona o llamas (comunicación síncrona). Cuando la tarea no es urgente, envías un email y sigues con otras cosas mientras esperas la respuesta (comunicación asíncrona). La elección depende de la urgencia e importancia del asunto.
Del mismo modo, los microservicios pueden comunicarse de distintas formas según sus responsabilidades. Por ejemplo:
- Si el microservicio A necesita una respuesta inmediata del microservicio B, llama directamente vía REST API.
- Si al microservicio A no le importa la inmediatez de la respuesta, enviará un mensaje a través de un broker (por ejemplo, Kafka).
Así que la comunicación síncrona o asíncrona son dos enfoques fundamentales que permiten la interacción entre servicios en una arquitectura de microservicios.
Comunicación síncrona mediante REST API
La comunicación síncrona significa que un servicio hace una petición y espera la respuesta de otro servicio. Es parecido a una llamada telefónica: llamas a un amigo y esperas a que responda. Si no contesta, llamas de nuevo o cuelgas.
En el mundo de microservicios, la forma más popular de comunicación síncrona es REST API.
Ejemplo de interacción síncrona con REST
Imagina que desarrollas un sistema de pedidos de comida. Tienes dos microservicios:
OrderService— se encarga del procesamiento de pedidos.PaymentService— se encarga del procesamiento de pagos.
Escenario: al realizar un pedido, OrderService debe llamar a PaymentService para comprobar si hay fondos suficientes. Así podría verse:
// OrderService: Llamada al REST API de PaymentService (petición síncrona)
@RestController
@RequestMapping("/orders")
public class OrderController {
@PostMapping
public ResponseEntity<String> createOrder(@RequestBody OrderRequest orderRequest) {
// Lógica de creación de pedido
// Enviamos la petición a PaymentService
RestTemplate restTemplate = new RestTemplate();
String paymentUrl = "http://localhost:8081/payment/validate";
PaymentResponse paymentResponse = restTemplate.postForObject(paymentUrl, orderRequest, PaymentResponse.class);
if (paymentResponse.isPaymentValid()) {
return ResponseEntity.ok("Pedido creado con éxito.");
} else {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("Pago fallido.");
}
}
}
Ventajas de la comunicación síncrona
- Implementación sencilla: REST API es un estándar que muchos desarrolladores ya conocen, y las herramientas (por ejemplo, Spring RestTemplate y WebClient) facilitan mucho el trabajo.
- Acceso directo: un servicio llama a otro directamente y obtiene la respuesta de inmediato.
- Familiaridad: REST API se usa ampliamente y es entendible tanto para desarrolladores como para gestores.
Limitaciones de la comunicación síncrona
- Dependencia temporal: si
PaymentServiceno está disponible, entoncesOrderServicetambién "se bloquea", lo que puede afectar a todo el sistema. - Problemas de escalado: si la carga sobre
OrderServiceaumenta,PaymentServicetambién tendrá que manejar más peticiones. - Mayor latencia: cada llamada REST implica tiempo de espera, lo que puede ralentizar el rendimiento global.
Cuándo usar comunicación síncrona?
- Cuando se necesita una respuesta inmediata.
- Cuando la dependencia entre servicios es estrecha (por ejemplo, validación de datos de pago).
- Cuando las fallas en un servicio son críticas para otro.
Comunicación asíncrona usando mensajes
La asincronía implica que un servicio envía un mensaje a otro a través de un broker (por ejemplo, Kafka, RabbitMQ o ActiveMQ) y no espera una respuesta inmediata. Es más parecido a enviar un correo electrónico: escribes el mensaje y sigues con tu trabajo, y el receptor contestará cuando pueda.
Conceptos clave de la comunicación asíncrona
- Brokers de mensajes (Message Brokers): normalmente se usa un intermediario, por ejemplo, Kafka, que almacena y entrega mensajes.
- Producer y consumer: el servicio emisor se llama producer, y el receptor — consumer.
- Topics: los mensajes se envían a "topics", que actúan como buzones.
Ejemplo de interacción asíncrona con Kafka
Continuando con el ejemplo de OrderService y PaymentService. Supongamos que queremos enviar el pedido para cobro de forma asíncrona.
Publicando un mensaje (Producer):
// OrderService: Envío de mensaje a Kafka
@RestController
@RequestMapping("/orders")
public class OrderController {
private final KafkaTemplate<String, OrderRequest> kafkaTemplate;
public OrderController(KafkaTemplate<String, OrderRequest> kafkaTemplate) {
this.kafkaTemplate = kafkaTemplate;
}
@PostMapping
public ResponseEntity<String> createOrder(@RequestBody OrderRequest orderRequest) {
kafkaTemplate.send("payment-topic", orderRequest); // Enviamos el mensaje
return ResponseEntity.ok("Pedido creado con éxito. El pago se procesará.");
}
}
Procesando el mensaje (Consumer):
// PaymentService: Recepción de mensaje desde Kafka
@Component
public class PaymentConsumer {
@KafkaListener(topics = "payment-topic", groupId = "payment-group")
public void handlePayment(OrderRequest orderRequest) {
// Lógica de procesamiento del pago
System.out.println("Procesando pago para el pedido: " + orderRequest.getOrderId());
}
}
Ventajas de la comunicación asíncrona
- Reducción de dependencias: los servicios pueden funcionar de forma independiente. Incluso si
PaymentServiceestá caído,OrderServicepuede seguir operando. - Mayor escalabilidad: los brokers de mensajes, como Kafka, pueden manejar volúmenes enormes de datos.
- Flexibilidad en la interacción: varios consumers pueden suscribirse a un mismo topic, útil en sistemas complejos.
Limitaciones de la comunicación asíncrona
- Complejidad en la implementación: requiere configurar el broker de mensajes y manejar errores (por ejemplo, mensajes no entregados).
- Falta de respuesta inmediata: si la confirmación de la operación es crítica, puede ser un problema.
- Garantías de entrega: no todos los brokers ofrecen garantías estrictas de entrega.
Cuándo usar comunicación asíncrona?
- Cuando la tarea no requiere finalización inmediata (por ejemplo, envío de notificaciones).
- Cuando se desea desacoplar servicios y reducir dependencias mutuas.
- Cuando hace falta procesar grandes volúmenes de datos de forma eficiente.
Elegir entre comunicación síncrona y asíncrona
La elección depende del escenario concreto. Aquí tienes unas recomendaciones:
| Criterio | Síncrona (REST) | Asíncrona (Mensajes) |
|---|---|---|
| Inmediatez de la respuesta | Requerida | No requerida |
| Dependencia entre servicios | Alta | Baja |
| Volumen de datos | Pequeño | Grande |
| Escalabilidad | Limitada | Alta |
| Complejidad de implementación | Baja | Alta |
Errores típicos al usar estos enfoques
- Usar REST para tareas que no requieren respuesta inmediata conduce a mayor latencia y dependencias innecesarias.
- Descuidar el manejo de errores en la comunicación asíncrona puede provocar pérdida de mensajes.
- Diseñar mal los topics de Kafka (por ejemplo, demasiados producers y consumers en un mismo topic) genera caos.
Para evitar estos problemas, analiza con cuidado los requisitos del sistema y elige el enfoque que mejor se ajuste a tus objetivos.
Con esto ya entendemos cómo los microservicios pueden interactuar entre sí mediante REST síncrono y mensajes asíncronos. En la siguiente lección nos meteremos más a fondo en la decomposición de aplicaciones para arquitectura de microservicios. ¡Nos vemos en el código! 😉
GO TO FULL VERSION