Spring Cloud : Ribbon

Ribbon is a client side load balancer. Its was a developed by Netflix and open sourced. Spring cloud provides an easy wrapper aroud it for using. Traditionally load balancer are server side componenets that sits infornt of the applications. It distribute incoming traffic to several servers.
Client side load balancer is part of the client application and its purpose is to select which server (There may be multiple copies of the server application running that the client can call) to call. You may be thinking why do we need a client side load balancer when we laready have a server side load balancer.  In Microservce world this is reqired if you are running many servers instances. Some of them are :

  • Some servers ay be unavailable (faults). also what if the server side load balancer is offline.
  • Some servers may be slower than others (performance).
  • Some servers may be further away from others (regions).

Ribbon automatically integrates with service dicovery (Eureka). It even supports things like caching and batching. Caching is when you avoid a client to do a remote call entirely because it has save result in the recent call. Batching is when several request are grouped together into one call. It support multiple protocols like HTTP, TCP, UDP.

Key Ribbon Concepts :

  • Server lists : Determine whats the list of possible servers are for a given client service. This can be done in 2 ways. static – populated via some configuration or dynamic – populated via service discovery mechanism like Eureka. Default is Eureka. It its not Eureka you have to provide it in the application.yml or a config server , the list of servers available for a server , etc.
  • Filtered list of server : Criteria by which you wish to limit the total list. Spring cloud default is to filter servers in the same zone.
  • Ping : Used to test if the server is up or down. Spring cloud defaultdelegate to Eureka to determine if the server is up or down. If you have noticed that Eureka doesnt straight away knows that a registered client went down. There is a bit of delay for eureka to know this when it stops receiving the ping from the registered service.
  • Load balancer : his is the actual component that routes the calls to the servers in the filtered list. Several stratergies are available, but they usually defer to a Rule component to make the actual decisions. Spring clouds default is ZoneAwareloadBalancer
  • Rule : is the single module of intelligence that makes the decisions on whether to call or not. Spring cloud default is ZoneAvoidanceRule.

All these defaults can be changed , but lets go ahead with the defaults for now.

Lets have a Eureka server and a user-service that has 2 instances running (on port 8010 and 8020). You can take help form my Eureka post.

spring-ribbon1

Lets creat a ribbon client. pom.xml


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.2.RELEASE</version>
<relativePath />
</parent>

<groupId>com.mynotes.spring.cloud</groupId>
<artifactId>ribbon-client</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>ribbon-client</name>
<description>Demo project for Spring Cloud cloud ribbon-client</description>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Camden.SR3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>

As you can see, we do not need any specific ribbon related dependencies. Infact you can remove the eureka one too if you dont want this app to register itself to Eureka.

Configuration file application.yml. We just have to tell about the eureka server.


server:
  port: 8090

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

Writing the RibbonClientApplication.java:


package com.mynotes.spring.cloud.ribbon;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.stereotype.Component;

@SpringBootApplication
public class RibbonClientApplication {

public static void main(String[] args) {
SpringApplication.run(RibbonClientApplication.class, args);
}

}

@Component
class RibbonRunner implements CommandLineRunner {
@Autowired
LoadBalancerClient loadBalancer;

@Override
public void run(String... args) throws Exception {
System.out.println("Inside Ribbon Runner");
ServiceInstance instance=loadBalancer.choose("user-service");
System.out.println("=======RIBBON=================");
System.out.println("URI==>>"+instance.getUri());

}
}

 

Above we used a CommandLineRunner just for testing purpose. We autowired a LoadBalancerClient, and asked it to choose a ‘user-service’. It will go to Eureka and find the best . Lets run

spring-ribbon2

You probably wont be using Ribbon directly as its integrated with Feign, Springs Resttemplate and Zuul.
Spring RestTemplte is Ribbon aware. Lets see this via exmaple:


@Component
class RestTemplateRunner implements CommandLineRunner {
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}

@Autowired
RestTemplate restTemplate;

@Override
public void run(String... args) throws Exception {

String result = restTemplate.getForObject("http://user-service/users/getPublicMailingAddress", String.class);
System.out.println("=======RestTemplate=================");
System.out.println("RESULT===>" + result);

}
}

Notice that you have to do an injection of RestTemplate. If you just do a new RestTemplate() , it wont work. You have to create a bean with annotation @Loadbalanced. This is as per Camden release.
As you can see , here we just have to give the user-service name. Since it is integrated with ribbon, it automatically gets the best possible instance from the eureka and runs.

spring-ribbon3

Next we will see how to use Feign, which is a wrapper around ribbon. You can get the code from my github repo.

Advertisements
%d bloggers like this: