Load Balancing Services with Eureka Example
What is Load Balancing?
Load balancing means efficient distribution of incoming network traffic across a backend servers. It distributes client requests or network traffic efficiently across multiple servers.
Eureka Load Balancing In Action
Eureka is a REST (Representational State Transfer) based service that is primarily used in the AWS cloud to locate services for load balancing and failure of middle-tier servers.
Eureka Load Balancing Flow
Eureka Server - Project Structure
Let's begin with creating Eureka Server and then will create services called Ticket Rate Service and it's UI Service.Create Spring Boot Eureka Server Project
Create Spring Boot Project from Spring Initializer site https://start.spring.io/.pom.xml
If you see, we addedspring-cloud-starter-eureka-server
dependencies in 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>techgeeknext.eureka.server</groupId>
<artifactId>techgeeknext-eureka-server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>techgeeknext-eureka-server</name>
<description>Demo project for Spring Cloud Eureka</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.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>
<spring-cloud.version>Dalston.SR1</spring-cloud.version>
</properties>
<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-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-actuator</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</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>
Properties
We don't want this service to register with Eureka, because this a Eureka Server, so makeregister-with-eureka
flag false.
# set port
server.port=8761
# no need to register the server with the server
eureka.client.register-with-eureka=false
# don't need a local copy of the registry
eureka.client.fetch-registry=false
# value used for AWS, here can be anything
eureka.datacenter=techgeeknext-datacenter
eureka.environment=dev
Main Class
Add@EnableEurekaServer
annotation in the main class to denote this service as Eureka Server.
package techgeeknext.eureka.server;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@EnableEurekaServer
@SpringBootApplication
public class TechgeeknextEurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(TechgeeknextEurekaServerApplication.class, args);
}
}
Testing Eureka in Dashboard
Run this application, and goto http://localhost:8761/, and you can see Eureka Server up and running without any services register. In this tutorial, will create two services called rate-service and other service to display rates from rate-service using Eureka Load Balancing. Let's start creating services.techgeeknext-eureka-rate-service
Define your service name in bootstrap.propertiesspring.application.name=techgeeknext-rate-service
Properties
Register this service as a client in Eureka Server.eureka.client.register-with-eureka=true
eureka.client.fetch-registry=false
eureka.instance.hostname=localhost
eureka.instance.instance-id=${spring.application.name}:${random.int}
eureka.client.healthcheck.enabled=true
server.port=0
pom.xml
Add
spring-cloud-starter-netflix-eureka-client
dependencies.
<?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>techgeeknext.rate</groupId>
<artifactId>techgeeknext-eureka-rate-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>techgeeknext-eureka-rate-service</name>
<description>Demo project for Spring Cloud Eureka</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.RELEASE</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<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.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</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>
Main class
We're going to add an annotation to the primary class so it's actually a client and pulls down that registry Add
@EnableEurekaClient
annotation to declare this service as Eureka Client.
package techgeeknext.rate;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@EnableEurekaClient
@SpringBootApplication
public class TechgeeknextEurekaRateServiceApplication {
public static void main(String[] args) {
SpringApplication.run(TechgeeknextEurekaRateServiceApplication.class, args);
}
}
Controller
Create Rest End point called GetTicketRate with the url /rate/{stationId}.package techgeeknext.rate;
import java.math.BigDecimal;
import java.time.Instant;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TicketRateController {
@RequestMapping("/rate/{stationId}")
public TicketRate GetTicketRate(@PathVariable int stationId) {
TicketRate ticketRate;
System.out.println("Station Id : " + stationId);
switch(stationId) {
case 1:
ticketRate = new TicketRate(stationId, new BigDecimal("0.32"), Instant.now().toString());
break;
case 2:
ticketRate = new TicketRate(stationId, new BigDecimal("1.02"), Instant.now().toString());
break;
case 3:
ticketRate = new TicketRate(stationId, new BigDecimal("0.40"), Instant.now().toString());
break;
default:
ticketRate = new TicketRate(stationId, new BigDecimal("1.00"), Instant.now().toString());
break;
}
return ticketRate;
}
}
Testing Rate Service in Eureka Dashboard
Run this application, and goto http://localhost:8761/, and you can see rate services got register with Eureka Server.Open and click on the register service and append the url parameter as given below.
techgeeknext-eureka-rate-display
Define your service name in bootstrap.propertiesspring.application.name=techgeeknext-rate-display-UI
Properties
Register this service as a client in Eureka Server.server.port=8081
eureka.client.register-with-eureka=true
eureka.client.fetch-registry=true
eureka.instance.instance-id=${spring.application.name}:${random.int}
pom.xml
Add
spring-cloud-starter-netflix-eureka-client
dependencies.
<?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>techgeeknext.rate</groupId>
<artifactId>techgeeknext-eureka-rate-display</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>techgeeknext-eureka-rate-display</name>
<description>Demo project for Spring Cloud Eureka Load Balancing</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.RELEASE</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<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.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</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>
Main class
Add
@EnableEurekaClient
annotation to declare this service as Eureka Client.
package techgeeknext.rate;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@EnableEurekaClient
@SpringBootApplication
public class TechgeeknextEurekaRateDisplayApplication {
public static void main(String[] args) {
SpringApplication.run(TechgeeknextEurekaRateDisplayApplication.class, args);
}
}
Controller
Create Rest End point called GetTicketRate with the url /dashboard. You can Load Balanced the RestTemplate using@LoadBalanced
annotation.
So it's actually going to use that information from the registry to figure out where to call the service. We have used techgeeknext-rate-service
service registered in the eureka.
package techgeeknext.rate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.client.RestTemplate;
@Controller
public class RateController {
@LoadBalanced
@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder.build();
}
@Autowired
private RestTemplate restTemplate;
@RequestMapping("/dashboard")
public String GetTicketRate(@RequestParam int stationId, Model m) {
TicketRate tr = restTemplate.getForObject("http://techgeeknext-rate-service/rate/" + stationId, TicketRate.class);
m.addAttribute("rate", tr.getCurrentRate());
return "dashboard";
}
}
Testing Rate Service in Eureka Dashboard
Run this application, and goto http://localhost:8761/, and you can see rate services got register with Eureka Server.Testing Load balancing Rate Service using Eureka
Goto http://localhost:8081/dashboard?stationId=2 (techgeeknext-rate-display-UI) url as given below and you can see it's fetching ticket rate from ticket rate service (techgeeknext-rate-service) using service registered in Eureka.Download Source Code
The full source code for this article can be found on below.Download it here - Load Balancing Services With Eureka