Spring Cloud: Zuul, Eureka Integration in SpringBoot Applications

What is Zuul:  Zuul is a proxy server which uses filter to perform authentication, authorization, real-time monitoring, dynamic routing, load shedding, and static response handling. It can also be used for load testing as well. 

What is Eureka: Eureka is a REST based service that is used in cloud for locating instances of services for load balancing and failover of middle-tier servers. Eureka allows two microservices to communicate with each other without knowing each other’s whereabouts. Services just need to know the service names that they need to reach.

What is Eureka Client: It is any service that wants to discover other services.

What is Eureka Instance:  It is a microservice that wants to register with Eureka so that other microservices can discover and use it. 

What problem we are solving:  Using the above architecture we can deploy and undeploy services with zero downtime. We are also dynamically routing to multiple instances of services.

We will follow the below architecture and will deploy and undeploy services.

Create Service Discovery: For creating service discovery we will start with a sample Spring Boot project and follow the below steps. 

Maven configurations:  It contains actuator and eureka-server dependencies.


<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>


App properties: We will add below properties in service discovery application.yaml properties file. Most of the properties are default. You can tune according to your needs.

server:
 port: 8989
 address: 127.0.0.1
spring:
 application:
   name: service-discovery
eureka:
 environment: local
 rateLimiter:
   enabled: false
   throttleStandardClients: false
   burstSize: 10
   registryFetchAverageRate: 500
   fullFetchAverageRate: 100
 client:
   register-with-eureka: true
   fetch-registry: true
   service-url:
     defaultZone: http://yourUser:yourPassword@127.0.0.1:8989/eureka
 server:
   responseCacheUpdateIntervalMs: 30000
   minThreadsForPeerReplication: 5
   maxThreadsForPeerReplication: 20
   maxTimeForReplication: 30000
   minThreadsForStatusReplication: 1
   maxThreadsForStatusReplication: 1
   numberOfReplicationRetries: 5
   peerEurekaStatusRefreshTimeIntervalMs: 30000
   waitTimeInMsWhenSyncEmpty: 30000
   peerNodeConnectTimeoutMs: 200
   peerNodeReadTimeoutMs: 200
   peerNodeTotalConnections: 1000
   peerNodeTotalConnectionsPerHost: 500
 instance:
   leaseRenewalIntervalInSeconds: 30

To enable Eureka Server we will add @EnableEurekaServer to  ServiceDiscoverApplication class


package com.test.servicediscovery;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@SpringBootApplication
@EnableEurekaServer
public class ServiceDiscoveryApplication {

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

}

Now start the server. When you open http://127.0.0.1:8989/. As there are no services currently registered with service-discovery, you will see an empty table.


Now we will create a eureka client and zuul routing server.

Zuul Server: For creating Zuul Server we will start with sample spring boot project and follow the below steps. 

Maven configurations: It contains actuator, zuul, and eureka-client related dependencies.

 <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-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
        </dependency>

App properties:  We will add the below properties. We have added route path for product-search-service, user-service, and order-management-service. zuul.prefix  will capture all the requests starting with /api and will use route information to route it to the respective service.

server:
 port: 4444
spring:
 application:
   name: zuul-server
zuul:
 sensitiveHeaders: Cookie,Set-Cookie
 prefix: /api
 health:
   enabled: true
 routes:
   productSearchService:
     path: "/product-search-service/**"
     serviceId: product-search-service
     sensitiveHeaders: Cookie,Set-Cookie
     stripPrefix: true
   orderManagementService:
     path: "/order-management-service/**"
     serviceId: order-management-service
     sensitiveHeaders: Cookie,Set-Cookie
     stripPrefix: true
   userService:
     path: "/user-service/**"
     serviceId: user-service
     sensitiveHeaders: Cookie,Set-Cookie
     stripPrefix: true
 host:
   maxTotalConnections: 200
   maxPerRouteConnections: 20

