Introduction
Microservices architecture divides the application into small, independent services. Spring Cloud provides full tools: Service Discovery, API Gateway, Circuit Breaker, Config Server to build production-ready microservices systems.
1. Microservices Architecture Overview
┌──────────────┐
│ Client │
└──────┬───────┘
│
┌──────▼───────┐
│ API Gateway │
│(Spring Cloud)│
└──────┬───────┘
│
┌────────────────┼────────────────┐
│ │ │
┌──────▼──────┐ ┌──────▼──────┐ ┌──────▼──────┐
│ Order │ │ Product │ │ User │
│ Service │ │ Service │ │ Service │
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘
│ │ │
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐
│Order DB │ │Product │ │User DB │
│(Postgres)│ │DB(Mongo)│ │(Postgres)│
└─────────┘ └─────────┘ └─────────┘
2. Service Discovery with Consul
2.1 Setup Consul (Docker)
# docker-compose.yml
services:
consul:
image: hashicorp/consul:1.20
ports:
- "8500:8500"
command: agent -server -bootstrap-expect=1 -ui -client=0.0.0.0
2.2 Spring Boot Service Registration
// build.gradle.kts
implementation("org.springframework.cloud:spring-cloud-starter-consul-discovery")
# application.yml (Product Service)
spring:
application:
name: product-service
cloud:
consul:
host: localhost
port: 8500
discovery:
service-name: ${spring.application.name}
health-check-interval: 10s
instance-id: ${spring.application.name}:${random.value}
2.3 Service-to-Service Communication
@Configuration
public class RestClientConfig {
@Bean
@LoadBalanced
public RestClient.Builder restClientBuilder() {
return RestClient.builder();
}
}
@Service
public class OrderService {
private final RestClient restClient;
public OrderService(RestClient.Builder builder) {
this.restClient = builder
.baseUrl("http://product-service") // Tên service, không phải IP
.build();
}
public ProductResponse getProduct(Long productId) {
return restClient.get()
.uri("/api/v1/products/{id}", productId)
.retrieve()
.body(ProductResponse.class);
}
}
3. API Gateway with Spring Cloud Gateway
3.1 Setup Gateway
// build.gradle.kts (Gateway Service)
implementation("org.springframework.cloud:spring-cloud-starter-gateway")
implementation("org.springframework.cloud:spring-cloud-starter-consul-discovery")
3.2 Route Configuration
# application.yml
spring:
application:
name: api-gateway
cloud:
gateway:
routes:
- id: product-service
uri: lb://product-service
predicates:
- Path=/api/v1/products/**
filters:
- StripPrefix=0
- name: CircuitBreaker
args:
name: productCircuitBreaker
fallbackUri: forward:/fallback/products
- id: order-service
uri: lb://order-service
predicates:
- Path=/api/v1/orders/**
filters:
- StripPrefix=0
- id: user-service
uri: lb://user-service
predicates:
- Path=/api/v1/users/**
3.3 Global Filters
@Component
public class LoggingFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String requestId = UUID.randomUUID().toString();
exchange.getRequest().mutate()
.header("X-Request-Id", requestId);
log.info("Request: {} {} [{}]",
exchange.getRequest().getMethod(),
exchange.getRequest().getPath(),
requestId);
return chain.filter(exchange);
}
@Override
public int getOrder() {
return -1;
}
}
4. Circuit Breaker with Resilience4j
4.1 Setup
// build.gradle.kts
implementation("org.springframework.cloud:spring-cloud-starter-circuitbreaker-resilience4j")
4.2 Configuration
resilience4j:
circuitbreaker:
instances:
productService:
sliding-window-size: 10
failure-rate-threshold: 50
wait-duration-in-open-state: 10s
permitted-number-of-calls-in-half-open-state: 3
slow-call-duration-threshold: 2s
slow-call-rate-threshold: 80
retry:
instances:
productService:
max-attempts: 3
wait-duration: 1s
exponential-backoff-multiplier: 2
timelimiter:
instances:
productService:
timeout-duration: 3s
4.3 Use in Code
@Service
public class OrderService {
private final RestClient restClient;
private final CircuitBreakerFactory circuitBreakerFactory;
@CircuitBreaker(name = "productService", fallbackMethod = "getProductFallback")
@Retry(name = "productService")
public ProductResponse getProduct(Long productId) {
return restClient.get()
.uri("/api/v1/products/{id}", productId)
.retrieve()
.body(ProductResponse.class);
}
// Fallback khi circuit open hoặc service down
private ProductResponse getProductFallback(Long productId, Throwable t) {
log.warn("Fallback for product {}: {}", productId, t.getMessage());
return new ProductResponse(productId, "Unknown Product",
BigDecimal.ZERO, "N/A");
}
}
4.4 Circuit Breaker States
┌─────────┐ Failure rate > threshold ┌──────────┐
│ CLOSED │ ──────────────────────────► │ OPEN │
│(normal) │ │(blocking)│
└────▲────┘ └────┬─────┘
│ │
│ Success rate OK Wait timeout │
│ │
┌────┴──────────┐ │
│ HALF-OPEN │ ◄──────────────────────────┘
│(testing) │
└───────────────┘
5. Centralized Configuration
5.1 Spring Cloud Config Server
# Config Server application.yml
spring:
cloud:
config:
server:
git:
uri: https://github.com/myorg/config-repo
default-label: main
5.2 Client Configuration
# bootstrap.yml (Client Service)
spring:
application:
name: product-service
config:
import: optional:configserver:http://localhost:8888
Summary
- Microservices architecture: each service is independent, has its own database, communicates via REST/gRPC
- Service Discovery (Consul): automatically register/discover services, load balancing with @LoadBalanced
- API Gateway: single entry point, routing, filtering, circuit breaker integration
- Resilience4j Circuit Breaker: protects service from cascading failures with fallback
Exercises
- Build 3 microservices (Order, Product, User) with Consul service discovery. Test load balancing when scaling the service
- Setup Spring Cloud Gateway: routing to 3 services, global logging filter, rate limiting
- Implement Circuit Breaker for Order → Product communication: test fallback when Product service is down