Implementing Service Invocation with Spring Cloud Ribbon Load Balancing
Understanding Ribbon
Load balancing can be implemented in two primary ways:
- Server-side load balancing (e.g., using Nginx)
- Client-side load balancing
What is Ribbon?
Ribbon is a Netflix open-source project that provides client-side load balancing capabilities. It offers various configuration options including connection timeouts and retry mechanisms. Essentially, Ribbon actss as a client-side load balancer that automatically distributes requests among available service instances based on configurable rules such as round-robin or random selection.
Creating User Service Modules
User Service Dependencies
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
Application Configuration
server:
port: 8301
spring:
application:
name: user-service
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://localhost:8001/eureka/
Domain Models
public class Customer {
private Long customerId;
private String customerName;
private String password;
// Constructors, getters, and setters
}
public class ServiceResponse<T> {
private T data;
private String message;
private Integer statusCode;
// Constructors, getters, and setters
}
Service Implementation
@Service
public class CustomerServiceImpl implements CustomerService {
private List<Customer> customerData;
@PostConstruct
public void initializeData() {
customerData = new ArrayList<>();
customerData.add(new Customer(1L, "customer1", "pass123"));
customerData.add(new Customer(2L, "customer2", "pass456"));
customerData.add(new Customer(3L, "customer3", "pass789"));
}
@Override
public Customer findCustomer(Long customerId) {
return customerData.stream()
.filter(customer -> customer.getCustomerId().equals(customerId))
.findFirst()
.orElse(null);
}
// Other CRUD operations
}
Controller Implementation
@RestController
@RequestMapping("/customers")
public class CustomerController {
@Autowired
private CustomerService customerService;
@GetMapping("/{id}")
public ServiceResponse<Customer> getCustomer(@PathVariable Long id) {
Customer customer = customerService.findCustomer(id);
return new ServiceResponse<>(customer);
}
// Additional endpoints for CRUD operations
}
Creating Ribbon Service Module
Ribbon Dependencies
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
Ribbon Configuration
@Configuration
public class LoadBalancerConfig {
@Bean
@LoadBalanced
public RestTemplate loadBalancedRestTemplate() {
return new RestTemplate();
}
}
Service Invocation with Ribbon
@RestController
@RequestMapping("/api")
public class LoadBalancedController {
@Autowired
private RestTemplate restTemplate;
@Value("${service-url.user-service}")
private String userServiceEndpoint;
@GetMapping("/customers/{id}")
public ServiceResponse getCustomer(@PathVariable Long id) {
return restTemplate.getForObject(
userServiceEndpoint + "/customers/{1}",
ServiceResponse.class,
id
);
}
@PostMapping("/customers")
public ServiceResponse createCustomer(@RequestBody Customer customer) {
return restTemplate.postForObject(
userServiceEndpoint + "/customers",
customer,
ServiceResponse.class
);
}
}
Ribbon Configuration Options
Global Configuration
ribbon:
ConnectTimeout: 1000
ReadTimeout: 3000
OkToRetryOnAllOperations: true
MaxAutoRetriesNextServer: 1
MaxAutoRetries: 1
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
Service-Sepcific Configuration
user-service:
ribbon:
ConnectTimeout: 1000
ReadTimeout: 3000
OkToRetryOnAllOperations: true
MaxAutoRetriesNextServer: 1
MaxAutoRetries: 1
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule
Load Balancing Strategies
- RandomRule: Random selectoin among available instances
- RoundRobinRule: Sequential selection in circular order
- RetryRule: Round-robin with retry mechanism
- WeightedResponseTimeRule: Selection based on response time weights
- BestAvailableRule: Selection of least concurrent instances
- AvailabilityFilteringRule: Filters out unhealthy instances
- ZoneAwareLoadBalancer: Considers zone and instance health
RestTemplate Methods
GET Requests
// Get response as object
ServiceResponse response = restTemplate.getForObject(
serviceUrl, ServiceResponse.class, parameters
);
// Get full response entity
ResponseEntity<ServiceResponse> entity = restTemplate.getForEntity(
serviceUrl, ServiceResponse.class, parameters
);
POST Requests
// Post and get response object
ServiceResponse response = restTemplate.postForObject(
serviceUrl, requestObject, ServiceResponse.class
);
// Post and get response entity
ResponseEntity<ServiceResponse> entity = restTemplate.postForEntity(
serviceUrl, requestObject, ServiceResponse.class
);
PUT and DELETE Requests
// PUT request
restTemplate.put(serviceUrl, requestObject);
// DELETE request
restTemplate.delete(serviceUrl, parameters);