April 20, 2021

Unified Interface for Microservice Registration and Discovery

As in typical monolithically-architectured applications, some applications are deployed over to application servers and statically registered with load balancers. But as we move towards microservices-based architectures, services may scale up and down based on certain pre-defined metrics or due to auto-scaling. This dynamic nature of service endpoint addresses is handled by service registration and discovery. Each service registers with a broker and provides more details about itself, such as the endpoint address. Other consumer services then query the broker to find out the location of a service and invoke it.

In this blog, we will talk about three concepts for a sound microservice architecture – service discovery, client-side load balancing, and a Non-JVM client. We will also see how the dynamic scaling of services takes place.

Eureka Service Registry

The service registry is a kind of database populated with information on how to dispatch requests to microservice instances. Whenever a service endpoint changes, the registry needs to know about the change. This is what registration is all about; who publishes or updates the information on how to reach each service. Netflix Eureka, in our case, will tell users where services register themselves with a known Eureka instance and then will intermittently send heartbeats to make sure the Eureka instance(s) know they’re still alive. Let’s start the Eureka registry server for services:

First, we create a new Maven project and put the dependencies into it.


<dependency>

<groupId>org.springframework.cloud</groupId>

<artifactId>spring-cloud-starter-eureka-server</artifactId>

<version>1.1.5.RELEASE</version>

</dependency>

Next, we’re creating the main application class:

@SpringBootApplication

@EnableEurekaServer

public class EurekaServerApplication {

public static void main(String[] args) {

SpringApplication.run(EurekaServerApplication.class, args);

}

}

 

Then, we configure the properties for the Eureka server, so an application.properties will be our configuration file:


server.port=8764

eureka.client.register-with-eureka=false

eureka.client.fetch-registry=false

logging.level.com.netflix.eureka=OFF

logging.level.com.netflix.discovery=OFF

 

Here we’re configuring an application port – 8764 is the default one for Eureka servers. We are telling the built-in Eureka client not to register with ‘itself’ because our application should be acting as a server.

Now we will point our browser to http://localhost:8764 to view the Eureka dashboard, where we will later inspect the registered instances.

 

Enable client application for service registry

To register our application service with the Eureka server, we will make the following configuration in application service.


@SpringBootApplication

@EnableDiscoveryClient

public class ServiceApplication {

public static void main(String[] args) {

SpringApplication.run(ServiceApplication.class, args);

}

}

 

Then we configure the application service properties like application.properties:


spring.application.name=eureka-application

eureka.client.serviceUrl.defaultZone=http://localhost:8764/eureka/

server.port=9080

 

The service points to Eureka using the specified ‘eureka.client.serviceUrl.defaultZone’ value. By default, services will try to connect to localhost:8761/eureka server.

After that, we need to start our client service application and point our browser to http://localhost:8764. The client service application is now registered with the Eureka server.

 

Service discovery and client-side load balancing using Ribbon

As you can imagine, discovery is the counterpart to registration from the point of view of clients. When a client wants to access a service, they must find out where the service is located (and other relevant information to perform the request).

The client is responsible for connecting to the service registry and looking up the service to get actual address information (IPs, hostnames, ports) of services they need to call. The client is coupled with service registry concerns. An example of a client-side load balancer in the Spring Cloud ecosystem is Netflix Ribbon. Netflix Ribbon is used to look up and communicate with services. Ribbon comes with the basic round-robin based load balancing and fault tolerance.


@SpringBootApplication

@RibbonClient(name = "ribbonservice",configuration=SayHelloConfiguration.class)

public class RibbonClientApplication {

public static void main(String[] args) {

SpringApplication.run(RibbonClientApplication.class, args);

}

@LoadBalanced

@Bean

public RestTemplate restTemplate(RestTemplateBuilder builder) {

return builder.build();

}

}

Unified interface for a non-JVM based client using a proxy

A Java-based client can easily invoke microservices using a Ribbon client, so we extended this to make it possible for a non-JVM based client using proxy over HTTP to invoke it.

 

Here we are using restTemplate returned by the Ribbon client, so it will provide us with an easy mechanism for load balancing as well as service discovery.

Using this approach in microservice architecture, we get the benefit of client-side load balancing and service discovery. Microservices can be easily invoked by non-JVM clients.