ribbon:
 eager-load:
   enabled: true
 ConnectTimeout: 3000
 ReadTimeout: 60000
hystrix:
 command:
   default:
     execution:
       isolation:
         thread:
           timeoutInMilliseconds: 50000


eureka:
 client:
   register-with-eureka: true
   fetch-registry: true
   serviceUrl:
     defaultZone: http://yourUser:yourPassword@127.0.0.1:8989/eureka/
   registryFetchIntervalSeconds: 30
   instanceInfoReplicationIntervalSeconds: 30
   initialInstanceInfoReplicationIntervalSeconds: 40
   eurekaServiceUrlPollIntervalSeconds: 300
   eurekaServerReadTimeoutSeconds: 8
   eurekaServerConnectTimeoutSeconds: 5
   eurekaServerTotalConnections: 200
   eurekaServerTotalConnectionsPerHost: 50
   heartbeatExecutorThreadPoolSize: 2
   heartbeatExecutorExponentialBackOffBound: 10
   cacheRefreshExecutorThreadPoolSize: 2
   cacheRefreshExecutorExponentialBackOffBound: 10
   gZipContent: true
   preferSameZoneEureka: true
   filterOnlyUpInstances: true
   healthcheck:
     enabled: true
 instance:
   preferIpAddress: true
   leaseRenewalIntervalInSeconds: 30
   leaseExpirationDurationInSeconds: 90

To enable Zuul server add @EnableZuulProxy and to make it Eureka client add

@EnableEurekaClient annotation on ZuulServerApplication class

package com.test.zuulServer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;

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

Create user-service microservice: For creating the user-service let’s start with the sample springBoot project and follow the below steps.

Project structure:

Maven Configurations: It contains below dependencies.

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

App properties: 

server:
 port: 3333
spring:
 application:
   name: user-service
eureka:
 client:
   register-with-eureka: true
   fetch-registry: true
   serviceUrl:
     defaultZone: http://yourUser:yourPassword@127.0.0.1:8989/eureka/
   registryFetchIntervalSeconds: 30
   instanceInfoReplicationIntervalSeconds: 30
   initialInstanceInfoReplicationIntervalSeconds: 40
   eurekaServiceUrlPollIntervalSeconds: 300
   eurekaServerReadTimeoutSeconds: 8
   eurekaServerConnectTimeoutSeconds: 5
   eurekaServerTotalConnections: 200
   eurekaServerTotalConnectionsPerHost: 50
   heartbeatExecutorThreadPoolSize: 2
   heartbeatExecutorExponentialBackOffBound: 10
   cacheRefreshExecutorThreadPoolSize: 2
   cacheRefreshExecutorExponentialBackOffBound: 10
   gZipContent: true
   preferSameZoneEureka: true
   filterOnlyUpInstances: true
   healthcheck:
     enabled: true
 instance:
   preferIpAddress: true
   leaseRenewalIntervalInSeconds: 30
   leaseExpirationDurationInSeconds: 90

Similar zuulServer we will add @EnableEurekaClient to register with Eureka

package com.test.userservice;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

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


Similarly, we will create order-management-service and product-search-service

Adding more instances to the cluster:  Assume we got to add more instances, we can add easily changing instanceId of eureka client. InstanceId is composed of 

${spring.application.name}:${vcap.application.instance_id:${spring.application.instance_id:${random.value}}}

Lets add one more instance of product-search-service. We have just started the service with unique InstanceId, this service will be automatically discovered by other eureka clients in time(as you have configured).


Similarly, we can also add other instances of zuul-server and order-management-service.

Now to deregister service from service-discovery you can gracefully close the application or you can use api to manually deregister it.

DELETE :: http://127.0.0.1:8989/eureka/apps/rkc:product-search-service:1112product-search-service/rkc:product-search-service:1112

When you use execute above url , you will see that one of the product-search-service is not avaliable to other eureka clients