Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Service Discovery and Client-Side Load Balancing With Eureka and Ribbon

DZone's Guide to

Service Discovery and Client-Side Load Balancing With Eureka and Ribbon

Want to learn how to build an application with service discovery and client-side load balancing? Check out this post to learn more about using Eureka and Ribbon.

· Java Zone ·
Free Resource

Get the Edge with a Professional Java IDE. 30-day free trial.

Image title

Today, we are going to build an application with load balancing and service discovery. Traditionally, a load balancer is a separate application running that has all server nodes, as well. We will build an application where the client does not need to remember the IPs of a server, and we can dynamically add and remove nodes.

Let's start with app1 and app 2, which are two applications or servers with REST endpoints, such as /process . We are going to discover and load balance it. App1 and app2 will register themselves into the Eureka server with the name app-producer whenever they get started.

The app consumer is the consumer application, called app-producer, which also register themselves to the Eureka service registry as app-consumer.eureka .

Step-By-Step Code

A request comes to the app-consumer (localhost:7070/process), and the app consumer ask the Eureka server to show the available instances. Then, Eureka has two instances of the app-producer registered, so the client load balance is set in a round-robin manner.

Eureka Pom.xml

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

  <groupId>zuul</groupId>
  <artifactId>zuul</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

    <name>SpringBootHelloWorld</name>
<description>Demo project for Spring Boot</description>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.1.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zuul</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
  <dependency>
    <groupId>com.hazelcast</groupId>
    <artifactId>hazelcast</artifactId>
    <version>3.10.3</version>
</dependency>

<dependency>
    <groupId>com.hazelcast</groupId>
    <artifactId>hazelcast-client</artifactId>
    <version>3.10.3</version>
</dependency>

</dependencies>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Camden.SR6</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>


<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

</project>


Eureka app

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;

@SpringBootApplication
@EnableEurekaServer
public class Eureka 
{
  public static void main( String[] args )
    {
SpringApplication.run(Eureka.class, args);
    }   
}


App1 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>

<groupId>com.app1</groupId>
<artifactId>app1</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>

<name>app1</name>
<description>Demo project for Spring Boot</description>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>


</dependencies>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Camden.SR6</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>



<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>


</project>


App1 application

package com.app1.app1;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient
public class App1Application {

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


App1 REST endpoint

package com.app1.app1;

import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class AppController {

    @RequestMapping(value="/process", method = RequestMethod.GET)
    public @ResponseBody String  showLoginPage(ModelMap model){
        return "Processing aap1";
    }
}


App1 properties

server.port=8091
eureka.client.serviceUrl.defaultZone=http://localhost:8080/eureka
spring.application.name=app-producer
eureka.instance.instanceId=${spring.application.name}:${random.int}


For this tutorial, I am not adding code for app 2. Just create the same application as app1. The only change will be its REST endpoint, which will give us "Processing app2."

Now, let's start with app consumer:

application code

package com.app2.app2;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class AppConsumer {

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

@Bean
public  Client  client()
{
return  new Client();
}
}


REST endpoint with client-side balancing

package com.app2.app2;
import java.io.IOException;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.client.RestClientException;

@Controller
public class AppController {

@Autowired
private Client client;
@RequestMapping(value="/process", method = RequestMethod.GET)
    public @ResponseBody String  showLoginPage(ModelMap model) throws RestClientException, IOException{
        return client.getEmployee("/process");
    }


}
package com.app2.app2;

import java.io.IOException;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

public class Client {

@Autowired
private LoadBalancerClient loadBalancer;

public String getEmployee(String url) throws RestClientException, IOException {

ServiceInstance serviceInstance=loadBalancer.choose("app-producer");

System.out.println(serviceInstance.getUri());

String baseUrl=serviceInstance.getUri().toString()+url;


RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> response = null;
try {
response = restTemplate.exchange(baseUrl, HttpMethod.GET, getHeaders(), String.class);
} catch (Exception ex) {
System.out.println(ex);
}
return response.getBody();
}

private static HttpEntity<?> getHeaders() throws IOException {
HttpHeaders headers = new HttpHeaders();
headers.set("Accept", MediaType.TEXT_PLAIN_VALUE);
return new HttpEntity<>(headers);
}

}


application.properties

server.port=7070
eureka.client.serviceUrl.defaultZone=http://localhost:8080/eureka
spring.application.name=app-consumer
eureka.instance.instanceId=${spring.application.name}:${random.int}


Lastly, you will need to deploy all Spring Boot applications and hit the localhost:7070/process.

The output will be in a round-robin manner:

Processing aap1

Processing aap2

Processing aap1

Get the Java IDE that understands code & makes developing enjoyable. Level up your code with IntelliJ IDEA. Download the free trial.

Topics:
java ,spring cloud ,eureka ,service discovery ,load balancing ,tutorial

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}