Load Balancer in Springboot
Load balancing is a mechanism that ensures that incoming traffic to multiple servers or multiple instances of a service is distributed and no single server/instance is overwhelmed by too much traffic.
Load balancing can be of two types: Client side load balancing and Server side load balancing. Server side loading balancing is done outside of spring boot. Thus, we will learn in this tutorial client side load balancing using spring cloud load balancer.
Load Balancer enables service requests to be routed to multiple instances of a service in a load balanced fashion.
First of all, create a simple microservice that adds two numbers and returns the result of addition. Controller for the same service is as below
package com.jts;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class AdditionController {
@RequestMapping("/add/{n1}/{n2}")
public ResponseEntity<String> addTwoNumbers(@PathVariable int n1, @PathVariable int n2) {
int result = n1 + n2;
System.out.println("The result is = " + result);
return new ResponseEntity<String>("Result = " + result , HttpStatus.OK);
}
}
Now, run this service on two different ports: let’s say on 8082 and 8086. In Eureka Server it should show two different instances like below
Now, create another service that implements features of a load balancer.
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 https://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>3.3.4</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.jts</groupId>
<artifactId>boot-load-balancer-example</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>boot-load-balancer-example</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>17</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-loadbalancer</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>2023.0.3</version> <!-- Choose the latest 2023 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>
application.properties file
spring.application.name=boot-load-balancer-example
server.port = 8084
eureka.client.serviceUrl.defaultZone = http://localhost:8761/eureka
springboot application class
package com.sks;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
public class BootLoadBalancerExampleApplication {
public static void main(String[] args) {
SpringApplication.run(BootLoadBalancerExampleApplication.class, args);
}
@Bean
@LoadBalanced
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder.build();
}
}
Controller class
package com.sks;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
public class MyController {
@Autowired
private RestTemplate restTemplate;
@GetMapping("/invoke/{n1}/{n2}")
public String invokeService(@PathVariable int n1, @PathVariable int n2) {
String url = "http://AdditionService/add/" + n1 +"/" + n2 + "";
// Load balanced call to the service registered with Eureka as 'my-service'
String response = restTemplate.getForObject(url, String.class);
return "Response from my-service: " + response;
}
}
Test load balancing
Start the Eureka server. And Addition Service on two different ports
Now, make multiple requests to the load balancer service which eventually calls our Addition service. Notice the logs on the two instances, some calls will go to one instance while others should go to another resource.
Call going to another instance