The introduction

This is the official architecture diagram of Nacos, and you can find two main modules: ConfigService (configuration center), NamingService (registry), as well as the well-known problem of what is the configuration center and registry, this article is to look at the nacOS registration process from a source point of view and feel some of the ideas it uses that we can learn from.

Server source code environment construction

  1. Pull source: github.com/alibaba/nac…
  2. Local startup server single-machine deployment mode Set the following parameters:-Dnacos.standalone=true

Client source code analysis

Nacos clients need to import dependencies:

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
Copy the code

Note: In Nacos you need to import a Web initiator if you want the client to actively register the server

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
Copy the code

Let’s start with the source code analysis: first we findnacos-discoveryDepending on the package’s startup entry, the springBoot project’s launcher is usually automatically configured to start, so let’s go with itspring.factoriesFile finding auto-configuration class:com.alibaba.cloud.nacos.registry.NacosServiceRegistryAutoConfiguration Click on it to see that a very important Bean has been created:

@Bean
@ConditionalOnBean(AutoServiceRegistrationProperties.class)
public NacosAutoServiceRegistration nacosAutoServiceRegistration( NacosServiceRegistry registry, AutoServiceRegistrationProperties autoServiceRegistrationProperties, NacosRegistration registration) {
   return new NacosAutoServiceRegistration(registry,
         autoServiceRegistrationProperties, registration);
}
Copy the code

To see what this class does, take a look at its class diagram:inheritedApplicationListenerWhich means he can post events, so let’s find outonApplicationEventTo see what you’re doing, skip the doll’s bind() method and go straight to the core: start():The codes 1 and 3 in figure 1 publish events before and after registration, which is also an extension point of the NacOS client. We can listen for these events to do our own business processing. The main logic for registration is still in step 2, which is to click in and find that it is called in the register() methodnamingService.registerInstance(): Take a look at the registration logic. Click here to find the code that calls the server interface:At this point, client registration ends. It’s not hard to see a problem here: in Nacos, you don’t need to use@EnableDiscoveryClientYou can register the service.

Server source code analysis

Let’s switch to the Nacos server to see how to handle the service registration request. The request interface is/Nacos /v1/ns/instance. In this interface calls the serviceManager. RegisterInstance (namespaceId serviceName, instance);

ServiceManager#registerInstance

Let’s see what this method doesThe main steps to do things are 1, 2. Click on the first step to see the next step, click on the innermost callcreateServiceIfAbsentMethods:

ServiceManager#createServiceIfAbsent

The core isgetService()andputServiceAndInit()methods

  • getService(); The serviceMap does not have any data yet, so null is returned. Create a Serivce object under getSerivce(). Let’s look at the structure of the Service object.
    /** * The scheduled task used to detect heartbeat */
    @JsonIgnore
    private ClientBeatCheckTask clientBeatCheckTask = new ClientBeatCheckTask(this);

    private String namespaceId;

    /** * If you do not send beat for a period of time, the IP will be deleted. The default timeout period is 30 seconds. * /
    private long ipDeleteTimeout = 30 * 1000;

    private Map<String, Cluster> clusterMap = new HashMap<>();
Copy the code

In addition to scheduled tasks for heartbeat detection, there is an important clusterMap, which is empty. So far, we’ve found a lot of confusion:

  1. What does SerivceMap do?
  2. What does this Service object do?

So let’s put a little bit of a marker here and keep going with this problem.

  • PutServiceAndInit () :

The code goes back toputServiceAndInit()Method here, click in, the core code is these two lines:putService()The method name should give you some clues as to where to put the Service. Click inside to see:The Serivce object is in the ServiceMap, so we will call it next timegetSerivice(namespaceId)“, you can get a Serivice object. Look at thesevice.init()Methods:Started a scheduled task to handle heartbeat detection. Take a lookclientBeatCkeckTaskThe run method of the object:In this method, each temporary instance of the current service is losed to determine whether the current time minus the last heartbeat time is greater than the heartbeat timeout time. If the time is greater than the heartbeat timeout time, the execution will be performedinstance.setHealthy(false)Change the health state of the instance to false; However, the scheduled task is not executed immediately. It is executed every 5 seconds:

Now that the main line of ServiceManager#createEmptyService has been analyzed, let’s briefly summarize what it does:

  1. Create a Serivice object containing a clusterMap.
  2. Add the service object to SeriviceMap. The structure is Map

    >.
    ,>
  3. Enable a scheduled task to check whether the heartbeat of the instance times out. The task is executed every five seconds.

ServiceManager#addInstance

The internal structure of the Serivce object has not really been initialized after analyzing the source code above. The rest of the logic is in the addInstance method. Just to give you a hint, take a look at the comment I added to this method so you can understand it later:Click here to see how this method works:

addIpAddresses()

Take a look at what’s done in the addIpAddresses() method, all the way to the innermost updateIpAddresses() method:This code creates a Cluster object and places the cluster object in the clusterMap of the Service. So let’s look at what the Cluster object looks like:

@JsonIgnore
private Set<Instance> persistentInstances = new HashSet<>();

@JsonIgnore
private Set<Instance> ephemeralInstances = new HashSet<>();
Copy the code

PersistentInstances are registered instances, and ephemeralInstances are ephemeralInstances. These two sets are still empty.

consistencyService.put(key, instances)

Now that the Service is initialized, we need to add the registered instance to the Cluster.

  • onPut(key, value):Here you wrap instance as a Datum into the dataStore and generate a Key. The dataStore acts as a staging point. The lasttask.offerWrap the key and the action as a tuple and throw it into a queue and return it. I want to store instance in Cluster. I want to store instance in Cluster. So let’s find out where it was done. Take a lookNotifierThe structure of the:If the Runnable interface is implemented, there must be a Runnable implementation. Check the run method to see if you can find anything (note: from now on the following code is executed asynchronously, and the main thread has ended) :The handler method is called to process the tuple from the queue.The listener.onChange method implementation class is Service, Will always point in call updateIPs (value. GetInstanceList (), KeyBuilder. MatchEphemeralInstanceListKey (key)) method, basically see this line of code:This method will have a copy of registered list of instance, the new instance and old instances are updated to a collection, eventually will update this collection to the real instance list again, when you write is a copy of thoughts, mainly in order to solve the concurrent conflict, in the process of writing, read other threads or old data, Then update the data back after you’ve actually written it.

After analyzing this, let’s look at what the registry structure looks like:

Sorrow can rejuvenate the country, leisure can die.