1. web.xml

<! - at the time of the web project startup will perform, in had in the core - > < listener > < listener - class > com.net flix. Eureka. EurekaBootStrap < / listener - class > </listener>Copy the code

Web.xml has several fileters and listeners configured

  • Com.net flix. Eureka. EurekaBootStrap: responsible for the initialization of eureka – server.
  • Filter: Any request is passed through filter
  • Com.net flix. Eureka. StatusFilter: be responsible for the processing logic state
  • Com.net flix. Eureka. ServerRequestAuthFilter: request for authorization
  • Com.net flix. Eureka. RateLimitingFilter: current limiting relevant logic (focus on how to realize the current limit), the default is not open, need to make their own parameter Settings
<! -- Uncomment this to enable rate limiter filter. <filter-mapping> <filter-name>rateLimitingFilter</filter-name> <url-pattern>/v2/apps</url-pattern> <url-pattern>/v2/apps/*</url-pattern> </filter-mapping> -->Copy the code
  • Com.net flix. Eureka. GzipEncodingEnforcingFilter: dealing with the compression and coding, only to certain requests to take effect
<filter-mapping>
    <filter-name>gzipEncodingEnforcingFilter</filter-name>
    <url-pattern>/v2/apps</url-pattern>
    <url-pattern>/v2/apps/*</url-pattern>
  </filter-mapping>
Copy the code
  • Jersey is a global, Restful framework that works for all applications
<filter-mapping>
    <filter-name>jersey</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
Copy the code
  • The home page for the welcome-list launch is the one we see in the Eureka Server registry
 <welcome-file-list>
    <welcome-file>jsp/status.jsp</welcome-file>
  </welcome-file-list>
Copy the code

2. Eureka Server startup

As can be seen from web. XML, the contextInitialized of the EurekaBootStrap class is the startup entry

public void contextInitialized(ServletContextEvent event) { try { initEurekaEnvironment(); initEurekaServerContext(); ServletContext sc = event.getServletContext(); sc.setAttribute(EurekaServerContext.class.getName(), serverContext); } catch (Throwable e) { logger.error("Cannot bootstrap eureka server :", e); throw new RuntimeException("Cannot bootstrap eureka server :", e); }}Copy the code

2.1 initEurekaServerContext() Basic flow parsing

  • Will first build a DefaultEurekaServerConfig this class to implement internal init () method, loading configuration files
  • Get the environment configuration from the environment information set up in the previous step and set it to the ConfigurationManager class
  • Find the file name of the configuration class eureka-server written in the configuration
  • ConfigurationManager to load the configuration file, you will get the configuration file name eureka-server. Properties, and call the API to encapsulate its internal configuration properties (this file is empty by default, but will be filled with default values when we fetch values). The contents of the returned parameter Properties object are put into the ConfigurationManagaer object for unified management
  • The EurekaServerConfig interface provides many methods to obtain configuration parameters. Basically, the parameters set in eureka-server.properties can be obtained through this interface. Here by DefaultEurekaServerConfig class – this class implements this interface
  • The DynamicPropertyFactory class is used to retrieve the configuration information in eureka-server.properties encapsulated in ConfigurationManager. We use this class because ConfigManagerConfig assigns the configuration information to DynaminPropertyFactory after it has retrieved the configuration information through a series of getXXXProperty() methods. This is in the form of hard coding, instead of using constant to obtain the corresponding value of the key, and for each key value, if it is empty, the default value is set, which can also be understood as object oriented to obtain configuration parameters
  • Using the interface to obtain parameter values so that more object-oriented some, can learn and adopt.

2.2 Use Eureka Server as a Eureka client in constructor mode

  • A Eureka server can register with other Eureka servers to form a cluster. In essence, the Eureka server acts as a Eureka client. All parameter information is managed by the ApplicationInfoManager object
  • The eureka-client.properties configuration file is read according to whether the cloud environment is used. The way of initializing the service context is basically the same. It is also interface – oriented to obtain all parameter values in hard-coded form
  • The InstanceConfig object is then constructed using the constructor mode (InstanceInfo has an internal Builder class) based on the configuration read from the configuration file, encapsulating some of the parameter information needed for Eureka Server as an instance object
  • Finally, the InstanceInfo object is handed over to ApplicationConfigManager for unified management

2.3 Initializing eureka Client

  • Use DiscoveryClient to initialize eurekaClient

  • The information previously read from eureka-client.properties is first assigned to some internal variables

  • Then, different parameters are initialized according to whether the registry is needed or not. If not, some properties are set to NULL for resource release

  • Build a thread pool for periodic scheduling

  • Build a thread pool to fetch the registry

  • Build the thread pool for heartbeat renewal

    • Each of these pools has a maximum of five threads
  • EurekaTransport is built to initialize the httpClient object for fetching and registering

  • Then according to the configuration, to perform the registry crawl, if set not to crawl, will not crawl, if set to crawl, but crawl failure, there will be a read backup operation

  • Then the scheduling task will be initialized. According to our configuration, the task of fetching the registry will be initialized if the registry is configured, the task of fetching the registry will be initialized if the registration to eureka service is configured and the heartbeat renewal is sent, the heartbeat task will be initialized, the copy of the instance will be set, and the status monitoring of the instance will be set. If we are configured to listen for state, we register the listener

  • Later, the scheduling task will be started based on the instance copy, mainly for operation synchronization between clusters, such as service online, offline, renewal and so on.

2.4 Service Context

  • First of all is to be able to build a registry can sense the cluster: PeerAwareInstanceRegistry class,
  • The PeerEurekaNodes class is then built to get cluster information within the cluster
  • And then builds a EurekaServerContext service context object, and the object to the EurekaServerContextHolder, convenient somewhere else get to eureka server context object at any time, It mainly updates the cluster status and obtains the registry based on the cluster information
  • SyncUp obtains the registry information from any node and adds it to the local node. If the registry information is not pulled, a maximum of five retries are performed by default and the retry interval is 30 seconds
  • Deal with the aftermath, add some monitoring information, etc

3. Main flow diagram of Eureka Server

4. The Eureka Client is started

4.1 Basic Flow Chart

4.2 Eureka Client Registration Process

  • In fact, his registration process is to build EurekaClient, where an InstanceInfoReplicator is responsible for instance copy information. Just after step 6 in the figure above, the initialization of the network communication component is also used by the Eureka client for registration.
  • Through clientConfig * * getInitialInstanceInfoReplicationIntervalSeconds () * * to get to the default values, 40 s
  • By calling InstanceInfoReplicator’s start method, you throw yourself as a thread into a pool of scheduled threads. By default, the thread is executed after 40s. Since it is a thread, the main implementation logic is in the run method
  • Register is invoked through discoveryClient, a subclass of eureka Client instance
  • Here is also used in the above Seventh step to initialize the HTTP module, because had the jersey as a restful frame, so the core, or call AbstractJersey2EurekaHttpClient registered this class, The main thing is to set the path and some properties, in JSON format, post request method, data information to eureka server.

* * * *

4.2.1 Simple diagram of registration process

4.3 Eureka Server Receives eureka Client registration

  • For the Jersey framework, the Resource package acts as our Spring MVC controller, and we do unit tests and debug the flow
  • The addInstance method in the ApplicationResource class is called to receive the registration
  • After entering the method is a string of verification and parameters, a good code, that is, defensive programming, can resist others random transfer of parameters, but the source code in this way is not recommended, you can consider a separate extraction method for implementation.
  • The next step is to get the data center and perform different operations depending on the data center, in the form of hard coding, we can consider setting parameters through configuration files, marking whether it is an AWS cloud environment, and building different objects using factory or policy patterns.
  • Call PeerAwareInstanceRegistry this can feel instance information method of registry of a class to register, call this method will actually call the superclass AbstractInstanceRegistry registration method.
  • In the form of read/write locks, read locks are added during registration to allow simultaneous registration of multiple services. The data structure of the service registry is ConcurrentHashMap>>.
  • Each time a new service is registered, lease information is set for the instance, various property values and states are set, and the registered service is added to a recentRegisteredQueue.
  • For recently updated service instances, a recentlyChangedQueue queue is added and the lock is released.
  • Finally, 204 is returned, and the magic number appears.

4.4 Display of eureka console data

When we complete the registration, we can see the corresponding information in our Eureka console page

  • The service context object is first retrieved from the Hoder object when Eureka Server is started
  • Get information from the query object to the Registry
  • Iterate through the registry and encapsulate it into an Application object, one of which represents a service instance and is presented to the JSP page

4.5 Complete Eureka registration flowchart

5. Crawl the registry

When the Eureka client starts for the first time, it captures the full amount of registry information from the Eureka server and caches it locally. After that, it captures incremental registry information from the Eureka server every 30 seconds and merges it with the local cache

5.1 Eureka Client Sends a capture request

  • Call the fetchRegistry method to determine some parameters to see if a full registry fetching is required

  • To fully fetch the registry, the getAndStoreFullRegistry method is called

    • Call the Apps interface through Jersey to get the full instance information
    • Encapsulate the captured instance information in the local cache Atom Rence

5.2 Eureka Server Responds to capture Requests

  • Eureka Server implements a set of multi-level caching mechanisms:

  • First, get the registry information according to the getValue method in the ResponseCache class

    • If a read-only cache is allowed, readOnlyCacheMap is fetched directly from the read-only cache. If not, readWriteCacheMap is fetched from the read/write cache.
    • If the read/write cache also have no, may be obtained through PeerAwareInstanceRegistry all of the registry
    • If the read-only cache is not allowed, it is directly fetched from the read/write cache. If not, it is directly fetched from the full registry
5.2.1 Response Flow chart

5.3 Cache Expiration

  1. Take the initiative to expire

When a new service instance is registered, offline, or faulty, the readWriteCacheMap is refreshed and the corresponding key is set to expire.

In the addInstance registration method, there is an invaldate method that sets all caches in readWriteCacheMap to expire.

  1. Time expired

When we build readWriteCacheMap to read and write cache, set up a responseCacheAutoExpirationInSeconds attribute, the default value is 180, or 180 seconds later will be expired

this.readWriteCacheMap = CacheBuilder.newBuilder().initialCapacity(1000) .expireAfterWrite(serverConfig.getResponseCacheAutoExpirationInSeconds(), TimeUnit. SECONDS). / / the default value of 180 s configInstance getIntProperty (namespace + "responseCacheAutoExpirationInSeconds", 180).get();Copy the code
  1. Passive overdue

Passive expiration is set relative to readOnlyCacheMap read-only cache, which executes a scheduled task every 30 seconds and sets the cache state to invalid

if (shouldUseReadOnlyResponseCache) {
            timer.schedule(getCacheUpdateTask(),
                    new Date(((System.currentTimeMillis() / responseCacheUpdateIntervalMs) * responseCacheUpdateIntervalMs)
                            + responseCacheUpdateIntervalMs),
                    responseCacheUpdateIntervalMs);
        }
Copy the code
  1. Extended out a problem, when the registered instance, logoff, fault, to invoke other services, the service could be separated after the 30 seconds, to perceive, because here at the time of access to the registry, a multistage cache mechanism, recently is 30 seconds to update the cache, the background have a scheduling tasks, once every 30 seconds will perform, The main function is to synchronize read and write cached and read-only cached data

5.4 Incremental registry fetching

When eureka client starts, it initializes the scheduling task. If the registry needs to be fetched,

There will be a 30 seconds (getRegistryFetchIntervalSeconds) a scheduling task execution, incremental registry fetching, another is before the initialization of scheduling tasks, if the configuration need to grab the registry, will go a way to grab the registry, In the method to determine whether to crawl the full registry or incremental registry

  1. The fetchRegistry method is set to allow fetching the registry. The method determines whether to perform full fetching or incremental fetching. The other method initializes a cache refresh task every 30 seconds. Both entries end up calling the same method.
  2. Fetching the delta registry by calling the apps/delta path with ALL_APPLICATION_DELTA as key. This will also go through the secondary cache. The difference is that if the read/write cache is not present, It gets the data from recentlyChangedQueue, and when we build this, we build a scheduling task that checks every 30 seconds to get rid of any data that’s been in this queue for more than 3 minutes, which means that this queue has the service instances that have changed in the last 3 minutes.
  3. After obtaining the value, the Eureka client computes a hash value and puts it into the service instance information. When the Eureka client receives the response, it merges the remote obtained value with the local cache value. After the merger, the Eureka client computes a hash value to determine whether the hash values at both ends of the object are equal. If not, it means something is wrong somewhere, so grab the full registry and synchronize it with the local cache.

In fact, eureka Server is suitable for us to learn

    • The registry’s second-level caching mechanism.
    • Recentlychange ue The use of update queues, add changes to the queue, set a periodic schedule, only retain the last three minutes of data.
    • Double-end calculation of hash value, once on the server and once on the client, using hash value to determine whether the data is the same, if not, it means that there is a problem in a link, and a full table fetching

6. Service renewal

The Eureka client sends heartbeat messages to the Eureka server every once in a while to inform the Server that it is still alive. In eureka, the heartbeat is called lease renewal

When eureka client starts, it initializes a thread pool and calls the Renew method in HeartbeatThread every 30 seconds by calling apps/appName/Id

The renewLease method changes the ** lastUpdateTimestamp attribute in the Lease object in the registry

Public void renew() {lastUpdateTimestamp = system.currentTimemillis () + duration; }Copy the code

7. Services are offline and removed

If a service needs to be stopped or restarted, the Eureka client needs to call EurekaClient’s shutdown method to stop the service instance.

  • The first step is to call shutdown to cancel the various schedulers and thread pools started when eureka client is started.

  • And then through a call to unregister method, called InstanceResouce. CancelLease method:

    • This method first removes the client from the registry
    • Add information about this instance to the recentCanceledQueue.
    • Update the offline time of the Lease object
    • I’m going to add this instance to the change opposite queue.
    • Invalidates the read/write cache
  • When eureka client is started, a 30-second scheduling task is constructed to synchronize readWriteCacheMap and readOnlyCacheMap cache values. Therefore, when other clients are performing incremental registry pulls, It finds that there’s no value in the read-only cache, no value in the read/write cache, and it reads recentlyChangedQueue, and the recentlyChangedQueue holds the previous instance going offline, so when the instance goes offline, the associated registry information, It’s removed from other service instances

8. Service instance fault awareness and service instance removal

Most of the time, it may not be that we take the service offline manually, but that the service itself has a problem, so the shutdown method will not be called, and the request to take the service instance offline will not be sent. In this case, it depends on Eureka’s fault awareness mechanism and service instance removal mechanism

Eureka relies on heartbeats to determine if a service has failed. If a service has failed, it must not be sending a heartbeat. If eureka Server does not receive a heartbeat from a service instance for a period of time, it will assume that the service instance has failed.

The faulty instance is detected and removed by calling Registry. OpenForTraffic (applicationInfoManager, registryCount)

  1. First, when eureka Server starts, the openForTraffic method is called to initialize a scheduled task, which is executed every 60 seconds
  2. A compensation time is obtained, which is used to calculate the difference between the current time and the last execution time in the event of a failure to renew an operation during gc or a problem with the server clock
  3. After getting the compensation time, evICT method will be called to obtain all the instance information, traversal, and obtain the lease object of each service instance
  4. The last update time is the current time + duration value, that is, the current time +90 seconds. However, when we calculate whether the service instance is expired or not, Duration * 2 + duration * 2 + duration * 2 + duration * 2 + duration * 2 + duration * 2 Now it will expire after 180 seconds, this is a bug
  5. When we decide whether to expire or not, we add the past data to the set. Here, we do not adopt a one-time expiration method, but adopt a partial random expiration method, only a few values can be expired at a time
int registrySize = (int) getLocalRegistrySize(); // 20 * 0. 85 = 17 int registrySizeThreshold = (int) (registrySize * serverConfig.getRenewalPercentThreshold()); // 20% // 20-17 = 3, int evictionLimit = registrySize - registrySizeThreshold; Leases = leases. Min (expiredLeases. Size (), evictionLimit);Copy the code

With a random algorithm, each value that can only expire in a subset of the set, call internalCancel offline, remove it from the registry, add it to the cancel queue, add it to the last change queue, invalidate the cache information.

9. Self-protection against network faults

Suppose there are 20 service instances, and after a minute, only 8 service instances are still beating. Would you remove the remaining 12 service instances? At this time, it is likely that the network of Eureka Sevrer fails to receive the heartbeat, so that the local eureka Server does not update the heartbeat of the service instance. Therefore, eureka Server does not send heartbeat for more than a certain proportion of service instances within a period of time. It thinks it has failed, enters a protection mechanism, and no more service instances are removed from it

  • In eureka server startup, there is a pull from adjacent note service instance registry steps, in this step will pull to the registry and their own local information, to compare, if have their own local does not exist, will its registered to their local, is completed, will return the l pull to the number of the registry.
  • Access to the last synchronization to the number of, into service instance failure stage, first to pull onto a service instance number * 2, to perform a contract operation because the default is 30 seconds, this is one minute for a cycle, so will the number * 2, that is to say, if there are 10 service instance, in one minute by default, It takes 20 heartbeats. (* * * 2 it directly, of course, is not correct, because we could set the time interval, if behind 1.9 repair), then take this value * * * serverConfig. GetRenewalPercentThreshold (the default is 0.85), Calculated per minute to receive an expected number of heartbeat numberOfRenewsPerMinThreshold * * * *
/ / because every 30 seconds sends a heartbeat, the following calculation calculation of minute when it's worth, so direct * 2 enclosing expectedNumberOfRenewsPerMin = count * 2; // Calculate the number of heartbeats you want to receive per minute. At least count * 2 * 85% response this. NumberOfRenewsPerMinThreshold = (int) (enclosing expectedNumberOfRenewsPerMin * serverConfig.getRenewalPercentThreshold()); // The default value is 0. 85Copy the code
  • In the following code, if false is returned, the subsequent service instance removal operations will not continue
if (! // todo logger.debug("DS: lease expiration is currently disabled."); return; } public Boolean isLeaseExpirationEnabled() {if (! IsSelfPreservationModeEnabled ()) {/ / whether to enable the self protection mechanism, The default is true; // The self preservation mode is disabled, hence The instances to expire. Return true; } / / numberOfRenewsPerMinThreshold I expect is a minute how many heartbeat sending here / / getNumOfRenewsInLastMin get on a minute, all service instance, Renewslastmin.getcount (); RenewsLastMin is renewed every time a heartbeat comes in, and counts the number of beats per minute. If the number of beats per minute is greater than the expected number, return true to remove expired instances. At this point it returns false, don't expire instance/how is * * * * numberOfRenewsPerMinThreshold eureka server startup, Will be initialized once this value * / return numberOfRenewsPerMinThreshold > 0 && getNumOfRenewsInLastMin () > numberOfRenewsPerMinThreshold; }Copy the code
  • The above code is also relatively simple:

    • The first is to check whether the parameters allow the self-protection mechanism to be turned on
    • NumberOfRenewsPerMinThreshold, this word is in the initialization phase calculated expectations of a number of minutes of the heart
    • GetNumOfRenewsInLastMin, this is the number of heartbeats received in a minute, this is a technical highlight
class MeasuredRate { public synchronized void start() { if (! Schedule (new TimerTask() {@override public void run() {// Zero out the current Bucket. // Save last for the last time // set the current value to 0 // that is, last for reading, Currentbucket.set (currentBucket.getAndSet(0)); } catch (Throwable e) { logger.error("Cannot reset the Measured Rate", e); } } }, sampleInterval, sampleInterval); isActive = true; }}}Copy the code

In simple terms, this class sets up a scheduled task, which is scheduled every 1 minute, assigns that minute’s worth of data to lastBucker for external reading, and then sets currentBucket to 0

    • Then a comparison is made. If the number of heartbeats in the last minute is greater than the expected number of heartbeats in one minute, the service is normal
    • If the number of heartbeats in the last minute is less than the expected number of heartbeats in one minute, the service is abnormal
    • Otherwise, the self-protection mechanism will be triggered and the service instance will not be removed
  • In addition, while initializing the registry object, a periodic scheduling task is built that executes every 15 minutes to update the expected number of heartbeats in a minute

  • When the service is registered, the expected number is +2, and when the service is offline, the expected number is -2, but when the service fails, the code of -2 is not found, which is expected to be a Bug

  • When eureka server is in protected mode, the sentence comes from a method that compares the number of heartbeats received in a minute with the expected number of heartbeats received in a minute

10. Synchronize registries between Eureka Server clusters

When eureka Server is started, it also acts as a Eureka client. Therefore, Eureka servers can form a cluster to register each other.

  • When eureka Server is started, a service instance of the cluster used by PeerEurekaNodes to process Eureka Server is initialized and added to the service context object for initialization.
  • There will be a start method that builds a single thread pool, and the scheduler will update the state of the cluster, build the Eureka Server information configured in the configuration file into PeerEurekaNodes instance objects that will exclude themselves, Dispatch every 10 minutes.
  • The syncUp method is then called to pull the registry cache from any of the nodes and store it locally. If 0 is retrieved, five retries are performed with a 30-second retry interval.
  • Of course, synchronization between Eureka Servers is performed every time services are online, offline, heartbeat, and failure
  • The addInstance method is called during registration, and after the service instance information is added to the registry, replicateToPeers is called to synchronize requests between clusters
  • To put it bluntly, the address configured in the configuration file, after removing itself, one by one call related (online, offline, heartbeat, fault) API.
  • In order to prevent endless cycles between service registrations, the isReplication parameter is used to control the synchronization. The default value is false, but the value is set to true during synchronization. It is not synchronized to other service instances to prevent an endless loop