Client-side load balancing is used to balance incoming loads to the microservices because each service is typically deployed as multiple instances, so, for fault-tolerance and load-sharing, how do we decide which service instance to use?
Implementing client-side load balancing provides a way to distribute the load across multiple instances. The Discovery server returns the location of these multiple instances. The multiple instances are only for resilience and load-sharing, but the client needs to pick only one instance of the service. So, Spring Cloud Netflix Ribbon comes into the picture and provides several algorithms for client-side load-balancing. Spring also provides a smart RestTemplate.
Spring's RestTemplate is a smart client to call microservices registered on the Eureka server, and it automatically integrates two Netflix utilities, such as the Eureka Service Discovery and Ribbon client-side load balancer. Eureka returns the URL of all available instances. Ribbon determines the best available service to use. Just inject the load-balanced RestTemplate by using the @LoadBalanced annotation. And Spring Cloud provides @LoadBalanced annotation, it has built-in Service discovery and load balancing. Service Discovery is automatic lookup by using logical service-name of registered microservice.
Let's see following Maven dependency required for Ribbon:
<dependencies>
....
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
....
</dependencies>
As you can see, the spring-cloud-starter-netflix-ribbon starter will add the Ribbon libraries to your application. This includes the starters that we have added to create a web application and register this application to the Eureka as a service, such as spring-boot-starter-web and spring-cloud-starter-netflix-eureka-client.
Ribbon is a client-side load balancer that gives you a lot of control over the behavior of HTTP and TCP clients. And RestTemplate can be automatically configured to use Ribbon. To create a load-balanced RestTemplate, create an @Bean RestTemplate and use the @LoadBalanced qualifier:
package com.dineshonjava.ribbonclient;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
@EnableEurekaClient
public class RibbonClientApplication {
public static void main(String[] args) {
SpringApplication.run(RibbonClientApplication.class, args);
}
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
As you can see, the main application class has a bean definition for the RestTemplate. If you want to use RestTemplate in your application then you have to define a bean method for RestTempplate because a RestTemplate bean is no longer created via auto-configuration. It must be created by individual applications.
Now let's create a service by using this RestTemplate and call the service registered with Eureka:
package com.dineshonjava.ribbonclient.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
@Service
public class HelloServiceClient {
@Autowired
@LoadBalanced
RestTemplate restTemplate;
public String sayHello(){
return restTemplate.getForObject("http://SPRING-CLOUD-EUREKA-CLIENT/hello", String.class);
}
}
As you can see, here we have autowired the load-balanced RestTemplate to call the services. The RestTemplate is nothing but a high-level implement of the HTTP Client and exposed several methods to call services. But these methods need a URI, and the URI needs to use a virtual host name that is service name, not a host name.
Let's see the application configuration class, that is, application.yml:
spring: application: name: spring-cloud-ribbon-client server: port: 8181 eureka: client: service-url: default-zone: ${EUREKA_URI:http://localhost:8761/eureka} instance: prefer-ip-address: true
This configuration file has defined the application name as spring-cloud-ribbon-client, the server port as 8181, and other configurations as the same as we used earlier in this chapter.
Let's run this client application and open the browser with the http://localhost:8761/ URL:
As you can see, on the preceding Eureka Dashboard, there are two services registered as SPRING-CLOUD-EUREKA-CLIENT, and SPRING-CLOUD-RIBBON-CLIENT.
After running this example, we'll open our browser and go to http://localhost:8181/say-hello and it should display something like the following:
As you can see, RestTemplate called the SPRING-CLOUD-EUREKA-CLIENT service registered with Eureka to fetch the Hello to the Dineshonjava from Eureka Client! string.
Spring Cloud also supports another client that internally implements load-balancing functionality. Let's discuss another client that is already aware of the cloud registry. Here there is no need to get the information about a service's instance such as URI. You just give the application name.