- Jacobo Zuluaga Jaramillo:
jzuluagaj@eafit.edu.co - Santiago de Jesús Gómez Alzate:
sjgomeza@eafit.edu.co - Victor Jesús Villadiego Álvarez:
vjvilladia@eafit.edu.co
Este proyecto, desarrollado en el marco del curso de Tópicos de Telemática, implementa una aplicación distribuida basada en microservicios que simula un sistema simple de gestión de usuarios, productos y pedidos. El objetivo principal es explorar y aplicar conceptos clave de la comunicación entre procesos remotos en entornos distribuidos, abordando desafíos como la eficiencia en la comunicación y la tolerancia a fallos.
La arquitectura sigue un patrón común: un API Gateway expone una interfaz RESTful a los clientes, mientras que los microservicios internos (Usuarios, Productos, Órdenes) se comunican entre sí, y con el API Gateway de manera eficiente utilizando gRPC con Protocol Buffers. Para garantizar la resiliencia del sistema ante fallos temporales de los microservicios, se integra un Middleware Orientado a Mensajes (MOM), específicamente RabbitMQ, que actúa como mecanismo de failover, encolando las solicitudes que no pueden ser procesadas inmediatamente y permitiendo su posterior recuperación y procesamiento.
- Diseñar e implementar un API Gateway para la gestión centralizada de peticiones REST.
- Aplicar gRPC para la comunicación eficiente y tipada entre microservicios.
- Implementar un mecanismo de failover utilizando RabbitMQ para manejar la indisponibilidad temporal de microservicios.
- Desarrollar la lógica necesaria en los microservicios para recuperar y procesar mensajes pendientes desde la cola de RabbitMQ.
- Integrar y probar el funcionamiento completo del sistema distribuido.
El sistema se compone de los siguientes contenedores principales:
- API Gateway (Java - Spring Cloud Gateway): Punto único de entrada. Recibe peticiones REST del cliente, las valida (parcialmente), interactúa con los microservicios vía gRPC y maneja errores (incluyendo el encolado en RabbitMQ para ciertos fallos).
- User Service (Go): Gestiona la información de los usuarios (obtener datos, actualizar saldo). Se comunica vía gRPC. Persiste datos en
users.json. - Product Service (Node.js - Express/gRPC): Gestiona la información de los productos (obtener detalles y precio). Se comunica vía gRPC.
- Order Service (Node.js - gRPC): Gestiona la creación y consulta de órdenes. Orquesta llamadas gRPC a User Service y Product Service. Implementa el consumidor de RabbitMQ para procesar órdenes pendientes. Persiste datos en
orders.json. - RabbitMQ (MOM): Broker de mensajes utilizado para el mecanismo de failover. Almacena temporalmente las solicitudes de creación de órdenes si el Order Service (o sus dependencias) fallan de forma recuperable.
Consulte la Wiki de Arquitectura para más detalles y diagramas.
- API Gateway: Java 17+, Spring Boot 3+, Spring Cloud Gateway
- User Service: Go (última versión estable)
- Order Service: Node.js (LTS)
- Product Service: Node.js (LTS)
- Comunicación Inter-Servicios: gRPC, Protocol Buffers
- Middleware de Mensajes (MOM): RabbitMQ
- Contenerización: Docker, Docker Compose
- Build Tools: Maven (Java), Go Modules (Go), npm (Node.js)
- Protocolos: REST/HTTP, AMQP
Para ejecutar este proyecto, necesitarás tener instaladas las siguientes herramientas:
- Docker y Docker Compose: Únicamente para ejecutar RabbitMQ fácilmente. Instalar Docker.
- Java JDK 17+: Para el API Gateway.
- Maven 3.8+: Para construir y ejecutar el API Gateway.
- Go (última versión estable): Para el User Service.
- Node.js (versión LTS recomendada): Para el Order Service y Product Service.
- Compilador
protoc: Necesario para generar los stubs gRPC si modificas los archivos.proto. Los plugins específicos para cada lenguaje también deben estar instalados (Java gRPC, Go gRPC, Node.js gRPC). - Git: Para clonar el repositorio.
Antes de ejecutar los servicios, asegúrate de configurar correctamente las URLs y puertos.
-
Clonar el repositorio:
git clone https://github.com/santig005/Distributed-Systems-gRPC cd Distributed-Systems-gRPC -
Configurar URLs de Servicios: Dado que los servicios correrán localmente en diferentes puertos, la comunicación entre ellos deberá usar
localhosto127.0.0.1.- API Gateway (
api-gateway/src/main/resources/application.yml): Ajusta las seccionesservices.*.hostalocalhosty verifica que losportcoincidan con los puertos donde realmente correrán los microservicios. Asegúrate quespring.rabbitmq.hostsealocalhostsi vas a correr RabbitMQ con el comando Docker de abajo. - Order Service (
microservices/order_service/.env): ModificaPRODUCT_SERVICE_URL,USER_SERVICE_URLyRABBITMQ_URLpara que apunten alocalhost:<puerto_correspondiente>. - Product Service (
microservices/product_service/.env): Asegúrate que exista y tenga la configuración de puerto correcta. - User Service (
microservices/user_service/main.go): Verifica si las URLs de dependencias (si las tuviera) están configuradas (probablemente no llama a otros servicios).
- API Gateway (
-
Generar Código gRPC (Si es la primera vez o modificaste .proto):
- API Gateway (Java):
cd api-gateway mvn clean generate-sources cd ..
- User Service (Go):
cd microservices/user_service # Asegúrate que la ruta al proto sea correcta desde esta carpeta protoc --go_out=. --go-grpc_out=. ../../libs/protobufs/users.proto # Descarga/actualiza dependencias si cambiaste el proto go mod tidy cd ../..
- (Node.js): No requiere un paso explícito de generación,
protoLoadercarga el.protoen tiempo de ejecución.
- API Gateway (Java):
Deberás abrir múltiples terminales, una para cada servicio y una para RabbitMQ.
-
Iniciar RabbitMQ (Usando Docker): En una terminal, ejecuta:
docker run -d --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3-management
- Esto descarga (si no existe) y ejecuta la imagen de RabbitMQ con la UI de administración expuesta en el puerto 15672.
- Puedes acceder a la UI en
http://localhost:15672(user:guest, pass:guest).
-
Iniciar User Service (Go): En una nueva terminal:
cd microservices/user_service go run main.go- Busca un mensaje indicando que el servidor gRPC está escuchando (probablemente en el puerto 50051).
-
Iniciar Product Service (Node.js): En una nueva terminal:
cd microservices/product_service npm install # Solo la primera vez o si cambian las dependencias npm start
- Busca un mensaje indicando que el servidor está escuchando (probablemente en el puerto 50053).
-
Iniciar Order Service (Node.js): En una nueva terminal:
cd microservices/order_service npm install # Solo la primera vez o si cambian las dependencias npm start
- Busca un mensaje indicando que el servidor gRPC está escuchando (probablemente en el puerto 50054) y que se conectó a RabbitMQ.
-
Iniciar API Gateway (Java): En una nueva terminal:
cd api-gateway # (Opcional) Limpiar y construir si no lo hiciste antes # mvn clean install -DskipTests mvn spring-boot:run
- Busca el logo de Spring y mensajes indicando que la aplicación inició y está escuchando (probablemente en el puerto 8080).
-
Verificar:
- Prueba los endpoints del API Gateway usando
curlo Postman (ver sección "Uso / API Endpoints"). Asegúrate de usarhttp://localhost:8080(o el puerto configurado para el Gateway).
- Prueba los endpoints del API Gateway usando
-
Detener los Servicios:
- Para detener cada servicio Node.js, Go y Java, ve a su terminal respectiva y presiona
Ctrl + C. - Para detener y eliminar el contenedor de RabbitMQ:
docker stop rabbitmq docker rm rabbitmq
- Para detener cada servicio Node.js, Go y Java, ve a su terminal respectiva y presiona
Asumiendo que el API Gateway corre en http://localhost:8080 (verifica application.yml y docker-compose.yml):
-
Obtener Usuario por ID:
curl http://localhost:8080/api/users/{userId}Ejemplo:
curl http://localhost:8080/api/users/1 -
Obtener Producto por ID:
curl http://localhost:8080/api/products/{productId}Ejemplo:
curl http://localhost:8080/api/products/1 -
Crear una Orden:
curl -X POST http://localhost:8080/api/orders \ -H "Content-Type: application/json" \ -d '{ "userId": "1", "productIds": ["1", "2"] }'Respuesta Exitosa:
201 Createdcon los detalles de la orden. Respuesta por Failover:202 Acceptedsi un servicio falló y se encoló. -
Obtener Orden por ID:
curl http://localhost:8080/api/orders/{orderId}Ejemplo:
curl http://localhost:8080/api/orders/1745194637551 -
Obtener Órdenes por ID de Usuario:
curl http://localhost:8080/api/orders-user/{userId}Ejemplo:
curl http://localhost:8080/api/orders-user/1
Consulta la Documentación de la API para ver detalles completos de request/response y códigos de error.
Puedes simular un fallo para ver el MOM en acción:
- Inicia todos los servicios como se describe en "Ejecución Manual".
- Detén el User Service (presiona
Ctrl + Cen su terminal). - Intenta crear una orden usando
curl. Deberías recibir un202 Accepteddel API Gateway. - Verifica los logs del Order Service (en su terminal). Verás un error al intentar contactar
localhost:50051. - (Opcional) Revisa la cola
order-service-queueen la UI de RabbitMQ (http://localhost:15672). Debería haber un mensaje pendiente. - Reinicia el User Service (ejecuta
go run main.gode nuevo en su terminal). - Observa los logs del Order Service. El consumidor debería recoger el mensaje, procesarlo (ahora User Service responde) y confirmar el mensaje.
- Verifica el estado final (la orden existe, el saldo se actualizó) usando los endpoints GET.