1. Overview

In this article, we’ll look at how load balancing works with Zuul and Eureka.

We’ll route requests to a REST Service discovered by Spring Cloud Eureka through Zuul Proxy.

2. Initial Setup

We need to set up Eureka server/client as shown in the article Spring Cloud Netflix-Eureka.

3. Configuring Zuul

Zuul, among many other things, fetches from Eureka service locations and does server-side load balancing.

3.1. Maven Configuration

First, we’ll add Zuul Server and Eureka dependency to our pom.xml:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

3.2. Communication With Eureka

Secondly, we’ll add the necessary properties in Zuul’s application.properties file:

server.port=8762
spring.application.name=zuul-server
eureka.instance.preferIpAddress=true
eureka.client.registerWithEureka=true
eureka.client.fetchRegistry=true
eureka.client.serviceUrl.defaultZone=${EUREKA_URI:http://localhost:8761/eureka}

Here we’re telling Zuul to register itself as a service in Eureka and to run on port 8762.

Next, we’ll implement the main class with @EnableZuulProxy and @EnableDiscoveryClient. @EnableZuulProxy indicates this as Zuul Server and @EnableDiscoveryClient indicates this as Eureka Client:

@SpringBootApplication
@EnableZuulProxy
@EnableDiscoveryClient
public class ZuulConfig {
    public static void main(String[] args) {
        SpringApplication.run(ZuulConfig.class, args);
    }
}

We’ll point our browser to http://localhost:8762/routes. This should show up all the routes available for Zuul that are discovered by Eureka:

{"/spring-cloud-eureka-client/**":"spring-cloud-eureka-client"}

Now, we’ll communicate with Eureka client using Zuul Proxy route obtained. Pointing our browser to http://localhost:8762/spring-cloud-eureka-client/greeting should generate the response something like:

Hello from 'SPRING-CLOUD-EUREKA-CLIENT with Port Number 8081'!

4. Load Balancing with Zuul

When Zuul receives a request, it picks up one of the physical locations available and forwards requests to the actual service instance. The whole process of caching the location of the service instances and forwarding the request to the actual location is provided out of the box with no additional configurations needed.

Here, we can see how Zuul is encapsulating three different instances of the same service:

Zuul 1

Internally, Zuul uses Netflix Ribbon to look up for all instances of the service from the service discovery (Eureka Server).

Let’s observe this behavior when multiple instances are brought up.

4.1. Registering Multiple Instances

We’ll start by running two instances (8081 and 8082 ports).

Once all the instances are up, we can observe in logs that physical locations of the instances are registered in DynamicServerListLoadBalancer and the route is mapped to Zuul Controller which takes care of forwarding requests to the actual instance:

Mapped URL path [/spring-cloud-eureka-client/**] onto handler of type [class org.springframework.cloud.netflix.zuul.web.ZuulController]
Client:spring-cloud-eureka-client instantiated a LoadBalancer:
  DynamicServerListLoadBalancer:{NFLoadBalancer:name=spring-cloud-eureka-client,
  current list of Servers=[],Load balancer stats=Zone stats: {},Server stats: []}ServerList:null
Using serverListUpdater PollingServerListUpdater
DynamicServerListLoadBalancer for client spring-cloud-eureka-client initialized: 
  DynamicServerListLoadBalancer:{NFLoadBalancer:name=spring-cloud-eureka-client,
  current list of Servers=[0.0.0.0:8081, 0.0.0.0:8082],
  Load balancer stats=Zone stats: {defaultzone=[Zone:defaultzone;    Instance count:2;    
  Active connections count: 0;    Circuit breaker tripped count: 0;    
  Active connections per server: 0.0;]},
  Server stats: 
    [[Server:0.0.0.0:8080;    Zone:defaultZone;......],
    [Server:0.0.0.0:8081;    Zone:defaultZone; ......],

Note: logs were formatted for better readability.

4.2. Load-Balancing Example

Let’s navigate our browser to http://localhost:8762/spring-cloud-eureka-client/greeting a few times.

Each time, we should see a slightly different result:

Hello from 'SPRING-CLOUD-EUREKA-CLIENT with Port Number 8081'!
Hello from 'SPRING-CLOUD-EUREKA-CLIENT with Port Number 8082'!
Hello from 'SPRING-CLOUD-EUREKA-CLIENT with Port Number 8081'!

Each request received by Zuul is forwarded to a different instance in a round robin fashion.

If we start another instance and register it in Eureka, Zuul will register it automatically and start forwarding requests to it:

Hello from 'SPRING-CLOUD-EUREKA-CLIENT with Port Number 8083'!

We can also change Zuul’s load-balancing strategy to any other Netflix Ribbon strategy – more about this can be found in our Ribbon article.

5. Conclusion

As we’ve seen, Zuul provides a single URL for all the instances of the Rest Service and does load balancing to forward the requests to one of the instances in round robin fashion.

As always, the complete code for this article can be found over on GitHub.