Please forgive me for using the icon of Lianjia, xiaobian is not really advertising to real estate agents.
What is service discovery?
There’s nothing mysterious about service discovery, it’s pretty simple. It is just that too many articles in the market demonize the difficulty of service discovery, which makes readers feel low in IQ and dare not climb.
What the service provider is, in a nutshell, is an HTTP server that provides API services and has an IP port as the service address. What a service consumer is, it’s a simple process that wants to access a service provided by a service provider to do something. An HTTP server can be either a service provider providing services externally or a consumer requiring services provided by other service providers. This is called service dependency. I am not myself without you. Complex services even have multiple service dependencies.
Service discovery has three roles, service provider, service consumer, and service mediator. Service mediations are a bridge between service providers and service consumers. The service provider registers the address of the service it provides with the service intermediary, and the service consumer looks up the address of the desired service from the service intermediary and enjoys the service. Service mediations provide multiple services, each corresponding to multiple service providers.
A service mediation is a dictionary containing key/value pairs. Key is the name of the service and value is the address list of the service provider. Service registration calls the dictionary’s Put method to stuff things, and service lookup calls the dictionary’s Get method to Get things.
When the service provider node is down, the service is required to cancel the registration in time, and then the consumer is notified to get the service address again in time.
When a new service provider joins, the service intermediary is required to inform the service consumer whether you want to try the new service.
Redis acts as a service intermediary
Redis has rich data structures that are perfect for storing service dictionaries. For each service name, we use a set structure to store the IP:Port string for the service. If the service provider joins, run the sadd command to add the service address. If the service fails, run the srem command to remove the service address. Use the smembers directive to get all service addresses for service consumers and then randomly select one in the consumption process, or use the srandmemember directive to get random service addresses directly.
At this point you might wonder, is service discovery really that simple? The answer is almost. There are a few problems with the above solution.
The first question is what if the service provider process is killed by kill -9 and cannot actively invoke the SREM command?
In this case, an extra black address in the service list points to a non-existent service and the consumer is completely unaware of this, so the service intermediary becomes a black intermediary. So what to do?
We introduced service survival and inspection mechanisms and replaced data structures. The service provider needs to report the survival every five seconds or so to the service mediation, which records the service address and reporting time in the Value and score of the ZSet data structure. The service mediation needs to check the ZSET data structure every 10 seconds or so to kick off service address entries that are seriously behind in reporting time. In this way, the validity of the service address in the service list can be guaranteed in quasi-real time.
The second problem is how to notify consumers when the list of services changes. There are two solutions.
The first is polling, where consumers need to check the list of services every few seconds to see if they have changed. If you have a lot of services, a lot of service lists, a lot of customers, redis will feel some pressure. In this case, the version number mechanism of the service list can be introduced. Each service is provided with a key/value to set the version number of the service. That is, the version number increases when the service list changes. Consumers simply need to poll for a change in the version number to see if the list of services has changed. Because the list of services is stable and changes frequently only in the event of severe network jitter, Redis has little pressure.
The second is to use pubsub. This method is significantly better than polling in timeliness. The downside is that each Pubsub occupies the consumer one thread and one additional Redis connection. To reduce waste on threads and connections, we broadcast global version number changes using a single PubSub. The global version number is incremented when any list of services changes. Consumers who receive a version change then check to see if the version number of their respective list of dependent services has changed. This global version number can also be used for the first polling scheme.
The third problem is that Redis is a single point, what if it dies?
That’s a big problem. Because of this problem, popular service discovery systems use distributed databases such as ZooKeeper /etcd/ Consul to mediate services. They are distributed multi-node, and the system can still function if a node fails.
Is Redis really unreliable as a service intermediary? In fact, there is a redis-Sentinel to eliminate the single point problem of Redis. Redis-sentinel can automatically upgrade the secondary node to the primary node when the primary node fails. So it’s okay to do it with Redis. It’s really easy to do service discovery with Redis, although it’s very unfashionable.
Service providers are not just HTTP services
The service provider mentioned above is simply an HTTP server, but there are many different services. It could be a database service, it could be an RPC service, it could be a UDP service, and so on.
If it’s a MySQL database, how do YOU register your MySQL service with a service mediation? Native MySQL does not provide this functionality. The common practice is to provide an Agent Agent to deregister. In addition to registering the service address with the service mediation, the agent also needs to monitor the health of MySQL so that it can switch to a new MySQL service address in the event of a MySQL outage. In order to save resources, this Agent can monitor multiple databases at the same time, or even multiple databases.
Service configuration is reloaded
Service discovery is usually a simple function to register and find a list of services. However, modern service discovery systems also integrate service configuration management capabilities. This enables real-time reloading of the service configuration. The principle is simple: for each service item, the service mediation also stores a separate key/value to store the configuration information of the service. When this configuration item is modified in the background, the service mediation notifies the relevant server of the change in real time. For example, the database address changes and service parameters change.
Service Management Background
To facilitate service management, common service discovery provides a service management background for managers to check the status of service clusters. If redundant configuration information is provided during service registration and reporting, the service management background can present more detailed service information. The service management background can also organize all the service dependencies, presenting a beautiful service dependency tree.
A simple implementation of service discovery
Xiaobian in his spare time based on Redis to achieve a simple service discovery system Captain. You can download the project on Github to learn more about it. In addition to writing the server for service discovery, I also developed the client SDK together, which may be unstable. I hope readers can understand and do not use it for online business system.
In the project Captain, my service discovery server encapsulated the services provided by Redis and provided HTTP API externally for service registration and search, without using the pubsub function mentioned above.
Read related articles, pay attention to the public account [code hole]