Spring cloud - Eureka Registration Center

Eureka principle

eureka comes from ancient Greek words, meaning "discovered"

eureka is divided into two parts, Server side and Client side

Register

Service registration

The instance that wants to participate in service registration discovery needs to register information with Eureka server first

Registration is submitted when the first heartbeat occurs

Renew

Renewal, heartbeat

Eureka customers need to send a heartbeat every 30 seconds to renew the update and notify Eureka that the server instance is still active. If the server does not see the update within 90 seconds, it deletes the instance from its registry

Fetch Registry

Eureka client obtains registry information from the server and caches it locally.

The client then uses this information to find other services.

This information can be updated periodically (every 30 seconds) by obtaining incremental updates between the previous acquisition cycle and the current acquisition cycle.

The node information is saved in the server for a longer time (about 3 minutes), so the same instance may be returned again when obtaining the node information. Eureka client automatically handles duplicate information.

After obtaining the increment, Eureka client coordinates the information with the server by comparing the instance count returned by the server. If the information does not match for some reason, it obtains the whole registry information again.

Cancel

The Eureka client sends a cancellation request to the Eureka server when it is shut down. This will remove the instance from the instance registry of the server, effectively removing the instance from traffic.

Time Lag

Synchronization time delay

All operations from Eureka clients may take some time to be reflected on Eureka servers and then on other Eureka clients. This is because the payload cache on the Eureka server is refreshed periodically to reflect new information. Eureka clients also periodically acquire incremental. Therefore, it may take 2 minutes for the changes to propagate to all Eureka clients.

Communication mechanism

Communication mechanism

Rest request under Http protocol

By default, Eureka uses Jersey, Jackson and JSON to complete the communication between nodes

Service registration

Create a new web project and introduce starterspring cloud starter Netflix Eureka client

Client configuration options

#The default sending interval for renewal is 30 seconds, and the heartbeat interval is
eureka.instance.lease-renewal-interval-in-seconds=5
#It indicates how long the eureka client takes to pull the service registration information. The default value is 30 seconds. For API gateway, if you want to quickly obtain the service registration status, you can reduce this value, such as 5 seconds
eureka.client.registry-fetch-interval-seconds=5
# Renewal expiration time (default: 90 seconds)
eureka.instance.lease-expiration-duration-in-seconds=60

Server side configuration options

#Turn off self-protection mode
eureka.server.enable-self-preservation=false
#Failure service interval
eureka.server.eviction-interval-timer-in-ms=3000

Eureka alone

Rest service call

Official documents

https://github.com/Netflix/eureka/wiki/Eureka-REST-operations

OperationHTTP actionDescription
Register new application instancePOST /eureka/v2/apps/appIDInput: JSON/XMLpayload HTTPCode: 204 on success
De-register application instanceDELETE /eureka/v2/apps/appID/instanceIDHTTP Code: 200 on success
Send application instance heartbeatPUT /eureka/v2/apps/appID/instanceIDHTTP Code: * 200 on success * 404 if instanceIDdoesn't exist
Query for all instancesGET /eureka/v2/appsHTTP Code: 200 on success Output: JSON/XML
Query for all appID instancesGET /eureka/v2/apps/appIDHTTP Code: 200 on success Output: JSON/XML
Query for a specific appID/instanceIDGET /eureka/v2/apps/appID/instanceIDHTTP Code: 200 on success Output: JSON/XML
Query for a specific instanceIDGET /eureka/v2/instances/instanceIDHTTP Code: 200 on success Output: JSON/XML
Take instance out of servicePUT /eureka/v2/apps/appID/instanceID/status?value=OUT_OF_SERVICEHTTP Code: * 200 on success * 500 on failure
Move instance back into service (remove override)DELETE /eureka/v2/apps/appID/instanceID/status?value=UP (The value=UP is optional, it is used as a suggestion for the fallback status due to removal of the override)HTTP Code: * 200 on success * 500 on failure
Update metadataPUT /eureka/v2/apps/appID/instanceID/metadata?key=valueHTTP Code: * 200 on success * 500 on failure
Query for all instances under a particular vip addressGET /eureka/v2/vips/vipAddress* HTTP Code: 200 on success Output: JSON/XML * 404 if the vipAddressdoes not exist.
Query for all instances under a particular secure vip addressGET /eureka/v2/svips/svipAddress* HTTP Code: 200 on success Output: JSON/XML * 404 if the svipAddressdoes not exist.

