December 02, 2019

Part 5: Microservices Demo (Service Discovery using Eureka)

Why use Service Discovery?
Service discovery is how applications and (micro)services locate each other on a network. Service discovery implementations include both: a central server (or servers) that maintain a global view of addresses and clients that connect to the central server to update and retrieve addresses.

Let’s imagine that we are writing some code that invokes a service that has a REST API. In order to make a request, our code needs to know the network location (IP address and port etc) of a service instance.

In a traditional application running on physical hardware, the network locations of service instances are relatively static. For example, our code can read the network locations from a configuration file that is occasionally updated. In a modern, cloud-based microservices application, however, this is a much more difficult problem to solve.

Service instances have dynamically assigned network locations. Moreover, the set of service instances changes dynamically because of autoscaling, failures, and upgrades. Consequently, our client code needs to use a more elaborate service discovery mechanism.

There are two main service discovery patterns: clientside discovery and serverside discovery.

Spring cloud use clientside discovery.

Service Discovery Patterns:
  • Client-side discovery - client queries a service registry to discover the locations of service instances
  • Server-side discovery - router queries a service registry to discover the locations of service instances
  • Service registry - a database of service instance locations
  • Self registration - service instance registers itself with the service registry
  • 3rd party registration - a 3rd party registers a service instance with the service registry
In a monolithic application, services invoke one another through language-level method or procedure calls. In a traditional distributed system deployment, services run at fixed, well known locations (hosts and ports) and so can easily call one another using HTTP/REST or some RPC mechanism.

However, a modern microservice-based application typically runs in a virtualized or containerized environments where the number of instances of a service and their locations changes dynamically.

Client-side Service Discovery Pattern
When making a request to a service, the client obtains the location of a service instance by querying a Service Registry, which knows the locations of all service instances.

Client-side discovery has the following benefits:
  • Fewer moving parts and network hops compared to Server-side Discovery
Client-side discovery also has the following drawbacks:
  • This pattern couples the client to the Service Registry
  • You need to implement client-side service discovery logic for each programming language/framework used by your application, e.g Java/Scala, JavaScript/NodeJS. For example, Netflix Prana provides an HTTP proxy-based approach to service discovery for non-JVM clients.
Server-side Service Discovery Pattern
When making a request to a service, the client makes a request via a router (a.k.a load balancer) that runs at a well known location. The router queries a service registry, which might be built into the router, and forwards the request to an available service instance.

Server-side service discovery has a number of benefits:
  • Compared to client-side discovery, the client code is simpler since it does not have to deal with discovery. Instead, a client simply makes a request to the router.
  • Some cloud environments provide this functionality, e.g. AWS Elastic Load Balancer.
It also has the following drawbacks:
  • Unless it’s part of the cloud environment, the router must is another system component that must be installed and configured. It will also need to be replicated for availability and capacity.
  • The router must support the necessary communication protocols (e.g HTTP, gRPC, Thrift, etc) unless it is TCP-based router
  • More network hops are required than when using Client Side Discovery
Service Registry Pattern
A service registry is a database of services, their instances and their locations. Service instances are registered with the service registry on startup and deregistered on shutdown.

Client of the service and/or routers query the service registry to find the available instances of a service. A service registry might invoke a service instance’s health check API to verify that it is able to handle requests.

Some examples of service registries (or technologies that are commonly used as service registries) include: Netflix Eureka, Apache Zookeeper, Consul and Etcd. Some systems such as Kubernetes, Marathon and AWS ELB have an implicit service registry.

Self Registration Pattern
A service instance is responsible for registering itself with the service registry. On startup the service instance registers itself (host and IP address) with the service registry and makes itself available for discovery.

The client must typically periodically renew its registration so that the registry knows it is still alive. On shutdown, the service instance unregisters itself from the service registry. This is typically handled by a Microservice chassis framework

3rd Party Registration Pattern
A 3rd party registrar is responsible for registering and unregistering a service instance with the service registry.

