Using Spring Cloud Load Balancer In Microservices Communication

Using Spring Cloud Load Balancer In Microservices Communication

Almost a year ago Spring Cloud announced that most of Spring Cloud Netflix OSS projects will be moved to the maintenance mode starting from Spring Cloud GreenwichRelease Train. In fact, the maintenance mode only does not include Eureka, which still will be supported. I referred to that information in one of my previous articles The Future of Spring Cloud Microservices After Netflix Era. I have shared some opinions about the future of microservices with Spring Cloud. Of course, I also included an example of building microservices architecture without Netflix OSS using HashiCorp’s Consul, Spring Cloud Gateway and an early version of Spring Cloud LoadBalancer.
Today, the currently developed version of Spring Cloud Released Train is Hoxton (the next after Greenwich), so I decided to get back on track and update my example of microservices shared in the previous article. It might be slightly surprising, but I could find any working example presenting usage of the new built-in Spring Cloud LoadBalancer on the Internet. Probably the reason is that it is still under active development. I was able to build a working example with an auto-configured load balancer, without any additional part of the source code. Let’s take a look at how to implement load balancing with Spring Cloud.

Release Train

The Release Train version used in this article is Hoxton.M2. To access it we need to use the Spring Milestone repository.

<repositories>
   <repository>
      <id>spring-milestones</id>
      <name>Spring Milestones</name>
      <url>https://repo.spring.io/milestone</url>
   </repository>
</repositories>
<pluginRepositories>
   <pluginRepository>
      <id>spring-milestones</id>
      <name>Spring Milestones</name>
      <url>https://repo.spring.io/milestone</url>
   </pluginRepository>
</pluginRepositories>

Here’s declaration of release train inside dependency management section:

<parent>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-parent</artifactId>
   <version>2.2.0.RC1</version>
   <relativePath/>
</parent>
<properties>
   <java.version>1.8</java.version>
   <spring-cloud.version>Hoxton.M2</spring-cloud.version>
</properties>
<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>

Dependencies

Besides standard Spring Boot Web Starter we need to include starters for Consul discovery and config client, and of course spring-cloud-loadbalancer library. We should remember about excluding Ribbon and Hystrix artifacts from spring-cloud-starter-consul-discovery starter.

<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-starter-consul-discovery</artifactId>
   <exclusions>
      <exclusion>
         <groupId>org.springframework.cloud</groupId>
         <artifactId>spring-cloud-netflix-hystrix</artifactId>
      </exclusion>
      <exclusion>
         <groupId>org.springframework.cloud</groupId>
         <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
      </exclusion>
   </exclusions>
</dependency>
<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-starter-consul-config</artifactId>
</dependency>
<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-loadbalancer</artifactId>
</dependency>

Sample Applications

We have three sample applications. First callme-service exposes some REST endpoints, second caller-service communicates with the first using Consul discovery, RestTemplate and Spring Cloud Loadbalancer, and third gateway-service acts as API gateway in our architecture.

spring-cloud-load-balancing-1

The repository with source code snippets is available on GitHub: https://github.com/piomin/sample-spring-cloud-microservices-future.git. For some configuration details related to Consul discovery please refer to my previous article. In fact we don’t have to provide any additional code to make it working. We just have to declare RestTemplate bean annotated with @LoadBalanced:

@SpringBootApplication
public class CallerApplication {

   public static void main(String[] args) {
      SpringApplication.run(CallerApplication.class, args);
   }

   @LoadBalanced
   @Bean
   RestTemplate template() {
      return new RestTemplate();
   }
}

Then we may call the target service using its name taken from the discovery server:

@RestController
@RequestMapping("/caller")
public class CallerController {

   private static final Logger LOGGER = LoggerFactory.getLogger(CallerController.class);

   @Autowired
   Environment environment;
   @Autowired
   RestTemplate template;

   @GetMapping
   public String call() {
      String url = "http://callme-service/callme";
      String callmeResponse = template.getForObject(url, String.class);
      LOGGER.info("Response: {}", callmeResponse);
      return "I'm Caller running on port " + environment.getProperty("local.server.port")
            + " calling-> " + callmeResponse;
   }
   
}

Summary

In this article, I show you a working example of communication between microservices using the new Spring Cloud Load Balancer. I also tried to use that load balancer instead of Spring Cloud Netflix Ribbon inside my application with Spring Cloud Gateway – with no success. According to the newest documentation of Spring Cloud Circuit Breaker built on top of Resilience4J I tried to include circuit breaker in the communication between caller-service and callme-service – also with no success. These new Spring Cloud features are still under active development. I hope to use them successfully in my applications soon. For more advanced Spring Cloud load balancing usage please refer to the article A Deep Dive Into Spring Cloud Load Balancer.

16 COMMENTS

comments user
Daniel Truong

Thank you for that article! Very helpful. I’m a big fan of you 🙂

    comments user
    Piotr MiƄkowski

    Thanks 🙂

comments user
Van Dame

You can see this talk here
[youtube=https://www.youtube.com/watch?v=mINNQ3zpRrE&w=640&h=360]
to check out how to use the newest recommended stack which includes working SC Load Balancer, SC Circuit Breaker and Resilience4J.

    comments user
    Piotr MiƄkowski

    The presentation is ok, however the problem is that it still doesn’t work with Consul-based discovery on Spring Cloud Gateway. They show examples with Eureka discovery – but my article was not about it.

comments user
Piotr MiƄkowski

Since Hoxton.RC1 the problem with load balancing on Spring Cloud Gateway with Consul discovery has been fixed. The sample on GitHub has been actualized

comments user
Subramanian

Is there any update on spring cloud load balancer

    comments user
    Piotr MiƄkowski

    Yes, it is. Currently they fixed some problems and for example with Hoxton.RC1 release train spring cloud gateway and consul works fine. I have also updated version of release train in my repository.

comments user
Andrea Cavalieri

Nice article Piotr.
I am currently working on a spring boot project using spring cloud zuul (not nee cloud gateway) and I wonder if it is possible to integrate new spring cloud load balancer (instead of ribbon).
Thanks

comments user
Daniel Lopez

Very interesting. We are currently using a balancer (Fabio) instead of a client-balanced strategy like this one. Have you tried both? Any reasons to prefer this one?
Thanks

    comments user
    Piotr MiƄkowski

    Hi. I didn’t try Fabio…

comments user
Ivan Markov

Hi Piotr!, thanks for the article! I agree its a pity there is such a little documentation and working examples of the new Spring Cloud stack. I am now struggling to understand how can I configure the new Spring Cloud LoadBalancer with RestTemplate. Previously with Ribbon it was pretty much easy. Now the only tutorials I find are using Flux and Project Reactor for microservice communication. As of my project’s specification, I can’t use Consul or Eureka, so I would like to setup a static list of servers just like it was able using Ribbon. What is your opinion on this? Thanks!

comments user
srijini

Hi, thanks for ur article. now im experimenting spring cloud gateway load balancer.. i used the caller microservice. and i gave 8500 as port. but im getting error :
org.apache.http.conn.HttpHostConnectException: Connect to MY-IP:8500 [/MY-IP] failed: Connection refused (Connection refused)
Also i’m trying to integrate with Eureka server.

    comments user
    piotr.minkowski

    Hi, is it still occurs?

Leave a Reply