Master java skills

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