When the service instance starts up, the registrar registers the service instance with the service registry. When the service instance shuts downs, the registrar unregisters the service instance from the service registry.

How Can You Set Up Service Discovery?
There are multiple ways to set up service discovery. One of the best efficient ways is Eureka by Netflix. It is a hassle-free procedure that does not weigh much on the application. Plus, it supports numerous types of web applications.

Eureka configuration involves 2 steps: Client configuration and server configuration.

Client configuration can be done easily by using the property files. In the classpath, Eureka searches for eureka-client.properties. It also searches for overrides caused by the environment in property files that are environment-specific.

For Server configuration, you have to configure the client first. Once that is done, the server fires up a client which is used to find other servers. The Eureka server, by default, uses the Client configuration to find the peer server.

What is Eureka Server?
There are several popular options for service registries. Netflix built and then open-sourced their own service registry, Eureka. Another new, but increasingly popular option is Consul. Eureka is implemented on the JVM but Consul is implemented in Go.

Eureka Server is an application that holds the information about all client-service applications. Every Micro service will register into the Eureka server and Eureka server knows all the client applications running on each port and IP address.

Eureka Server is also known as Discovery Server.

Microservice Registration and Discovery with Spring Cloud and Netflix's Eureka
In the previous post, we have developed three micro-services. In this post, we’ll look at how Spring Cloud helps you manage that complexity with a service registry like Eureka and Consul and client-side load-balancing.

You can download the code for simple micro-services (which we developed in previous post) from the below GIT URL.

GIT URL: microservices

In the getDetails API, we had hard-coded URL's of getDepartmentDetails and getEmployeeDetails. Now, we will use Spring Cloud and Eureka to discover those URL's instead of hard-coding them.

Creating and Starting Eureka Server

We will create another Spring Boot project with name 'discovery-server' and use it as our Discovery Server. We need to add Eureka Server dependency in the project.

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

We need to add @EnableEurekaServer annotation. The @EnableEurekaServer annotation is used to make your Spring Boot application acts as a Eureka Serverp.

Then add below properties in application.properties file, so that Eureka does not register's with itself. Every Eureka server is also a Eureka client, below properties will tell Eureka server to stop acting like a client. FYI, server.port is optional, by default Eureka server always start at port 8761.

server.port=8761
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false

When you run discovery-server project you will see the discover server is started at port number 8761. To verify if the server is started or not open
http://localhost:8761/ in browser.


Creating Eureka Client

We need to add below dependency in depart-employee-details, department-details and employee-details, this will make them eureka client.

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

Now, we need to add the @EnableEurekaClient annotation in the main Spring Boot application class file of depart-employee-details, department-details and employee-details. The @EnableEurekaClient annotation makes your Spring Boot application act as a Eureka client.

After this we need to add spring.application.name in the application.properties file.
1). depart-employee-details
spring.application.name = depart-employee-details
2). department-details
spring.application.name = department-details
3). employee-details
spring.application.name = employee-details

Discovering services through Eureka

Client side vs server side load balancing
The multiple instances of the same microservice is run on different computers for high reliability and availability. Server side load balancing is distributing the incoming requests towards multiple instances of the service. Client side load balancing is distributing the outgoing request from the client itself.

@LoadBalanced annotation enable RestTemplate to have load balancing capabilities. In Spring Cloud microservice application system, remote calls should be load balanced. When we use RestTemplate as a remote call client, it's extremely simple to turn on load balancing by adding a @LoadBalanced annotation.

We need to annotate RestTemlate Bean (which we have created in DepartEmployeeDetailsApplication.java of depart-employee-details project with @LoadBalanced
In the getDetails API instead of using localhost we will pass service names.

Start all the projects discovery-server, employee-details, department-details and then depart-employee-details. If you open http://localhost:8761/ in browser, you will see all the three services registered with it.


Download the code till now from below GIT url:
GIT URL: microservices

-K Himaanshu Shuklaa..

No comments:

Post a Comment