Make writing a habit together! This is my first day to participate in the “Gold Digging Day New Plan · April More text challenge”, click to see the details of the activity
Eureka Server startup process analysis
Reading is easy, thinking is difficult, but the lack of one, it is useless — Franklin
Where to start the analysis
Web.xml in the Eureka-Server project
The loading sequence of Web projects is as follows:
- When a WEB project is started, the WEB container reads its configuration file, web.xml, and two nodes.
- Urgently, create a ServletContext (servlet context) that will be shared by all parts of the Web project.
- The container converts it to a key-value pair and passes it to the servletContext.
- Class instance in container creation, creating listeners
The loading order of WEB projects has nothing to do with the configuration order of element nodes in the file. That is, the filter is not loaded first because it is written before the listener. The loading order of the WEB container is ServletContext -> context-param -> listener -> filter -> servlet and these elements can be configured anywhere in the file
<! Context-param: context-param: context-param: context-param: context-param
<! -- The most important listener for eureka-core -->
<listener>
<listener-class>com.netflix.eureka.EurekaBootStrap</listener-class>
</listener>
Copy the code
Core classes EurekaBootStrap
Class structure
The EurekaBootStrap class implements the ServletContextListener. When the container is started, the contextInitialized method is called and the Servlet container event object is passed to EurekaBootStrap
Class methods and properties
Entry function call flow
Package: a package com.net flix. Eureka; Class: Public class EurekaBootStrap implements ServletContextListener When the container is started, the contextInitialized method is called and the Servlet container event object is passed to EurekaBootStrap, so start from here
// Initialize Eureka, including synchronizing with other EureKas and publishing registries
@Override
public void contextInitialized(ServletContextEvent event) {
/** Initialize the Eureka environment variable */
initEurekaEnvironment();
/** Initialize the eureka container context */
initEurekaServerContext();
/** Get the current ServetContext */
ServletContext sc = event.getServletContext();
/** Set serverContext to ServletContext */
sc.setAttribute(EurekaServerContext.class.getName(), serverContext);
}
Copy the code
In the figurecontextInitialized#initEurekaServerContext();The method is more important and the main core logic is in there
Initialize the environment variable initEurekaEnvironment()
- InitEurekaEnvironment () calls this method when the Eureka service is started to initialize the Eureka server environment. If there is no data center configuration, the default environment will be used and the environment will be set as the test environment
protected void initEurekaEnvironment(a) throws Exception {
/** EUREKA_DATACENTER = "eureka.datacenter" */
String dataCenter = ConfigurationManager.getConfigInstance().getString(EUREKA_DATACENTER);
// If the data center is configured, go to the data center; if the data center is not configured, go to the default
if (dataCenter == null) {
ConfigurationManager.getConfigInstance().setProperty(ARCHAIUS_DEPLOYMENT_DATACENTER, DEFAULT);
} else {
ConfigurationManager.getConfigInstance().setProperty(ARCHAIUS_DEPLOYMENT_DATACENTER, dataCenter);
}
// Get the eureka runtime environment if it is empty then set it as the test environment, if it is not empty then go to the set environment
String environment = ConfigurationManager.getConfigInstance().getString(EUREKA_ENVIRONMENT);
if (environment == null) { ConfigurationManager.getConfigInstance().setProperty(ARCHAIUS_DEPLOYMENT_ENVIRONMENT, TEST); }}Copy the code
Initialize eureka container context initEurekaServerContext()
Mostly did those things
1. Initialize the configuration file using the interface
The main function is to load the configuration in the eureka-server.properties file
EurekaServerConfig eurekaServerConfig = new DefaultEurekaServerConfig();
Copy the code
Call the DefaultEurekaServerConfig# of init () method,
/** * The server is configured to provide the necessary information and some rules of behavior for eureka server. By default, it is loaded from the eureka-serevr.properties file. * Manage configuration with ConfigationManager and support multiple levels of configuration, configuration attribute overrides, and expose configuration access through the EurekaServerConfig interface. * namely DefaultEurekaServerConfig this method the eureka - serevr. The properties in the configuration file is read out all information on the ConfigurationManager class - this class, * because DefaultEurekaServerConfig inherited EurekaServerConfig implements the method of configuration information inside, DefaultEurekaServerConfig * in fact, this method by ConfigurationManager inside the access to information, because in the ConfigurationManager before there * /
private void init(a) {
// If the run environment is set then get the set run environment otherwise the test environment
String env = ConfigurationManager.getConfigInstance().getString(EUREKA_ENVIRONMENT, TEST);
ConfigurationManager.getConfigInstance().setProperty(ARCHAIUS_DEPLOYMENT_ENVIRONMENT, env);
// Get the name of the eureka-props property configured in the Eureka-server service. The default value is eureka-server
String eurekaPropsFile = EUREKA_PROPS_FILE.get();
// Load the configuration information into the ConfigurationManager
ConfigurationManager.loadCascadedPropertiesFromResources(eurekaPropsFile);
}
Copy the code
2. Construct clients inside eureka-server to register with other service nodes
// Initialize ApplicationInfoManager
ApplicationInfoManager applicationInfoManager = null;
// Initializes a eureka-client that is used to register and communicate with other Eureka-servers
if (eurekaClient == null) {
/ / default is test environment so not cloud environment, so leave new MyDataCenterInstanceConfig () this method
// Load the eureka-client.properties configuration file into the ConfigurationManager for unified management.
// The EurekaInstanceConfig interface is used to fetch data from the Eureka-client
EurekaInstanceConfig instanceConfig = new MyDataCenterInstanceConfig();
/** * Construct InstanceInfo directly based on EurekaInstanceConfig and InstnaceInfo. An ApplicationInfoManager is constructed on which some management of the service instance will be performed
applicationInfoManager = new ApplicationInfoManager(instanceConfig, new EurekaConfigBasedInstanceInfoProvider(instanceConfig).get());
/ * * * through DynamicPropertyFactory configInstance create DefaultEurekaTransportConfig transmission configuration, and created eureka - client configuration, Access */ through the EurekaClientConfig interface
EurekaClientConfig eurekaClientConfig = new DefaultEurekaClientConfig();
/*** * A EurekaClient is built based on the ApplicationInfoManager (which contains the information and configuration of the service instance as a component of the service instance management), and the configuration of the Eureka client. Use a subclass of EurekaClient, DiscoveryClient */
eurekaClient = new DiscoveryClient(applicationInfoManager, eurekaClientConfig);
} else {
applicationInfoManager = eurekaClient.getApplicationInfoManager();
}
Copy the code
The eureka-client is used to communicate with other Eureka-server nodes, such as registering nodes, sending heartbeat, etc. (The construction and startup process of the client will be detailed later).
3. Construct a registry that is aware of service instances
PeerAwareInstanceRegistry registry;
/** * Create an empty instance registry, which contains a scheduled task (the task to detect queue changes is put into the scheduling pool, the default is 30 seconds) and three queues, * one registered instance queue, one offline instance queue, and one recently changed queue */
registry = new PeerAwareInstanceRegistryImpl(eurekaServerConfig,eurekaClient.getEurekaClientConfig(), serverCodecs,eurekaClient);
/** * 2.3 PeerEurekaNodes, handle eureka server cluster initialization */
PeerEurekaNodes peerEurekaNodes = getPeerEurekaNodes(
registry,eurekaServerConfig,eurekaClient.getEurekaClientConfig(),serverCodecs,applicationInfoManager);
Copy the code
PeerAwareInstanceRegistry: can sense the eureka server cluster instances of service registry, had the client (as a service instance) to register the registry, and the registry can be perceived eureka server cluster. If there is a eureka server cluster, this contains information about service instance registries in other Eureka servers
public class PeerAwareInstanceRegistryImpl extends AbstractInstanceRegistry{
public PeerAwareInstanceRegistryImpl(EurekaServerConfig serverConfig, EurekaClientConfig clientConfig, ServerCodecs serverCodecs, EurekaClient eurekaClient) {
super(serverConfig, clientConfig, serverCodecs); }}Copy the code
Taking a look at the important super method, create an empty instance registry that contains a scheduled task (the task to detect queue changes is put into the scheduling pool, which is executed every 30 seconds by default) and three queues, one for registering instances, one for offline instances, and one for recently changed instances
/** * creates an empty instance registry */
protected AbstractInstanceRegistry(EurekaServerConfig serverConfig, EurekaClientConfig clientConfig, ServerCodecs serverCodecs) {
this.serverConfig = serverConfig;
this.clientConfig = clientConfig;
this.serverCodecs = serverCodecs;
// The queue was recently cancelled
this.recentCanceledQueue = new CircularQueue<Pair<Long, String>>(1000);
// The most recently registered queue
this.recentRegisteredQueue = new CircularQueue<Pair<Long, String>>(1000);
// Renew the maximum minutes
this.renewsLastMin = new MeasuredRate(1000 * 60 * 1);
/ * * * detection task queue the changes in scheduling pool * serverConfig getDeltaRetentionTimerIntervalInMs () default is 30 s to perform a * /
this.deltaRetentionTimer.schedule(getDeltaRetentionTask(), serverConfig.getDeltaRetentionTimerIntervalInMs(), serverConfig.getDeltaRetentionTimerIntervalInMs());
}
Copy the code
When Registry is constructed, there is a scheduled task, which is scheduled every 30 seconds by default. Look at the change record of the service instance. If the service instance change record was in the queue for more than 180 seconds (3 minutes), if more than 3 minutes, the service instance change record will be removed from the queue. In other words, this queue keeps a record of service instance changes in the last 3 minutes.
private TimerTask getDeltaRetentionTask(a) {
return new TimerTask() {
@Override
public void run(a) {
Iterator<RecentlyChangedItem> it = recentlyChangedQueue.iterator();
while (it.hasNext()) {
/** * If the current system time - configured 180s is greater than the last update time then remove the instance */
if (it.next().getLastUpdateTime() < System.currentTimeMillis() - serverConfig.getRetentionTimeInMSInDeltaQueue()) {
it.remove();
} else {
break; }}}}; }Copy the code
4. Construct the context and initialize the context
/** * 2.3 The PeerEurekaNodes object is created to handle the configuration information required for eureka server cluster initialization */
PeerEurekaNodes peerEurekaNodes = getPeerEurekaNodes(
registry,/ / the registry
eurekaServerConfig, // Server configuration
eurekaClient.getEurekaClientConfig(), // Client configuration
serverCodecs,applicationInfoManager// Application manager
);
/** * 3. Construct a EurekaServerContext that represents a server context for the current Eureka server and contains everything the server needs. * /
serverContext = new DefaultEurekaServerContext(
eurekaServerConfig, // Server configuration
serverCodecs,
registry,/ / the registry
peerEurekaNodes,// The peerEurekaNodes object created above
applicationInfoManager); // Application manager
/ * * * * put this stuff in a EurekaServerContextHolder, who later if you want to use this EurekaServerContext, obtained directly from the holder. * /
EurekaServerContextHolder.initialize(serverContext);
/** *4. EurekaServerContext initializes the constructed server context */
serverContext.initialize();// Important method
Copy the code
It’s basically the initialization method of the service context. What’s going on in there
public void initialize(a) {
logger.info("Initializing ...");
/** * The eureka server is aware of all other Eureka servers. Then perform a scheduled task, just a background thread, every certain time, update the eureka server cluster information */
peerEurekaNodes.start();
Mysql > select * from eureka server; mysql > select * from eureka server; mysql > select * from eureka server; */ associated with registry information exchange between Eureka Server clusters
registry.init(peerEurekaNodes);
logger.info("Initialized");
}
Copy the code
The peerEurekaNodes () method starts a daemon thread that updates the address of the service list
public void start(a) {
// Create a task executor
taskExecutor = Executors.newSingleThreadScheduledExecutor("Eureka-PeerNodesUpdater"...). ;/** * Update eureka server url; /** * update eureka server URL
updatePeerEurekaNodes(resolvePeerUrls());
// Start a background thread, by default every 10 minutes, to refresh the eureka server list based on the URL in the configuration file
Runnable peersUpdateTask = new Runnable() {
@Override
public void run(a) { updatePeerEurekaNodes(resolvePeerUrls()); }};/ / serverConfig. GetPeerEurekaNodesUpdateIntervalMs () default is 10 * 60 * 1000 = 10 minutes
taskExecutor.scheduleWithFixedDelay(peersUpdateTask, serverConfig.getPeerEurekaNodesUpdateIntervalMs(),
serverConfig.getPeerEurekaNodesUpdateIntervalMs(),
TimeUnit.MILLISECONDS);
for (PeerEurekaNode node : peerEurekaNodes) {
logger.info("Replica node URL: {}", node.getServiceUrl()); }}Copy the code
Registry. Init (peerEurekaNodes), the method of registry initialization, see what is done inside
@Override
public void init(PeerEurekaNodes peerEurekaNodes) throws Exception {
this.peerEurekaNodes = peerEurekaNodes;
// Initialize the cache
initializedResponseCache();
// Related to renewalscheduleRenewalThresholdUpdateTask(); . }Copy the code
InitializedResponseCache () : initializedResponseCache() : initializedResponseCache() : initializedResponseCache() : initializedResponseCache() : initializedResponseCache(
@Override
public synchronized void initializedResponseCache(a) { // synchronized
if (responseCache == null) {
responseCache = new ResponseCacheImpl(serverConfig, serverCodecs, this); }}Copy the code
5. Obtain the service registration list from other Eureka-server nodes
When eureka-server starts initialization, the current Eureka-server pulls the registry from any other Eureka-server and places it locally as the initial registry. Make yourself a Eureka client, find any Eureka server to pull the registry, pull the registry to their own local
int registryCount = registry.syncUp();
@Override
public int syncUp(a) {
// Copy entire entry from neighboring DS node
int count = 0;
/ * * * serverConfig. GetRegistrySyncRetries () can retry up to five times the default is 5 * /
for (int i = 0; ((i < serverConfig.getRegistrySyncRetries()) && (count == 0)); i++) {
if (i > 0) {
/ / serverConfig. GetRegistrySyncRetryWaitMs () default is 30 s, 30 s sleep
Thread.sleep(serverConfig.getRegistrySyncRetryWaitMs());
}
/** * get all instance information */
Applications apps = eurekaClient.getApplications();
for (Application app : apps.getRegisteredApplications()) {
for (InstanceInfo instance : app.getInstances()) {
try {
if (isRegisterable(instance)) {
register(instance, instance.getLeaseInfo().getDurationInSecs(), true); // Important methodcount++; }}catch (Throwable t) {
logger.error("During DS init copy", t); }}}}return count;
}
Copy the code
Register (instance, instance.getleaseinfo ().getdurationinsecs (), true) This is the main method to register with your local cache, which will be explained later, as this method is also very complicated, This operation involves obtaining instance configuration information and accessing interfacesCopy the code
6. Regularly eliminate services without heartbeat
Automatic check service instances for failures and outages entry, and a follow-up article will be provided to explain
registry.openForTraffic(applicationInfoManager, registryCount);
Copy the code
7. Register monitors
/** * Is associated with eureka's own monitoring mechanism */
EurekaMonitors.registerAllStats();
Copy the code
At this point eureka server initialization is complete
summary
- Initialize the Eureka environment variable and configure the data center initEurekaEnvironment()
- Initialize the eureka server server configuration, created DefaultEurekaServerConfig object, the right picture there is an init method, The configuration file in Eureka-server. properties is loaded to the ConfigurationManager to obtain the information in the configuration file through the interface
- Initialize the client, through new MyDataCenterInstanceConfig () this object will be eureka – client. The properties of load to the ConfigurationManager configuration properties, And through EurekaInstanceConfig interface to access, because MyDataCenterInstanceConfig EurekaInstanceConfig interface is achieved, and through the DiscoveryClient created the client
- Create a service registry (PeerAwareInstanceRegistry), create a eureka server cluster (PeerEurekaNodes), The EurekaServerContext is created using these two objects and the eurekaServerConfig, applicationInfoMaager, and encoding methods created above. Represents the current in a server context in the eureka server everything, put this thing in a EurekaServerContextHolder, who later if you want to use this EurekaServerContext, We can get it directly from the holder, and then initialize(), fetching the registry, etc
- Initial Eureka server context operation
- Copy registry information from a neighboring Eureka Server node
- Registration is associated with Eureka’s own monitoring mechanism