In a monolithic architecture, we deployed a few application servers and statically registered them with load balancers. But in Microservices-based architectures, inherently the services are mobile and can come and go because of auto-scaling, self-healing etc.
So the clients need a way for looking up the services they want to talk to. Essentially we need a way for mapping logical service names to one or more network paths.
To accomplish this, we need to implement a service discovery mechanism. This usually has 3 parts:
- Service registry: This is a database of all the services and their network locations.
- Strategy for building up this database. i.e., registering the services.
- Strategy for service lookup.
There are several great options for service registry these days. Netflix Eureka, Consul, and ZooKeeper to name a few.
Registering the services
Whenever a service starts up or shuts down, the service registry needs to know about this. This can be implemented in 2 ways.
Every service when it starts up, registers with the service registry. If the registry requires meta-data, this also should be provided by the service itself. Netflix OSS Eureka client is an example of this where each service registers with Eureka on startup and also sends a heartbeat every 30 seconds. If the heartbeat fails, Eureka removes the service from its registry.
This is a bit of a design smell as the individual services have the additional responsibility of knowing about the service registry. But it’s simple and easy to get started with.
In this pattern, individual Microservices are blissfully unaware of service registry concerns. There is a third-party component that discovers and registers Microservices by polling specific files in the deployment environment or by subscribing to events. This component is also responsible for de-registering services that are no longer available. This is more prevalent in more mature implementations.
Registrator is a good example of this pattern. Here is a good article on this: https://www.airpair.com/scalable-architecture-with-docker-consul-and-nginx.
A big advantage of this pattern is that services are decoupled from service registries. A disadvantage is that the third-party component has to be installed and configured, but many Microservices environment like Kubernetes comes with one.
Once the service registry database is built up, clients should be able to look up services. This can be implemented in 2 ways:
The client is responsible for connecting to the service registry and looking up the service. Similar to self-registration, a client is coupled with service registry concerns. Netflix OSS Ribbon is an example of this. Netflix Ribbon is used to look up and communicate with services. Ribbon comes with the basic round-robin based load balancing and fault tolerance.
Though the client’s ability to implement custom load-balancing strategies is touted as an advantage of this pattern, in our experience we have hardly seen the need for this.
Here clients make the request for any service to a router/load balancer which is responsible for talking to the service registry and returning a suitable service instance. The router can additionally help with metrics, AB testing, Canary releases, etc.
Another good option if you are in AWS and especially if you deploy your Microservices as Docker containers is the newly launched AWS application load balancer.
Here is a good article on this: Amazon ECS Reference Architecture
Are you looking to build a great product or service? Do you foresee technical challenges? If you answered yes to the above questions, then you must talk to us. We are a world-class custom .NET development company. We take up projects that are in our area of expertise. We know what we are good at and more importantly what we are not. We carefully choose projects where we strongly believe that we can add value. And not just in engineering but also in terms of how well we understand the domain. Book a free consultation with us today. Let’s work together.