❓ Qué problema resuelve

  • Monolitos complejos: Aplicaciones grandes difíciles de mantener y desplegar
  • Escalabilidad: Escalar componentes específicos según demanda
  • Tecnología: Usar diferentes tecnologías para diferentes servicios
  • Equipos: Permitir que equipos trabajen independientemente
  • Despliegue: Despliegues independientes y más frecuentes

🔧 Cómo funciona

Descompone una aplicación en servicios pequeños e independientes que se comunican a través de APIs bien definidas.

Conceptos Clave:

  • Servicios independientes: Cada servicio tiene su propia base de datos
  • Comunicación por API: REST, gRPC, mensajería
  • Descentralización: Cada servicio maneja su propia lógica
  • Tolerancia a fallos: Circuit breakers, timeouts, retries
  • Service Discovery: Registro y descubrimiento de servicios

📊 Diagrama

graph TB
    subgraph "Client Applications"
        WEB[Web App]
        MOB[Mobile App]
    end
    
    subgraph "API Gateway"
        GW[Gateway]
    end
    
    subgraph "Microservices"
        subgraph "User Service"
            US[User Service]
            UDB[(User DB)]
        end
        
        subgraph "Order Service"
            OS[Order Service]
            ODB[(Order DB)]
        end
        
        subgraph "Product Service"
            PS[Product Service]
            PDB[(Product DB)]
        end
        
        subgraph "Payment Service"
            PYS[Payment Service]
            PYDB[(Payment DB)]
        end
        
        subgraph "Notification Service"
            NS[Notification Service]
            NDB[(Notification DB)]
        end
    end
    
    subgraph "Infrastructure"
        SD[Service Discovery]
        MB[Message Broker]
        MON[Monitoring]
    end
    
    WEB --> GW
    MOB --> GW
    
    GW --> US
    GW --> OS
    GW --> PS
    GW --> PYS
    
    US --> UDB
    OS --> ODB
    PS --> PDB
    PYS --> PYDB
    NS --> NDB
    
    OS --> MB
    PYS --> MB
    NS --> MB
    
    US --> SD
    OS --> SD
    PS --> SD
    PYS --> SD
    NS --> SD

☕ Ejemplo en Java

User Service

@RestController
@RequestMapping("/api/users")
public class UserController {
    private final UserService userService;
    
    public UserController(UserService userService) {
        this.userService = userService;
    }
    
    @GetMapping("/{userId}")
    public ResponseEntity<UserDto> getUser(@PathVariable String userId) {
        User user = userService.findById(userId);
        return ResponseEntity.ok(UserDto.from(user));
    }
    
    @PostMapping
    public ResponseEntity<String> createUser(@RequestBody CreateUserRequest request) {
        String userId = userService.createUser(request);
        return ResponseEntity.ok(userId);
    }
}

@Service
public class UserService {
    private final UserRepository userRepository;
    private final EventPublisher eventPublisher;
    
    public UserService(UserRepository userRepository, EventPublisher eventPublisher) {
        this.userRepository = userRepository;
        this.eventPublisher = eventPublisher;
    }
    
    public String createUser(CreateUserRequest request) {
        User user = new User(
            UUID.randomUUID().toString(),
            request.getEmail(),
            request.getName()
        );
        
        userRepository.save(user);
        
        eventPublisher.publish(new UserCreatedEvent(
            user.getId(),
            user.getEmail(),
            user.getName()
        ));
        
        return user.getId();
    }
    
    public User findById(String userId) {
        return userRepository.findById(userId)
            .orElseThrow(() -> new UserNotFoundException(userId));
    }
}

Order Service con comunicación entre servicios

@RestController
@RequestMapping("/api/orders")
public class OrderController {
    private final OrderService orderService;
    
    public OrderController(OrderService orderService) {
        this.orderService = orderService;
    }
    
    @PostMapping
    public ResponseEntity<String> createOrder(@RequestBody CreateOrderRequest request) {
        String orderId = orderService.createOrder(request);
        return ResponseEntity.ok(orderId);
    }
    
    @GetMapping("/{orderId}")
    public ResponseEntity<OrderDto> getOrder(@PathVariable String orderId) {
        Order order = orderService.findById(orderId);
        return ResponseEntity.ok(OrderDto.from(order));
    }
}