/eureka/status service status

Requesting a url using a browser returns server status information

<com.netflix.eureka.util.StatusInfo>
  <generalStats>
    <environment>test</environment>
    <num-of-cpus>16</num-of-cpus>
    <total-avail-memory>526mb</total-avail-memory>
    <current-memory-usage>183mb (34%)</current-memory-usage>
    <server-uptime>00:00</server-uptime>
  </generalStats>
  <applicationStats>
    <registered-replicas></registered-replicas>
    <available-replicas></available-replicas>
    <unavailable-replicas></unavailable-replicas>
  </applicationStats>
  <instanceInfo>
    <instanceId>localhost</instanceId>
    <hostName>localhost</hostName>
    <app>UNKNOWN</app>
    <ipAddr>192.168.29.1</ipAddr>
    <status>UP</status>
    <overriddenstatus>UNKNOWN</overriddenstatus>
    <port enabled="true">8080</port>
    <securePort enabled="false">443</securePort>
    <countryId>1</countryId>
    <dataCenterInfo class="com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo">
      <name>MyOwn</name>
    </dataCenterInfo>
    <leaseInfo>
      <renewalIntervalInSecs>30</renewalIntervalInSecs>
      <durationInSecs>90</durationInSecs>
      <registrationTimestamp>0</registrationTimestamp>
      <lastRenewalTimestamp>0</lastRenewalTimestamp>
      <evictionTimestamp>0</evictionTimestamp>
      <serviceUpTimestamp>0</serviceUpTimestamp>
    </leaseInfo>
    <metadata>
      <management.port>8080</management.port>
      <jmx.port>7649</jmx.port>
    </metadata>
    <homePageUrl>http://localhost:8080/</homePageUrl>
    <statusPageUrl>http://localhost:8080/actuator/info</statusPageUrl>
    <healthCheckUrl>http://localhost:8080/actuator/health</healthCheckUrl>
    <vipAddress>unknown</vipAddress>
    <secureVipAddress>unknown</secureVipAddress>
    <isCoordinatingDiscoveryServer>false</isCoordinatingDiscoveryServer>
    <lastUpdatedTimestamp>1586328420409</lastUpdatedTimestamp>
    <lastDirtyTimestamp>1586328420519</lastDirtyTimestamp>
  </instanceInfo>
</com.netflix.eureka.util.StatusInfo>

If you need json format, you can add a request header Accept:application/json

