client side load balancing happens
Client-side load balancing is a technique where the client is responsible for distributing requests across multiple instances of a microservice. This approach allows the client to make intelligent decisions about which instance to call based on various factors such as response times, instance health, etc. In Spring Boot microservices, client-side load balancing is commonly achieved using Spring Cloud LoadBalancer or Netflix Ribbon.
Table of Contents
Key Concepts:
- 1. Service Discovery: The client needs to know the available instances of the service. This is usually achieved through a service registry like Eureka, Consul, or Zookeeper.
- 2. Load Balancer: The client library (e.g., Spring Cloud LoadBalancer or Ribbon) that distributes the requests among the instances.
- 3. RestTemplate/WebClient: Spring’s utilities that can be enhanced with load-balancing capabilities.
Example using Spring Cloud LoadBalancer
We have two instances of a User Service running on different ports. An Order Service uses client-side load balancing to communicate with User Service instances.
User Service
```java
// UserServiceApplication.java
@SpringBootApplication
@RestController
@RequestMapping("/users")
public class UserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceApplication.class, args);
}
@GetMapping("/{id}")
public User getUserById(@PathVariable String id) {
return new User(id, "John Doe", "john.doe@example.com", System.currentTimeMillis());
}
}
// User.java
public class User {
private String id;
private String name;
private String email;
private long timestamp; // To distinguish which instance responded
// Constructors, Getters, and Setters
}
```
Order Service
```java
// OrderServiceApplication.java
@SpringBootApplication
@RestController
@RequestMapping("/orders")
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
@Autowired
private RestTemplate restTemplate;
@GetMapping("/{orderId}")
public Order getOrderById(@PathVariable String orderId) {
ResponseEntity<User> response = restTemplate.getForEntity("http://user-service/users/123", User.class);
User user = response.getBody();
return new Order(orderId, "Product 1", user);
}
}
// Order.java
public class Order {
private String orderId;
private String productName;
private User user;
// Constructors, Getters, and Setters
}
// RestTemplateConfig.java
@Configuration
public class RestTemplateConfig {
@LoadBalanced
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
```
Configuration (application.yml)
```yaml
spring:
application:
name: order-service
server:
port: 8081
# Instance 1 of user service
---
spring:
profiles: instance1
application:
name: user-service
server:
port: 8082
# Instance 2 of user service
---
spring:
profiles: instance2
application:
name: user-service
server:
port: 8083
# Order service
---
spring:
application:
name: order-service
server:
port: 8081
```
Explanation
- 1. User Service:
- Provides an endpoint `/users/{id}` to get user details.
- Running two instances on different ports (8082 and 8083).
- 2. Order Service:
- Uses `RestTemplate` with `@LoadBalanced` annotation to enable client-side load balancing.
- The `getOrderById` method calls the User Service to get user details and then creates an Order object using the retrieved user information.
- The `@LoadBalanced` RestTemplate ensures that the requests are distributed across available instances of the User Service.
Advantages:
- Scalability: Easily handles traffic by distributing requests among multiple instances.
- Resilience: If one instance fails, requests are automatically routed to healthy instances.
- Flexibility: Clients can make intelligent decisions about which instance to use based on custom logic.