@Service
public class OrderService {
    private final OrderRepository orderRepository;
    private final UserServiceClient userServiceClient;
    private final ProductServiceClient productServiceClient;
    private final EventPublisher eventPublisher;
    
    public OrderService(OrderRepository orderRepository,
                       UserServiceClient userServiceClient,
                       ProductServiceClient productServiceClient,
                       EventPublisher eventPublisher) {
        this.orderRepository = orderRepository;
        this.userServiceClient = userServiceClient;
        this.productServiceClient = productServiceClient;
        this.eventPublisher = eventPublisher;
    }
    
    @Transactional
    public String createOrder(CreateOrderRequest request) {
        // Validar usuario existe
        UserDto user = userServiceClient.getUser(request.getUserId());
        if (user == null) {
            throw new UserNotFoundException(request.getUserId());
        }
        
        // Validar productos y obtener precios
        List<OrderItem> items = new ArrayList<>();
        for (OrderItemRequest itemRequest : request.getItems()) {
            ProductDto product = productServiceClient.getProduct(itemRequest.getProductId());
            if (product == null) {
                throw new ProductNotFoundException(itemRequest.getProductId());
            }
            
            items.add(new OrderItem(
                itemRequest.getProductId(),
                product.getName(),
                product.getPrice(),
                itemRequest.getQuantity()
            ));
        }
        
        Order order = new Order(
            UUID.randomUUID().toString(),
            request.getUserId(),
            items
        );
        
        orderRepository.save(order);
        
        eventPublisher.publish(new OrderCreatedEvent(
            order.getId(),
            order.getUserId(),
            order.getTotalAmount(),
            order.getItems()
        ));
        
        return order.getId();
    }
}

Service Clients con Circuit Breaker

@Component
public class UserServiceClient {
    private final RestTemplate restTemplate;
    private final CircuitBreaker circuitBreaker;
    
    public UserServiceClient(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
        this.circuitBreaker = CircuitBreaker.ofDefaults("userService");
    }
    
    public UserDto getUser(String userId) {
        return circuitBreaker.executeSupplier(() -> {
            try {
                ResponseEntity<UserDto> response = restTemplate.getForEntity(
                    "http://user-service/api/users/" + userId,
                    UserDto.class
                );
                return response.getBody();
            } catch (Exception e) {
                throw new UserServiceException("Failed to get user: " + userId, e);
            }
        });
    }
}

@Component
public class ProductServiceClient {
    private final WebClient webClient;
    private final CircuitBreaker circuitBreaker;
    
    public ProductServiceClient(WebClient.Builder webClientBuilder) {
        this.webClient = webClientBuilder
            .baseUrl("http://product-service")
            .build();
        this.circuitBreaker = CircuitBreaker.ofDefaults("productService");
    }
    
    public ProductDto getProduct(String productId) {
        return circuitBreaker.executeSupplier(() -> {
            return webClient
                .get()
                .uri("/api/products/{productId}", productId)
                .retrieve()
                .bodyToMono(ProductDto.class)
                .timeout(Duration.ofSeconds(5))
                .block();
        });
    }
}

Configuration para Microservicios

@Configuration
@EnableEurekaClient
public class MicroserviceConfig {
    
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
    
    @Bean
    public WebClient.Builder webClientBuilder() {
        return WebClient.builder();
    }
    
    @Bean
    public CircuitBreakerRegistry circuitBreakerRegistry() {
        return CircuitBreakerRegistry.ofDefaults();
    }
}

// Application properties
# application.yml
server:
  port: 8081

spring:
  application:
    name: order-service
  datasource:
    url: jdbc:postgresql://localhost:5432/orderdb
    username: ${DB_USERNAME:orderuser}
    password: ${DB_PASSWORD:orderpass}

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
  instance:
    prefer-ip-address: true

management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics
  endpoint:
    health:
      show-details: always

resilience4j:
  circuitbreaker:
    instances:
      userService:
        failure-rate-threshold: 50
        wait-duration-in-open-state: 30s
        sliding-window-size: 10
      productService:
        failure-rate-threshold: 50
        wait-duration-in-open-state: 30s
        sliding-window-size: 10