{
    "generalStats": {
        "environment": "test",
        "num-of-cpus": "16",
        "total-avail-memory": "517mb",
        "current-memory-usage": "45mb (8%)",
        "server-uptime": "00:03"
    },
    "applicationStats": {
        "registered-replicas": "",
        "available-replicas": "",
        "unavailable-replicas": ""
    },
    "instanceInfo": {
        "instanceId": "localhost",
        "hostName": "localhost",
        "app": "UNKNOWN",
        "ipAddr": "192.168.29.1",
        "status": "UP",
        "overriddenStatus": "UNKNOWN",
        "port": {
            "$": 8080,
            "@enabled": "true"
        },
        "securePort": {
            "$": 443,
            "@enabled": "false"
        },
        "countryId": 1,
        "dataCenterInfo": {
            "@class": "com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo",
            "name": "MyOwn"
        },
        "leaseInfo": {
            "renewalIntervalInSecs": 30,
            "durationInSecs": 90,
            "registrationTimestamp": 0,
            "lastRenewalTimestamp": 0,
            "evictionTimestamp": 0,
            "serviceUpTimestamp": 0
        },
        "metadata": {
            "management.port": "8080",
            "jmx.port": "7649"
        },
        "homePageUrl": "http://localhost:8080/",
        "statusPageUrl": "http://localhost:8080/actuator/info",
        "healthCheckUrl": "http://localhost:8080/actuator/health",
        "vipAddress": "unknown",
        "secureVipAddress": "unknown",
        "isCoordinatingDiscoveryServer": "false",
        "lastUpdatedTimestamp": "1586328420409",
        "lastDirtyTimestamp": "1586328420519"
    }

View the service information registered with eureka

get: {ip:port}/eureka/apps

Check the specific services registered to eureka

get: {ip:port}/eureka/apps/{appname}/{id}

Service renewal

put: {ip:port}/eureka/apps/{appname}/{id}?lastDirtyTimestamp={}&status=up

Change service status

put: {ip:port}/eureka/apps/{appname}/{id}/status?lastDirtyTimestamp={}&value={UP/DOWN}
Corresponding to eureka source code: instanceresource statusUpdate

Delete status update

delete: {ip:port}/eureka/apps/{appname}/{id}/status?lastDirtyTimestamp={}&value={UP/DOWN}

Delete service

delete: {ip:port}/eureka/apps/{appname}/{id}

metadata

Eureka has two kinds of metadata: standard metadata and custom metadata.
Standard metadata: host name, IP address, port number, status page, health check and other information, which will be published in the service registry for calls between services.
Custom metadata: you can use Eureka instance. Metadata map configuration. These metadata can be accessed in the remote client, but generally do not change the client behavior unless the client knows the meaning of the metadata.

You can set custom metadata for the current service in the configuration file, which can be personalized for later users

Metadata can be configured on eureka server and eureka client

eureka.instance.metadata-map.dalao=mashibing

Server:

client:

{
    "applications": {
        "versions__delta": "1",
        "apps__hashcode": "UP_2_",
        "application": [
            {
                "name": "EUREKA-CONSUMER",
                "instance": [
                    {
                        "instanceId": "localhost:Eureka-Consumer:9001",
                        "hostName": "localhost",
                        "app": "EUREKA-CONSUMER",
                        "ipAddr": "192.168.29.1",
                        "status": "UP",
                        "overriddenStatus": "UNKNOWN",
                        "port": {
                            "$": 9001,
                            "@enabled": "true"
                        },
                        "securePort": {
                            "$": 443,
                            "@enabled": "false"
                        },
                        "countryId": 1,
                        "dataCenterInfo": {
                            "@class": "com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo",
                            "name": "MyOwn"
                        },
                        "leaseInfo": {
                            "renewalIntervalInSecs": 30,
                            "durationInSecs": 90,
                            "registrationTimestamp": 1586331982283,
                            "lastRenewalTimestamp": 1586331982283,
                            "evictionTimestamp": 0,
                            "serviceUpTimestamp": 1586331982283
                        },
                        "metadata": {
                            "dalao": "mashibing666",
                            "management.port": "9001",
                            "jmx.port": "10158"
                        },
                        "homePageUrl": "http://localhost:9001/",
                        "statusPageUrl": "http://localhost:9001/actuator/info",
                        "healthCheckUrl": "http://localhost:9001/actuator/health",
                        "vipAddress": "Eureka-Consumer",
                        "secureVipAddress": "Eureka-Consumer",
                        "isCoordinatingDiscoveryServer": "false",
                        "lastUpdatedTimestamp": "1586331982283",
                        "lastDirtyTimestamp": "1586331982260",
                        "actionType": "ADDED"
                    },
                    {
                        "instanceId": "localhost:Eureka-Consumer:9000",
                        "hostName": "localhost",
                        "app": "EUREKA-CONSUMER",
                        "ipAddr": "192.168.29.1",
                        "status": "UP",
                        "overriddenStatus": "UNKNOWN",
                        "port": {
                            "$": 9000,
                            "@enabled": "true"
                        },
                        "securePort": {
                            "$": 443,
                            "@enabled": "false"
                        },
                        "countryId": 1,
                        "dataCenterInfo": {
                            "@class": "com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo",
                            "name": "MyOwn"
                        },
                        "leaseInfo": {
                            "renewalIntervalInSecs": 30,
                            "durationInSecs": 90,
                            "registrationTimestamp": 1586331637223,
                            "lastRenewalTimestamp": 1586332057220,
                            "evictionTimestamp": 0,
                            "serviceUpTimestamp": 1586331637223
                        },
                        "metadata": {
                            "dalao": "mashibing",
                            "management.port": "9000",
                            "jmx.port": "10000"
                        },
                        "homePageUrl": "http://localhost:9000/",
                        "statusPageUrl": "http://localhost:9000/actuator/info",
                        "healthCheckUrl": "http://localhost:9000/actuator/health",
                        "vipAddress": "Eureka-Consumer",
                        "secureVipAddress": "Eureka-Consumer",
                        "isCoordinatingDiscoveryServer": "false",
                        "lastUpdatedTimestamp": "1586331637223",
                        "lastDirtyTimestamp": "1586331637182",
                        "actionType": "ADDED"
                    }
                ]
            }
        ]
    }
}

EurekaClient

eureka client can obtain the registrant information on eureka server at the client

org.springframework.cloud.client.discovery and com netflix. discovery. DiscoveryClient

org.springframework.cloud.client.discovery is an abstract encapsulation of the registry client by spring cloud, which provides common functions

org.springframework.cloud.client.discovery defines the client interface used for service discovery. It is the core interface used by the client for service discovery. It is the top-level interface used by spring cloud for service discovery. Its status can be seen in common. There are specific implementation classes in Netflix Eureka and consult.

Represents a read operation common to service discovery, such as in eureka or consumer.

have
	String description();//Gets the description of the implementation class.
	List<String> getServices();//Get all service instance IDs.
	List<ServiceInstance> getInstances(String serviceId);//Query the service instance information list through the service id.

com.netflix.discovery.DiscoveryClient is the interface of Eureka registry client, with more functions

Self protection mechanism

mechanism

Eureka belongs to AP in CAP theory, that is, when network partition is generated, Eureka guarantees the availability of the system, but does not guarantee the consistency of data in the system

It is enabled by default, which is a way of fault tolerance on the server side, that is, if the heartbeat does not arrive in a short time, the nodes in the service list will not be removed

EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY'RE NOT. RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUST TO BE SAFE.

By default, if Eureka Server does not receive a microservice heartbeat within a certain period of time, it will log off a microservice (90S). However, when the network fails, the micro service and the Server cannot communicate normally, and the above behavior is very dangerous, because the micro service is normal and should not be logged off.

Eureka Server solves the whole problem through self-protection mode. When the Server loses too many clients in a short time, the Server will enter self-protection mode and protect the micro services in the registry from being logged off. When the network fault recovers, exit the self-protection mode.

Thought: it's better to keep healthy and unhealthy than cancel any healthy services blindly.

Self protection trigger

The protection mechanism will be triggered when the number of client renewals per minute is less than 85% of the total number of clients

Trigger conditions of self-protection mechanism:
(when the number of heartbeats per minute (renewsLastMin) is less than numberOfRenewsPerMinThreshold and the automatic protection mode switch is turned on (Eureka. Server. Enable self preservation = true), the self-protection mechanism will be triggered and the lease will no longer expire automatically.)
numberOfRenewsPerMinThreshold = expectedNumberOfRenewsPerMin * renewal percentage (eureka.server.renewalPercentThreshold, 0.85 by default)
expectedNumberOfRenewsPerMin = number of currently registered application instances x 2
Why multiply by 2:
By default, the registered application instance is renewed every half a minute, so the heartbeat is twice a minute, so x 2.

Number of service instances: 10, expected renewal per minute: 10 * 2 = 20, expected threshold: 20 * 0.85 = 17, triggered when self-protection is less than 17.

eliminate:

    AbstractInstanceRegistry
    
    public void evict(long additionalLeaseMs) {
        logger.debug("Running the evict task");

        if (!isLeaseExpirationEnabled()) {
            logger.debug("DS: lease expiration is currently disabled.");
            return;
    }
    This code means: if Judged as true,Do not follow this logic, follow the following elimination. If if by false. Follow this logic and don't eliminate it.
PeerAwareInstanceRegistryImpl

    @Override
    public boolean isLeaseExpirationEnabled() {
        if (!isSelfPreservationModeEnabled()) {
        //If self-protection is turned on, this logic is not entered.
            // The self preservation mode is disabled, hence allowing the instances to expire.
            return true;
        }
        return numberOfRenewsPerMinThreshold > 0 && getNumOfRenewsInLastMin() > numberOfRenewsPerMinThreshold;
    }

close

eureka.server.enable-self-preservation=false

Prompt after closing

Cleaning time

Default 60 seconds

eureka.server.eviction-interval-timer-in-ms=3000

Multi network card selection

  1. ip registration
eureka:
  instance:
    prefer-ip-address: true
 Express that you will ip Register to EurekaServer Come on. No configuration or false,Indicates that the operating system will be hostname Register to server
  1. The server has multiple network cards, eh0, eh1 and eh2. Only eh0 can be accessed by other external services, and Eureka client registers eh1 and eh2 on Eureka server, so that other services cannot access the micro service.

  2. Specify Ip

    eureka:
      instance:
        prefer-ip-address: true
        ip-address: Actually accessible Ip
    

    If the ip address at this time is set, the metadata shows that it is this ip, and other services are also called through this ip.

    {
    	"host": "127.0.0.1",
    	"port": 8084,
    	"metadata": {
    		"yueyi": "2019",
    		"user.password": "root",
    		"management.port": "8084",
    		"jmx.port": "61378",
    		"user.name": "root"
    	},
    	"secure": false,
    	"uri": "http://127.0.0.1:8084",
    	"instanceId": "api-listen-order:30.136.133.11:port",
    	"serviceId": "API-LISTEN-ORDER",
    	"instanceInfo": {
    		"instanceId": "api-listen-order:30.136.133.11:port",
    		"app": "API-LISTEN-ORDER",
    		"appGroupName": null,
    		"ipAddr": "127.0.0.1",
    		"sid": "na",
    		"homePageUrl": "http://127.0.0.1:8084/",
    		"statusPageUrl": "http://127.0.0.1:8084/actuator/info",
    		"healthCheckUrl": "http://127.0.0.1:8084/actuator/health",
    		"secureHealthCheckUrl": null,
    		"vipAddress": "api-listen-order",
    		"secureVipAddress": "api-listen-order",
    		"countryId": 1,
    		"dataCenterInfo": {
    			"@class": "com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo",
    			"name": "MyOwn"
    		},
    		"hostName": "127.0.0.1",
    		"status": "UP",
    		"overriddenStatus": "UNKNOWN",
    		"leaseInfo": {
    			"renewalIntervalInSecs": 1,
    			"durationInSecs": 1,
    			"registrationTimestamp": 1579489514655,
    			"lastRenewalTimestamp": 1579489524146,
    			"evictionTimestamp": 0,
    			"serviceUpTimestamp": 1579489514147
    		},
    		"isCoordinatingDiscoveryServer": false,
    		"metadata": {
    			"yueyi": "2019",
    			"user.password": "root",
    			"management.port": "8084",
    			"jmx.port": "61378",
    			"user.name": "root"
    		},
    		"lastUpdatedTimestamp": 1579489514655,
    		"lastDirtyTimestamp": 1579489514111,
    		"actionType": "ADDED",
    		"asgName": null
    	},
    	"scheme": null
    }
    

    Or use spring cloud. Inetutils configuration network card selection

Eureka health examination

Because the server and client maintain the service status through heartbeat, only the service in UP status can be accessed. Look at the status in the eureka interface.

For example, the heartbeat is always normal and the service is always UP, but the service DB cannot be connected and cannot provide services normally.

At this point, we need to synchronize the health status of the micro service to the server. Just start eureka's health check. In this way, the micro service will synchronize its health status to eureka. The configuration is as follows.

Turn on manual control

Configure on the client side: propagate your true health status to the server.

eureka:
  client:
    healthcheck:
      enabled: true

Configure actor on Client side

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-actuator</artifactId>
		</dependency>

Service s that change health status

@Service
public class HealthStatusService implements HealthIndicator{

	private Boolean status = true;

	public void setStatus(Boolean status) {
		this.status  = status;
	}

	@Override
	public Health health() {
		// TODO Auto-generated method stub
		if(status)
		return new Health.Builder().up().build();
		return new Health.Builder().down().build();
	}

	public String getStatus() {
		// TODO Auto-generated method stub
		return this.status.toString();
	}

Controller for test

	@GetMapping("/health")
	public String health(@RequestParam("status") Boolean status) {
		
		healthStatusSrv.setStatus(status);
		return healthStatusSrv.getStatus();
	}

Security configuration

Open Eureka secure connection

spring.security.user.name=yiming
spring.security.user.password=123

If the service registration reports an error

Root name 'timestamp' does not match expected ('instance') for type [simple

Yes, cross domain attack prevention is enabled by default

Manual shutdown

Add configuration classes on the server

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		// TODO Auto-generated method stub
		http.csrf().disable();
		super.configure(http);
	}

}

Inter service call

In microservices, many service systems run in independent processes, and all business functions of a large project are realized through the cooperation between various service systems. Service systems use a variety of cross process ways to communicate and cooperate, and RESTful network request is one of the most common ways of interaction.

spring cloud provides:

  1. RestTemplate
  2. Feign

I am used to using RestTemplate because it is free and convenient to call other third-party http services. feign can also be more object-oriented and elegant. It just needs to be configured.

Rest

RESTful network request refers to RESTful style network request, in which REST is the abbreviation of resource representative state transfer, which is directly translated as "resource presentation layer state transfer".
Resource stands for Internet resources. The so-called "resource" is an entity on the network, or a specific information on the Internet. It can be a piece of text, a song or a service. It can be pointed to by a URI, and each "resource" corresponds to a URI.
Representational means "presentation layer". "Resource" is a kind of message entity, which can have a variety of external forms. We call the form of "resource" as its "expression layer". For example, text can be expressed in TXT format, XML format, JSON format and binary format; Video can be expressed in MP4 format or AVI format. The URI only represents the entity of the resource, not its form. Its specific manifestation should be specified by the HTTP request header information Accept and content type fields, which are the description of the "presentation layer".
State Transfer refers to "State Transfer". The process of client accessing services inevitably involves the transformation of data and state. If the client wants to operate the server-side resources, it must use some means to make the server-side resources "state transition". This transformation is based on the presentation layer, so it is called "presentation layer state transition". The client implements the above operations by using four verbs in the HTTP protocol, which are: GET to obtain resources, POST to create or update resources, PUT to update resources and DELETE to DELETE resources.

RestTemplate is a synchronous HTTP network client interface provided by Spring. It can simplify the interaction between the client and the HTTP server, and it forces the use of RESTful style. It handles HTTP connections and closures, requiring only the user to provide the server's address (URL) and template parameters.

The Web service of the first level (Level 0) only uses HTTP as the transmission mode. In fact, it is only a specific form of remote method call (RPC). Both SOAP and XML-RPC fall into this category.
The Web service of the second level (Level 1) introduces the concept of resources. Each resource has a corresponding identifier and expression.
The Web services of the third level (Level 2) use different HTTP methods to perform different operations, and use HTTP status codes to represent different results. For example, HTTP GET method is used to obtain resources, and HTTP DELETE method is used to delete resources.
The Web services of the fourth level (Level 3) use HATEOAS. Link information is included in the expression of resources. The client can find the actions that can be performed according to the link.

git's restful api

https://developer.github.com/v3/

Keywords: Java Microservices RESTful

Added by eatfishy on Thu, 10 Feb 2022 04:32:14 +0200