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.