Today we've got a topic that's foundational to success in microservices architecture: patterns! Imagine a city with lots of buildings: offices, shops, restaurants. Each has its own address and role. In theory you can go directly to any building, but how exactly? Imagine you have smart navigators that know all the routes and can point out the shortest path. In the world of microservices those "navigators" are called API Gateway, and to let the buildings find each other we use Service Discovery. But what if one of the buildings is temporarily closed? Then the city uses Circuit Breaker to avoid overload. The patterns we're studying today make working with microservices much simpler and make them resilient and manageable.
API Gateway: The gateway into the microservices world
API Gateway is a central entry point for all client requests. Instead of the client interacting directly with every microservice, it goes through the Gateway, which routes requests, performs data transformation, and is also responsible for security.
Here's an analogy: if microservices are buildings, the API Gateway is a single entrance from which visitors are then directed to the right building.
What the API Gateway does:
- Request routing: forwarding HTTP requests to the appropriate microservices.
- Authentication and authorization: ensuring system security.
- Data aggregation: combining responses from multiple microservices into one.
- Caching: reducing load on services by storing data locally.
- Request and response transformation: for example, converting data from one format to another.
What does this look like in practice?
Say you have an e-commerce app:
- The client wants to view product info. The request goes through the API Gateway.
- The Gateway forwards the request to the catalog microservice.
- If the product info is also tied to reviews, the Gateway can aggregate data from two microservices (catalog and reviews) and return a single response to the client.
Example using Spring Cloud Gateway:
@SpringBootApplication
public class ApiGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(ApiGatewayApplication.class, args);
}
}
@Configuration
public class GatewayConfig {
@Bean
public RouteLocator routeLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("catalog_service", r -> r.path("/catalog/**")
.uri("http://localhost:8081")) // redirects to the catalog microservice
.route("review_service", r -> r.path("/reviews/**")
.uri("http://localhost:8082")) // redirects to the reviews microservice
.build();
}
}
How does this help?
- Simplifies client logic: the client "knows" only a single entry point.
- Central control point: you can enable caching or logging just in the Gateway.
- Quick adaptation: you can change internal routes without touching clients.
Drawbacks of the API Gateway:
- Can become a single point of failure if you don't configure resilience.
- Adds some overhead, since all requests go through one service.
Service Discovery: now go find each other!
Service Discovery is a mechanism that allows microservices to find each other dynamically. This is especially important when microservices are frequently created, removed, or scaled.
If the API Gateway is the "main gate", Service Discovery is the "yellow pages" where the addresses of all the buildings (microservices) are listed.
Usage scenario:
- A new microservice starts up and registers itself in the "service registry".
- Other microservices or the API Gateway can query the "service registry" to find the needed service.
Popular Service Discovery tools:
- Netflix Eureka (supported out of the box by Spring Cloud).
- Consul.
- Zookeeper.
Example using Eureka:
Step 1: Set up the Eureka Server
@EnableEurekaServer
@SpringBootApplication
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
Step 2: Register the microservice Add to application.properties:
spring.application.name=catalog-service
eureka.client.service-url.defaultZone=http://localhost:8761/eureka
Now your "catalog-service" will register with the Eureka Server and become available to others.
Circuit Breaker: resilience to the max
Circuit Breaker is a pattern that prevents microservices from being overloaded. If one microservice stops responding (or responds slowly), the Circuit Breaker "cuts off" requests to that service, protecting other parts of the system.
Circuit Breaker makes the system more resilient because it prevents cascading failures when one service goes down. It also reduces load on resources that are already struggling.
Example of a Circuit Breaker for a REST call (implementation using Resilience4j)
- Add the dependency:
<dependency> <groupId>io.github.resilience4j</groupId> <artifactId>resilience4j-spring-boot2</artifactId> <version>2.0.2</version> </dependency> - Configure the Circuit Breaker in
application.properties:resilience4j.circuitbreaker.instances.catalog.failureRateThreshold=50 resilience4j.circuitbreaker.instances.catalog.slowCallRateThreshold=60 - Use it in code:
@RestController public class CatalogController { private final RestTemplate restTemplate; public CatalogController(RestTemplate restTemplate) { this.restTemplate = restTemplate; } @GetMapping("/catalog") @CircuitBreaker(name = "catalog", fallbackMethod = "fallbackCatalog") public String getCatalog() { return restTemplate.getForObject("http://localhost:8081/catalog", String.class); } public String fallbackCatalog(Throwable t) { return "Catalog service is currently down. Please try again later."; } }
Summary
These three patterns — API Gateway, Service Discovery, and Circuit Breaker — are cornerstones of microservices architecture. API Gateway provides a centralized entry point and manages requests. Service Discovery helps microservices find each other. Circuit Breaker protects your system from cascading failures.
These patterns will help make your system not just scalable and flexible, but also resilient to failures. In the next lecture we'll talk about service autonomy, data isolation, and some other architectural principles of microservices.
GO TO FULL VERSION