“This is the fifth day of my participation in the November Gwen Challenge. See details of the event: The Last Gwen Challenge 2021”.

Hello everyone, I am Wukong.

This article takes you through the process of receiving registration on the Eureka server from a source code perspective. In addition, I also found some worthy of learning from the source code, such as Eureka to store the data structure of the registry, the use of read and write locks to control more fine-grained concurrency, improve the efficiency of the program.

Next, it will be explained from the following aspects:

  • The client sends a registration request.
  • The Eureka registry receives registration requests.
  • The server saves the client registration information to a Map.

About the source code directly to the official website to download it. Github.com/Netflix/eur…

This article has been included on github: github.com/Jackson0714…

I. Registration entrance

Last time we saw that the Eureka Client is registered by sending an HTTP request, so there must be a place to receive the HTTP request, which is the registration entry. How does this work?

In fact, the Jersey framework is used, and we don’t need to dig into the framework, we just need to know where the framework is referenced and what it does.

An analogy to the MVC framework is Jersey, which has servlets dedicated to handling HTTP requests. References to the Jersey frame:

\eureka\eureka-server\src\main\webapp\WEB-INF\web.xml
Copy the code

And then where is the controller that handles the HTTP request?

In fact, the Resources directory of the Eureka-Core project defines a number of resource-ending classes that are used to handle HTTP requests.

\eureka\eureka-core\src\main\java\com\netflix\eureka\resources
Copy the code

The Jersey Resource class is used to handle HTTP requests.

A jersey resource that handles request
Copy the code

ApplicationsResource

Finally, we found the addInstance method of the ApplicationResource class that we were looking for to handle the registration request.

2. Receive registration requests

The overall process is as follows:

2.1 Method of receiving registration request

The core code inside the addInstance method is

registry.register(info, true);
Copy the code

The registry is PeerAwareInstanceRegistryImpl instance objects. It implements the PeerAwareInstanceRegistry interface.

Calling its register() method calls the register() method of the abstract class AbstractInstanceRegistry, where the core code resides. Another thing to note is that the above abstract classes and interfaces implement and inherit the InstanceRegistry interface, respectively.

The interface and class diagram is as follows:

So where does the registration information go?

The place where registration information is stored

The source code defines a gNewMap, ConcurrentHashMap, and assigns it to the gMap variable

ConcurrentHashMap<String, Lease<InstanceInfo>> gNewMap 
Copy the code

So the gMap variable is actually used to store the registration information. Let’s analyze the structure of gMap.

GMap is a ConcurrentHashMap structure, so it is a key-value pair.

  • keyIt’s a unique ID, String. Values like this:i-00000004
  • valueLease is stored in it.
  • LeaseIs a class that holds an instanceInfo holder. This instanceInfo is the registered service instance information, including IP address, port number, and so on.

Putting the service instance information into gMap is also easy by calling the PUT method.

gMap.put(registrant.getId(), lease);
Copy the code

Here is the status of the two service instances I registered:

Four, the place worth learning

4.1 ConcurrentHashMap?

ConcurrentHashMap, why not use hashMap?

ConcurrentHashMap<String, Lease<InstanceInfo>>()
Copy the code

The reason:

  1. Using HashMap in concurrent programming can cause an infinite loop (JDK 1.7 and 1.8 can cause data loss)
  2. HashTable is very inefficient.

What is the underlying principle of ConcurrentHashMap?

ConcurrentHashMap internally subdivides several small Hashmaps, called segments. By default, a ConcurrentHashMap is further subdivided into 16 segments, which are the concurrency of the lock. If you need to add a new entry to a ConcurrentHashMap, instead of locking the entire HashMap, you first get the segment in which the entry should be stored based on hashCode, then lock that segment, and then put. In a multithreaded environment, if multiple threads perform a PUT operation at the same time, true parallelism can be achieved between threads as long as the entries to be added are not in the same segment.

4.2 readWriteLock?

We see a useful read lock in the source code, ReentrantReadWriteLock, as shown below

readWriteLock = new ReentrantReadWriteLock(); Lock read = readWriteLock.readLock(); read.lock(); . read.unlock();Copy the code

4.2.1 Why are locks divided into read locks and write locks?

The reason:

Prior to the read/write lock, assuming a normal ReentrantLock, thread-safe is guaranteed, but some resources are wasted, because there is no thread-safe problem if multiple reads are running at the same time. You can allow multiple reads to run in parallel to improve program efficiency.

However, writes are not thread-safe, and can cause thread-safe problems if multiple threads write at the same time or read at the same time.

Read/write locks solve this problem by setting up a set of rules that ensure efficient simultaneous reads by multiple threads while ensuring thread-safe writes.

Read lock: Allows multiple threads to acquire read locks and access the same resource at the same time.

Read lock

Write lock: Only one thread is allowed to acquire the write lock.

Write lock

Overall idea:

Is it has two locks, the first lock is write lock, after obtaining write lock, can read data and can modify data, and the second lock is read lock, after obtaining read lock, can only view data, can not modify data. Read locks can be held by multiple threads, so multiple threads can view data at the same time.

Reasonable use of read lock in read place and flexible use of write lock in write place can improve the execution efficiency of the program.

4.2.2 Rules for obtaining read and write locks

Follow the following acquisition rules when using read/write locks:

  • If one thread has occupied the read lock, the other thread can apply for the read lock successfully.
  • If a thread has occupied the read lock, if another thread wants to apply for the write lock, the thread that applied for the write lock will wait for the release of the read lock, because the read and write operations cannot be performed simultaneously.
  • If one thread has occupied the write lock, the other thread must wait for the previous thread to release the write lock, also because the read and write cannot be simultaneous, and the two threads should not write at the same time.

Read/write lock mutex summary:

  • Read Share.
  • Write mutually exclusive, read/write mutually exclusive, write/read mutually exclusive.

Five, the summary

This paper analyzes the process of Eureka server receiving registration information from the perspective of source code. The core logic is to put the registration information of the service instance into ConcurrentHashMap, and use read locks to control fine-grained concurrent registration. We also introduced the Jersey framework, which is less familiar, for handling HTTP requests, such as client registrations.

ConcurrentHashMap<String, Lease>(); ConcurrentHashMap<String, Lease>() Then review again the principle of ConcurrentHashMap, reentrant read and write lock principle, learning is constantly memory, constantly forget the process, learning source code just can review a wave ~

The resources

www.passjava.cn

www.cnblogs.com/zz-ksw/p/12…