• Progen
    September 17, 2021

    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

    1. Eureka server
    2. Spring cloud gateway application
    3. 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 the 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