Load Balancing Spring Cloud Applications using Eureka and Spring Cloud Gateway
Spring Cloud Gateway + Eureka makes an amazing combination to scale Spring applications easily in production environments and load balance them effectively.
In this article I will focus on how we could build a simple Spring gateway application and demonstrate how it can perform laod balancing using default round-robbin strategy
What we need
- Eureka server
- Spring cloud gateway application
- Test application to test the load balancing
1. Create Eureka Server Application
- Create a Spring Boot application with below dependencies. Eureka will act as the service discovery server
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
- Enable Eureka server by annotating the main class with @EnableEurekaServer annotation
package com.example.eureka;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class EurekaApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class, args);
}
}
- Add necessary config in bootstrap.yml. In below sample, EUREKA_SERVER_ADDRESS (in this case it is http://localhost:8761) is an environment variable been passed to the application during runtime
spring:
application:
name: eureka
server:
port: 8761
eureka:
instance:
prefer-ip-address: true
client:
registerWithEureka: false
fetchRegistry: false
serviceUrl:
defaultZone: ${EUREKA_SERVER_ADDRESS}/eureka/
server:
waitTimeInMsWhenSyncEmpty: 0
2. Create Spring Cloud Gateway server
- Create a Spring Boot application with below dependencies
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</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>
</dependency>
- Add routing configuration in bootstrap.yml file. Note that we use the lb://<service-name> protocol to instruct gateway to lookup service via Eureka server
spring:
application:
name: gateway
cloud:
gateway:
routes:
- id: test-service
uri: lb://test-service
predicates:
- Path=/test/**
server:
port: 9000
eureka:
client:
registerWithEureka: true
serviceUrl:
defaultZone: ${EUREKA_SERVER_ADDRESS}
- Annotate the main application class with @EnableDiscoveryClient to enable eureka client and register it with Eureka server
package com.example.gateway;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
3. Create a test application to test load balancing
- Create a Spring Boot application with below dependencies
<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>
- Write a REST controller to print out the server details. This will help us to identify which instance of the service is called during our testing
package com.example.test.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
@RestController("/test")
public class TestController {
@GetMapping
public String testService(HttpServletRequest request) {
System.out.println("I am " + request.getRequestURL().toString());
return request.getRequestURL().toString();
}
}
- Annotate the main application class with @EnableDiscoveryClient. This will ensure that the service will get registered to Eureka server
package com.example.test;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class TestServiceApplication {
public static void main(String[] args) {
SpringApplication.run(TestServiceApplication.class, args);
}
}
Test it!
Above is all we need to test the load balancing. To test
- Start the Eureka server. You can use below maven command from the root of the project folder to start eureka server
mvn -pl eureka spring-boot:run -DskipTests -Dspring-boot.run.arguments= — EUREKA_SERVER_ADDRESS=http://localhost:8761/eureka
- Start the Gateway server. Run below command from project’s root folder
mvn -pl gateway spring-boot:run -DskipTests -Dspring-boot.run.arguments= — EUREKA_SERVER_ADDRESS=http://localhost:8761/eureka
- Now run multiple instances of test service. Choose different ports to avoid port conflict. You can use below maven command from the project’s root folder to run an instance of test service
Instance #1 on port 9001
mvn -pl test-service spring-boot:run -Dspring-boot.run.arguments= — EUREKA_SERVER_ADDRESS=http://localhost:8761/eureka -Dspring-boot.run.jvmArguments=-Dserver.port=9001
Instance #2 on port 9002
mvn -pl test-service spring-boot:run -Dspring-boot.run.arguments= — EUREKA_SERVER_ADDRESS=http://localhost:8761/eureka -Dspring-boot.run.jvmArguments=-Dserver.port=9002
- Access Eureka server console and make sure all services are listed there. A sample screen capture below. Note the 2 instances of test-service been registered in Eureka
- Now invoke the test-service via throught gateway. Our gateway is listening on port The REST service could be accessed via http://localhost:9000/test/. You will notice that the service URL printed in browser will keep switching between the instances on every call you make. This means the load-balancing is working perfectly in round-robbin strategy.
Hope this article will help to understand the load balancing technique for spring boot applications.
Remember to like and share the article :-). Thank you for reading.
A working version of the sample is available here https://github.com/negorp/spring_load_balancing