Introduction to Spring Cloud Rest Client with Netflix Ribbon
1. Introduction
Netflix Ribbon is an Inter Process
Communication (IPC) cloud library. Ribbon primarily provides client-side
load balancing algorithms.
Apart from the client-side load balancing algorithms, Ribbon provides
also other features:
-
Service Discovery Integration – Ribbon load balancers provide
service discovery in dynamic environments like a cloud. Integration with
Eureka and Netflix service discovery component is included in the ribbon
library -
Fault Tolerance – the Ribbon API can dynamically determine whether
the servers are up and running in a live environment and can detect
those servers that are down -
Configurable load-balancing rules – Ribbon supports
RoundRobinRule, AvailabilityFilteringRule,
WeightedResponseTimeRule out of the box and also supports defining
custom rules
Ribbon API works based on the concept called “Named Client”. While
configuring Ribbon in our application configuration file we provide a
name for the list of servers included for the load balancing.
Let’s take it for a spin.
2. Dependency Management
The Netflix Ribbon API can be added to our project by adding the below
dependency to our pom.xml:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency>
The latest libraries can be found
here.
3. Example Application
In order to see the working of Ribbon API, we build a sample
microservice application with Spring RestTemplate and we enhance it
with Netflix Ribbon API along with Spring Cloud Netflix API.
We’ll use one of Ribbon’s load-balancing strategies,
WeightedResponseTimeRule, to enable the client side load balancing
between 2 servers, which are defined under a named client in the
configuration file, in our application.
4. Ribbon Configuration
Ribbon API enables us to configure the following components of the load
balancer:
-
Rule – Logic component which specifies the load balancing rule we
are using in our application -
Ping – A Component which specifies the mechanism we use to determine
the server’s availability in real-time -
ServerList – can be dynamic or static. In our case, we are using a
static list of servers and hence we are defining them in the application
configuration file directly
Let write a simple configuration for the library:
public class RibbonConfiguration {
@Autowired
IClientConfig ribbonClientConfig;
@Bean
public IPing ribbonPing(IClientConfig config) {
return new PingUrl();
}
@Bean
public IRule ribbonRule(IClientConfig config) {
return new WeightedResponseTimeRule();
}
}
Notice how we used the WeightedResponseTimeRule rule to determine the
server and PingUrl mechanism to determine the server’s availability in
real-time.
According to this rule, each server is given a weight according to its
average response time, lesser the response time gives lesser the weight.
This rule randomly selects a server where the possibility is determined
by server’s weight.
And the PingUrl will ping every URL to determine the server’s
availability.
5. application.yml
Below is the application.yml configuration file we created for this
sample application:
spring:
application:
name: spring-cloud-ribbon
server:
port: 8888
ping-server:
ribbon:
eureka:
enabled: false
listOfServers: localhost:9092,localhost:9999
ServerListRefreshInterval: 15000
In the above file, we specified:
-
Application name
-
Port number of the application
-
Named client for the list of servers: “ping-server”
-
Disabled Eureka service discovery component, by setting eureka:
enabled to false -
Defined the list of servers available for load balancing, in this
case, 2 servers -
Configured the server refresh rate with ServerListRefreshInterval
6. RibbonClient
Let’s now set up the main application component snippet – where we use
the RibbonClient to enable the load balancing instead of the plain
RestTemplate:
@SpringBootApplication
@RestController
@RibbonClient(
name = "ping-a-server",
configuration = RibbonConfiguration.class)
public class ServerLocationApp {
@LoadBalanced
@Bean
RestTemplate getRestTemplate() {
return new RestTemplate();
}
@Autowired
RestTemplate restTemplate;
@RequestMapping("/server-location")
public String serverLocation() {
return this.restTemplate.getForObject(
"http://ping-server/locaus", String.class);
}
public static void main(String[] args) {
SpringApplication.run(ServerLocationApp.class, args);
}
}
We defined a controller class with the annotation @RestController; we
also annotated the class with @RibbonClient with a name and a
configuration class.
The configuration class we defined here is the same class that we
defined before in which we provided the desired Ribbon API configuration
for this application.
Notice we also annotated the RestTemplate with @LoadBalanced which
suggests that we want this to be load balanced and in this case with
Ribbon.
7. Failure Resiliency in Ribbon
As we discussed earlier in this article, Ribbon API not only provides
client side load balancing algorithms but also it has built in failure
resiliency.
As stated before, Ribbon API can determine the server’s availability
through the constant pinging of servers at regular intervals and has a
capability of skipping the servers which are not live.
In addition to that, it also implements Circuit Breaker pattern to
filter out the servers based on specified criteria.
The Circuit Breaker pattern minimizes the impact of a server failure on
performance by swiftly rejecting a request to that server that is
failing without waiting for a time-out. We can disable this Circuit
Breaker feature by setting the property
niws.loadbalancer.availabilityFilteringRule.filterCircuitTripped to
false.
When all servers are down, thus no server is available to serve the
request, the pingUrl() will fail and we receive an exception
java.lang.IllegalStateException with a message “No instances are
available to serve the request”.
8. Conclusion
In this article, we discussed Netflix Ribbon API and its implementation
in a simple sample application.
The complete source code for the example described above can be found on
the
GitHub
repository.