Event Handler para comunicación asíncrona

@Component
public class OrderEventHandler {
    private final NotificationServiceClient notificationClient;
    private final PaymentServiceClient paymentClient;
    
    public OrderEventHandler(NotificationServiceClient notificationClient,
                           PaymentServiceClient paymentClient) {
        this.notificationClient = notificationClient;
        this.paymentClient = paymentClient;
    }
    
    @EventListener
    @Async
    public void handle(OrderCreatedEvent event) {
        // Enviar notificación
        notificationClient.sendOrderConfirmation(
            event.getUserId(),
            event.getAggregateId()
        );
        
        // Iniciar proceso de pago
        paymentClient.processPayment(new PaymentRequest(
            event.getAggregateId(),
            event.getTotalAmount()
        ));
    }
}

##  Ventajas

- **Escalabilidad independiente**: Cada servicio se escala según su demanda
- **Tecnología heterogénea**: Diferentes tecnologías para diferentes servicios
- **Equipos autónomos**: Desarrollo y despliegue independiente
- **Tolerancia a fallos**: Fallo de un servicio no afecta a otros
- **Despliegues frecuentes**: Ciclos de desarrollo más rápidos

##  Desventajas

- **Complejidad operacional**: Más servicios que monitorear y mantener
- **Latencia de red**: Comunicación entre servicios añade latencia
- **Consistencia de datos**: Transacciones distribuidas son complejas
- **Testing complejo**: Pruebas de integración más difíciles
- **Overhead de infraestructura**: Más recursos necesarios

## 🎯 Patrones Complementarios

### API Gateway
```mermaid
graph TB
    subgraph "API Gateway Pattern"
        CLIENT[Client] --> GATEWAY[API Gateway]
        GATEWAY --> AUTH[Authentication]
        GATEWAY --> RATE[Rate Limiting]
        GATEWAY --> ROUTE[Routing]
        GATEWAY --> CACHE[Caching]
        
        ROUTE --> SERVICE1[Service A]
        ROUTE --> SERVICE2[Service B]
        ROUTE --> SERVICE3[Service C]
    end

Database per Service

graph TB
    subgraph "Database per Service Pattern"
        subgraph "User Service"
            US[User Service] --> UDB[(User DB)]
        end
        
        subgraph "Order Service"
            OS[Order Service] --> ODB[(Order DB)]
        end
        
        subgraph "Product Service"
            PS[Product Service] --> PDB[(Product DB)]
        end
        
        US -.->|Events| OS
        OS -.->|Events| PS
    end

🔄 Comunicación entre Servicios

Event-Driven Communication

sequenceDiagram
    participant OS as Order Service
    participant MB as Message Broker
    participant PS as Payment Service
    participant NS as Notification Service
    participant IS as Inventory Service
    
    OS->>MB: OrderCreatedEvent
    MB->>PS: Process Payment
    MB->>NS: Send Confirmation
    MB->>IS: Reserve Items
    
    PS->>MB: PaymentProcessedEvent
    MB->>OS: Update Order Status
    MB->>NS: Send Payment Confirmation

🛠️ Herramientas y Tecnologías

Service Discovery

  • Netflix Eureka: Service registry
  • Consul: Service mesh y discovery
  • Kubernetes: Service discovery nativo

API Gateway

  • Netflix Zuul: Routing y filtering
  • Spring Cloud Gateway: Gateway reactivo
  • Kong: API gateway empresarial

Resilience Patterns

  • Circuit Breaker: Resilience4j, Hystrix
  • Bulkhead: Aislamiento de recursos
  • Timeout: Límites de tiempo
  • Retry: Reintentos con backoff

🎨 Casos de Uso Ideales

E-commerce

  • User Service: Gestión de usuarios
  • Product Service: Catálogo de productos
  • Order Service: Procesamiento de pedidos
  • Payment Service: Procesamiento de pagos
  • Inventory Service: Gestión de inventario
  • Notification Service: Notificaciones

Banking

  • Account Service: Gestión de cuentas
  • Transaction Service: Procesamiento de transacciones
  • Fraud Service: Detección de fraude
  • Notification Service: Alertas y notificaciones
  • Reporting Service: Reportes y analytics ```