Service Discovery

Where is my service?

In a microservice application, every service is deployed to a specific host. When calling the service, it may be tempting to simply use a fixed hostname or IP Address to resolve the service, but unfortunately, this quickly leads to failure when dealing with elastic microservices.

Due to the elastic nature of these microservices, their hostnames and IP addresses are not static. Elastic services are created and destroyed based on the service's current load and may be deployed to various hosts according to resource availability. The dynamic assignment of a service's network location poses a serious problem. How do you connect to an endpoint if you don't know where it is deployed?

The fundamental theorem of Software engineering


"We can solve any problem by introducing an extra level of indirection."

- The fundamental theorem of software engineering (FTSE), originated by Andrew Koenig to describe a remark by Butler Lampson attributed to the late David J. Wheeler

In much the same way that the Domain Name System (DNS) allows us to find an IP address by domain name using a DNS server, we solve the problem of finding a service endpoint by introducing a Service Registry and Discovery Service.

The Service Registry

The Service Registry plays a vital role in the process of finding an endpoint. As the name implies, The Service Registry provides a database of the application's active services. This service needs to be highly available as it plays a part in every service invocation. The registry provides two primary functions: registration & query.



Service Registration

The registration function is responsible for receiving messages from each service provider instance indicating its ability to service requests. After each service instance is initialized, it notifies the registry of its presence by transmitting its metadata to the registry. The metadata generally includes the service provider's name, Host/IP address, service port as well as any other metadata the registry may support.

In a perfect world, each service provider would de-register itself before it stopped servicing requests. Unfortunately, In the real world, a service can fail without warning. If we expect a service to de-register prior to termination, a failure would leave entries in the registry pointing to unreachable services.

Health Check

A better approach is for the registry to require each active service provider to notify that it is still alive by periodically transmitting a heartbeat signal. When the registry fails to receive the heartbeat signal within the expected interval, the service provider is removed from the registry's table of active services.

Service Query

The second function of the Service Registry to provide a mechanism to query active services. The query function allows its clients to query a service by name and returns the set of all the active instances of that named service.

Avoiding the single point of failure

Due to the critical role the Service Registry serves in the application, it needs to be highly available. Every service invocation must first query the service registry to find an active endpoint. If the registry fails, the application fails. To avoid this situation, it is a common practice to deploy multiple instances of the service registry fronted with a load balancer. This redundancy allows a single instance of the Service Registry to crash without affecting overal service registry and query functions.

Service Discovery

The second part of the solution is Service Discovery, which, when queried, returns a single instance of the desired service. In addition to querying the service registry, Service Discovery is responsible for providing the necessary logic used to balance the load across the multiple instances in the query response.

There are two ways Service Discovery can be accomplished: Client-Side Discovery and Server-Side Discovery.

Client-Side Service Discovery

In this approach, each service client queries the registry directly. From the query response, the service client chooses which service provider endpoint it will use. Client-side Service Discovery tightly couples the service client to the service registry and requires that each service implementation language provides a parallel implementation of the common service discovery client.

Client-Side discovery

Server-Side Service Discovery

In Server-Side Service Discovery, the responsibility of service discovery is moved to a router service which provides load-balancing in addition to service registry query. Server-Side Service Discovery simplifies the service client code as it only needs to know the location of the router, which is responsible for directing the call to an appropriate service provider. The downside of this of twofold. First, we need to provision and deploy another highly-available service to manage the routing. Second, there is an additional delay in response as the router must invoke the service provider and proxy back the response.

Server-Side discovery

Summary

Service Discovery plays a crucial role in supporting microservice architectures. Service Discovery is composed of a Service Registry which stores the currently active services, and a Service Discovery client which queries the Service Registry and performs load balancing functions.

Coming Up

We've had an opportunity to look at one pattern to find services in our microservice architecture. In our next article, we will take a look at a way to simplify how clients interact with our microservice application by introducing the API Gateway pattern.