Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”.

This article has participated in the “Digitalstar Project” and won a creative gift package to challenge the creative incentive money.


As one of the core modules of Spring Cloud, Eureka plays an important role in service registration discovery. If you comb through the actual workflow of Eureka, it can be roughly divided into the following parts:

  • The service registry
  • The service contract
  • Service to eliminate
  • Service offline
  • Service discovery
  • Synchronizing Cluster Information

The above aspects may be analyzed from the server (registry) and client (including service provider and service caller) of Eureka. For simplicity, the Eureka server is called Eureka-Server and the client is called Eureka-client. This article starts with basic service registration.

The service registry

Eureka-client

In Eureka-Client, DiscoveryClient is a class that works with Eureka-Server. If you look at its annotations, it can register services, renew services, take services offline, and get a list of services. First, take a look at the register method used to initiate a registration request to eureka-server:

Call register AbstractJerseyEurekaHttpClient class methods:

Jersey is a framework for Restful request services, similar to the usual SpringMVC, and will be used later when eureka-Server intercepts requests.

Call the underlying class here:

com.sun.jersey.api.client.Client
Copy the code

Send an HTTP request through an HTTP client and build the response result.

Eureka-server

In Eureka-server, after configuring the necessary parameters in the YML file, only a single comment is required to open:

@EnableEurekaServer
Copy the code

The annotation implementation is blank and uses @import:

@Import(EurekaServerMarkerConfiguration.class)
Copy the code

The realization of the view EurekaServerMarkerConfiguration class:

It makes no sense to just inject beans into the Spring container here. Here we use Springboot autoassembly (see Springboot zero configuration for this unfamiliar startup) :

Found Eureka EurekaServerAutoConfiguration core automatic configuration of the server class

We see conditionally injected annotations on this class:

@ConditionalOnBean(EurekaServerMarkerConfiguration.Marker.class)
Copy the code

This class is instantiated only if there is a Marker Bean in the Spring container, so @enableeurekaserver acts as a switch for identification.

Interceptors are defined in this configuration class, also using Jersy to intercept requests:

The addInstance method of the ApplicationResource class receives the request and, after verifying the instance information, adds the instance to the service registry:

Enter the InstanceRegistry register method:

Two functions are done here:

1. Call handleRegistration and publish the listener event using publishEvent in the method. Spring supports event-driven, listener mode for listening for events, which are broadcast to all listeners and receive a request for service registration.

As for listeners, we can implement them by hand. Spring will inject the event types in the parameters directly for us:

@Component
public class EurekaRegisterListener {
  @EventListener
  public void registe(EurekaInstanceRegisteredEvent event){ System.out.println(event.getInstanceInfo().getAppName()); }}Copy the code

2, call the superclass PeerAwareInstanceRegistryImpl register method:

The following operations are performed:

① Get the expiration time of the micro service and update it

② Leave service registration to the parent class

③ Complete cluster information synchronization (this will be explained later)

Call the register method of the AbstractInstanceRegistry parent, where the service registration actually begins. Let’s start with the structure of eureka-Server’s service registry list defined in this class:

ConcurrentHashMap<String, Map<String, Lease<InstanceInfo>>> registry;
Copy the code

The outer String in ConcurrentHashMap indicates the service name.

The String in the Map represents the ID of the service node (that is, the instanceID of the instance);

Lease is a heartbeat renewal object. InstanceInfo is the instance information.

First, the registry takes a Map based on the name of the microservice or creates a new one if it does not exist, using putIfAbsent.

Then, a service instance is obtained from gMap (which is the list of instances of the service) to determine whether the node of the microservice exists, which generally does not exist in the case of the first registration

Of course, there may be registration information conflicts, in which case Eureka will determine which one to cover according to the last active time:

In this code, Eureka takes the last active time of the existing node and compares it with the time of initiating registration of the current registered node. When the last active time of the existing node is longer than the time of the current registered node, it indicates that the existing node is more active, and the current node is replaced.

The idea here is that if the old nodes in Eureka’s cache are more active, it is usable, while the new service I don’t know will be usable, so Eureka conservatively uses the old nodes that are available, and thus guarantees availability

Encapsulate a service instance once it is in hand:

Lease is a package that stores the registration information, the last operation time, the registration time, the expiration time, and the deletion time. Here you put the registered instance and expiration time into the heartbeat renewal object, and the heartbeat renewal object into the GMAP registry. Then change the service state, system data statistics, so far a service registration process is completed.

Eureka-client = eureka-client = Eureka-client = Eureka-client = Eureka-client

The service contract

Eureka-client

Service renewal is initiated by Eureka-client and completed by the renew method in DiscoveryClient class introduced earlier. The main content is still sending HTTP request:

Every 30 seconds to make a contract, call AbstractJerseyEurekaHttpClient sendHeartBeat method:

Eureka-server

On the Eureka-server side, the call chain for service renewal is basically the same as for service registration:

InstanceRegistry # renew() ->
PeerAwareInstanceRegistry # renew()->
AbstractInstanceRegistry # renew()v
Copy the code

AbstractInstanceRegistry renew method

The gMap instance list of the service is obtained from the registry, and then the specific instance to be renewed is obtained from the gMap by instance ID. Then check whether the service instance is down and in the same state as before based on InstanceStatus. If all is well, the renew method in Lease is finally called:

It can be seen that the operation of service renewal is very simple, its essence is to modify the last update time of the service. Change the last update time to the current system time plus the expiration time of the service. It is worth mentioning that the variable lastUpdateTimestamp is decorated with the volatile keyword.

In a previous article we said that volitaile is used to ensure visibility. So, visible to who, just to be clear, this is visible to the scheduled tasks that are being culled from the service, and we’ll look at that later.

conclusion

This article, the first in the Eureka source code analysis, briefly explains how services are registered and renewed. In the next article, we will follow the process and take a look at service removal and service downsizing.