The solution for a cloud-based microservice environment is to use a service-discovery mechanism that’s
- Highly available—Service discovery needs to be able to support a “hot” clustering environment where service lookups can be shared across multiple nodes in a service discovery cluster. If a node becomes unavailable, other nodes in the cluster should be able to take over.
- Peer-to-peer—Each node in the service discovery cluster shares the state of a service instance.
- Load balanced—Service discovery needs to dynamically load balance requests across all service instances to ensure that the service invocations are spread across all the service instances managed by it. In many ways, service discovery replaces the more static, manually managed load balancers used in many early web application implementations.
- Resilient—The service discovery’s client should “cache” service information locally. Local caching allows for gradual degradation of the service discovery feature so that if service discovery service does become unavailable, applications can still function and locate the services based on the information maintained in its local cache.
- Fault-tolerant—Service discovery needs to detect when a service instance isn’t healthy and remove the instance from the list of available services that can take client requests. It should detect these faults with services and take action without human intervention.
1. The architecture of service discovery
- Service registration—How does a service register with the service discovery agent?
- Client lookup of service address—What’s the means by which a service client looks up service information?
- Information sharing—How is service information shared across nodes?
- Health monitoring—How do services communicate their health back to the service discovery agent?
Once a service has registered with a service discovery service, it’s ready to be used by an application or service that needs to use its capabilities. Different models exist for a client to “discover” a service. A client can rely solely on the service discovery engine to resolve service locations each time a service is called. With this approach, the service discovery engine will be invoked every time a call to a registered microservice instance is made. Unfortunately, this approach is brittle because the service client is completely dependent on the service discovery engine to be running to find and invoke a service.
A more robust approach is to use what’s called client-side load balancing. Figure 4.3 illustrates this approach.
In this model, when a consuming actor needs to invoke a service
- It will contact the service discovery service for all the service instances a service consumer is asking for and then cache data locally on the service consumer’s machine.
- Each time a client wants to call the service, the service consumer will look up the location information for the service from the cache. Usually client-side caching will use a simple load balancing algorithm like the “round-robin” load balancing algorithm to ensure that service calls are spread across multiple service instances.
- The client will then periodically contact the service discovery service and refresh its cache of service instances. The client cache is eventually consistent, but there’s always a risk that between when the client contacts the service discovery instance for a refresh and calls are made, calls might be directed to a service instance that isn’t healthy.
If, during the course of calling a service, the service call fails, the local service discovery cache is invalidated and the service discovery client will attempt to refresh its entries from the service discovery agent.