Fading Coder

One Final Commit for the Last Sprint

Home > Notes > Content

Implementing Service Invocation with Spring Cloud Ribbon Load Balancing

Notes May 13 1

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);

Related Articles

Designing Alertmanager Templates for Prometheus Notifications

How to craft Alertmanager templates to format alert messages, improving clarity and presentation. Alertmanager uses Go’s text/template engine with additional helper functions. Alerting rules referenc...

Deploying a Maven Web Application to Tomcat 9 Using the Tomcat Manager

Tomcat 9 does not provide a dedicated Maven plugin. The Tomcat Manager interface, however, is backward-compatible, so the Tomcat 7 Maven Plugin can be used to deploy to Tomcat 9. This guide shows two...

Skipping Errors in MySQL Asynchronous Replication

When a replica halts because the SQL thread encounters an error, you can resume replication by skipping the problematic event(s). Two common approaches are available. Methods to Skip Errors 1) Skip a...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.