Why use service discovery?

When invoking a service from the REST API or Thrift API, we usually need to know the IP and port of the service instance when building the request. In traditional applications, the address information of the service instance is fixed and can be read from the configuration file. And those addresses are only updated occasionally.

However, in modern applications, which tend to be cloud-based microservices architectures, obtaining the IP and port of the service instance is a challenge to solve. As shown below:

In the figure above, the IP address of the service instance instance is dynamically assigned. At the same time, it also faces the change of service increase or decrease, failure and upgrade. This requires a more precise service discovery mechanism for the client program.

At present, there are two service discovery modes: client discovery mode and server discovery mode. Take a look at the client-side discovery pattern.

Client discovery mode

With the client discovery pattern, the client is responsible for determining the availability of service instances and load balancing requests. Service instances are stored in the registry, which is a database of service instances. The client queries the service registry, obtains a list of service instances, selects one of them using a load balancing algorithm, and initiates a request.

The following is an architecture diagram of this pattern:

In this mode, when a service instance starts, its address is registered in the service registry and removed from the service registry when the service instance stops. During this time, the heartbeat mechanism is typically used to determine the registration of the refresh service instance.

Netflix Eureka is a service registry component that provides reST-APi-based service instance registration and query capabilities. Netflix Ribbon is an IPC client that works with Eureka to load balance requests to service instances.

The advantage of the client-side discovery pattern is that it is relatively simple and requires no changes to other parts except the service registry. Also, because clients know all available instances, they can make more informed, application-specific load balancing decisions, such as using consistent hashing algorithms. The downside of this pattern is that the client and service registry functions are coupled together, and the service discovery logic must be implemented for the client side of each programming language and framework.

Server discovery mode

Another service discovery pattern is the server discovery pattern. The structure of this pattern is shown below:

The client sends requests to the service through the load balancer, which queries the service registry and routes the requests to available service instances. In contrast to client discovery, service instances are registered and unregistered through the service registry.

AWS ELB (Elastic Load Balancer) is an example of server side router discovery. Elbs are commonly used to load balance traffic from the external network, but you can also use ELBs to load balance traffic inside a private cloud (VPV). Clients use DNS names and send requests (Http or TCP) through elBS that load balance between registered elastic computing cloud (EC2) instances or containers of EC2 Container Services (ECS). This implementation does not have a separate service registry, but registers EC2 instances and ECS containers with the ELB itself.

Http servers and load balancers (such as Nginx Plus and Nginx) can also be used as server-side discovery load balancers. For example, dynamically configure an Nginx reverse proxy using the Consul template. Consul can periodically regenerate any configuration file from configuration data stored in the Consul service registry. Whenever a file changes, you can run an arbitrary shell command. For example, the Consul template generates an nginx.conf file that configures the reverse proxy and then executes a command telling Nginx to reload the configuration.

Some deployment environments, such as Kubernetes and Marathon, run an agent on each host in the cluster. This agent acts as a server-side discovery load balancer. When a client makes a request to a service, the request is transparently routed through a proxy to a service instance in the cluster.

The biggest advantage of the server-side discovery pattern is that the implementation details of service discovery are taken away from the client, which simply sends requests to the load balancer. This eliminates the need to implement service discovery logic for clients of every programming language and framework. Furthermore, some deployment environments already provide this functionality for free. Of course, there are some downsides to this model. If the deployment environment does not provide a load balancer, you will need to build and manage an additional high availability system component.

Service registry

The key to service discovery is the service registry, which is a database containing the address information of service instances. The service registry needs to be highly available and up to date. The client can cache the service instance address information obtained from the registry. But this information is out of date, so the service registry also needs to be in cluster mode, and consistency between clusters needs to be maintained by protocol.

Netflix Eureka is a service registry component that provides service instance registration and query functionality in the form of a REST API. A service instance can register itself in the registry with a POST request; It can refresh its registration information every 30 seconds with a PUT request; Instance registration information can be deleted through Http DELETE requests or timeout mechanisms; You can use Http GET requests to retrieve registered service instances.

Common service registry components include ETCD, Consul, Apache Zookeeper, and Nacos.

Option for service registration

Service instances must be registered or unregistered through a registry, and there are usually several different ways to handle registration and unregistration. One is self-registration of service instances, that is, self-registration; The other is to manage the registration of service instances based on other system components, the third-party registration model. Let’s take a look at self-registration.

Self-registration model

When using self-registration mode, the service instance is responsible for registering and unregistering itself in the service registry. If necessary, the service instance also needs to send a heartbeat request to avoid being logged out due to timeout. The following diagram shows the structure of this pattern:

An example of this pattern is the Netflix OSS Eureka client, which handles all registration and deregistration of service instances. In the Spring Cloud project, various patterns including service discovery are implemented, based on which it is easy to automatically register service instances to Eureka. You simply use the @enableeurekaclient annotation on the Java configuration class.

The advantage of self-registration mode is that it is very simple to use and does not require any other system components. The downside is that service instances are tightly coupled to service registries, requiring registration functionality in every programming language and framework.

Another way to decouple services from registries is through the third-party registry pattern.

Third-party Registration Mode

When using the third-party registry mode, the service instance is no longer responsible for registering itself in the service registry. This function is handled by a third-party component acting as a service registrar. Service registrars keep track of instance changes by polling or subscribing to events. When a new available service instance is found, the service instance is registered in the service registry. At the same time, the stopped service instances are deregistered. The following diagram shows the structure of this pattern:

An example is the open source project Registrator, which automatically registers and unregisters service instances based on the Docker container. Registrator supports a variety of registries including ETCD and Consul.

Another example is the NetflixOSS Prana project, which is a Sidecar application that runs parallel to the service instance, primarily for services written in non-JVM languages. Prana registers and unregisters service instances based on Netflix Eureka.

The advantage of the third-party registry pattern is that services are separated from service registries and service instance registrations are handled centrally within dedicated services without the need for clients of each programming language and framework to implement service registration logic. The downside of this pattern is that, unless the deployment environment provides built-in services, there is an additional need to build and manage a highly available system component.

conclusion

In microservice applications, the service instance running state changes dynamically, and the instance is dynamically assigned addresses. Therefore, in order for clients to request services properly, service discovery mechanisms must be used. This paper is about the two modes of service discovery (client discovery and server discovery), service registry and its two ways (self-registration mode and third-party registration mode), reverse proxy server and other knowledge points to explain. Only by popularizing the above basic knowledge, can we better learn and understand the service discovery function in microservices.

Nacos series

Why is the String. Intern method used in Nacos source code? Nacos, the Soul Ferryman of Microservices, here is a complete overview of the principle.

About the blogger: Author of the technology book SpringBoot Inside Technology, loves to delve into technology and writes technical articles.

Public account: “program new vision”, the blogger’s public account, welcome to follow ~

Technical exchange: Please contact the weibo user at Zhuan2quan