Know SpringCloud (1) Registration Center Eureka

Spring Cloud encapsulates the Eureka module developed by Netflix to implement service governance. In the traditional rpc remote call framework, it is more complicated to manage the dependencies between each service and the service, and the management is more complicated, so it is necessary to use service governance to manage the dependencies between services and services, which can realize service calls, load balancing, and fault tolerance etc. to realize service discovery and registration.

How to use

It is very simple to use Eureka in the springboot project. You only need the following steps to start a server.
Add dependencies to the pom file:

 <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>

Modify the yml file

server:
  port: 8610

spring:
  application:
    name: datax-eureka

eureka:
  instance:
    lease-renewal-interval-in-seconds: 20
    lease-expiration-duration-in-seconds: 60
    # Set to use IP
    prefer-ip-address: true
    # Set the external network IP number
    ip-address: localhost
  client:
    register-with-eureka: false
    fetch-registry: false
    instance-info-replication-interval-seconds: 40
    service-url:
      defaultZone: http://${<!-- -->eureka.instance.ip-address}:${<!-- -->server.port}/eureka/

Add @EnableEurekaServer annotation to the startup class

@EnableEurekaServer
@SpringBootApplication
public class DemoEurekaApplication {<!-- -->

    public static void main(String[] args) {<!-- -->

        SpringApplication.run(DataxEurekaApplication.class, args);
    }

}

Browser access http://127.0.0.1:8610/, you can see that a simple EurekaServer has been built successfully

After a while, a prompt appeared: 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.
The reason for this error is because Eureka enters self-protection mode

Self-protection mode

By default, if more than 85% of the client nodes do not have a normal heartbeat within 15 minutes, then Eureka believes that there is a network failure between the client and the registration center (such as network failure or frequent startup and shutdown of the client), Eureka Server automatically enters self-protection mode. No longer remove any services, when the network failure is restored, the node will automatically exit the self-protection mode.

You can use eureka.server.enable-self-preservation=false to disable the self-preservation mode, which is not recommended for production environments.

Another way is to lower the threshold factor eureka.server.renewalPercentThreshold, the default is 0.85, if the threshold is greater than the minimum value, the self-protection mode is turned on

eureka:
  server:
    enable-self-preservation: true
    #eureka server cleans up the interval of invalid nodes, the default is 60000 milliseconds, that is, 60 seconds
    eviction-interval-timer-in-ms: 60000
    #Threshold update interval, the unit is milliseconds, the default is 15 * 60 * 1000
    renewal-threshold-update-interval-ms: 15 * 60 * 1000
    #Threshold factor, the default is 0.85, if the threshold is greater than the minimum value, the self-protection mode is turned on
    renewal-percent-threshold: 0.85
    #Cleanup task program wake-up time interval, clean up expired incremental information, the unit is milliseconds, the default is 30 * 1000
    delta-retention-timer-interval-in-ms: 30000

Client health check

By default, Eureka uses the client heartbeat to determine whether the client is started. After successful registration, Eureka always declares that the application is in the “UP” state, which causes a problem. Although the client is started, it may not be able to provide the correct service for some reason (such as database downtime). In order to solve this problem, a health check mechanism needs to be introduced.

Preconditions: Start a server (port 8610 in this article), and start creating a client (port 8611)

Eureka’s health check depends on Springboot-actuator’s /health, and you need to introduce the spring-boot-starter-actuator module dependency in pom.xml

<dependencies>
    <dependency>
       <groupId>org.springframework.cloud</groupId>
       <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
</dependencies>

Configure in the application.properties or yml file in the eureka client: eureka.client.healthcheck.enabled=true, you can change the way the eureka server checks the health of the client, and use Actuator’s /actuator/health endpoint to detect.

# Registry configuration
eureka:
  instance:
    lease-renewal-interval-in-seconds: 20
    # Set to use IP
    prefer-ip-address: true
    # Set the external network IP number
    ip-address: localhost
  client:
    health check:
      enabled: true
    register-with-eureka: true
    fetch-registry: true
    instance-info-replication-interval-seconds: 30
    registry-fetch-interval-seconds: 3
    service-url:
      defaultZone: http://localhost:8610/eureka

# Expose monitoring endpoint
management:
  endpoints:
    web:
      exposure:
        include: '*'
  endpoint:
    health:
      show-details: always

Create a new HealthIndicatorImpl and implement HealthIndicator to customize the monitoring logic.

import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.stereotype.Component;

@Component
public class HealthIndicatorImpl implements HealthIndicator {<!-- -->

    private boolean up = true;

    @Override
    public Health health() {<!-- -->
        if (up) {<!-- -->
        
            return new Health.Builder().withDetail("status", "up").up().build(); //Customize monitoring content
        } else {<!-- -->
    \t
            return new Health.Builder().withDetail("error", "client is down").down().build();
        }
    }

    public boolean isUp() {<!-- -->
        return up;
    }

    public void setUp(boolean up) {<!-- -->
        this.up = up;
    }
}

Add annotations @EnableDiscoveryClient or @EnableEurekaClient on the startup class (@EnableEurekaClient is only applicable to Eureka as a registration center, @EnableDiscoveryClient can be other registration centers)

After the client starts, the server shows that the client service status is UP

Visit http://127.0.0.1:8611/actuator/health to view client status

{<!-- -->
  "status": "UP",
  "components": {<!-- -->
    "configServer": {<!-- -->
      "status": "UP",
      "details": {<!-- -->
        "repositories": [
          {<!-- -->
            "name": "app",
            "profiles": [
              "default"
            ],
            "label": null
          }
        ]
      }
    },
    "discoveryComposite": {<!-- -->
      "status": "UP",
      "components": {<!-- -->
        "discoveryClient": {<!-- -->
          "status": "UP",
          "details": {<!-- -->
            "services": [
              "datax-config"
            ]
          }
        },
        "eureka": {<!-- -->
          "description": "Remote status from Eureka server",
          "status": "UP",
          "details": {<!-- -->
            "applications": {<!-- -->
              "DATAX-CONFIG": 1
            }
          }
        }
      }
    },
    "diskSpace": {<!-- -->
      "status": "UP",
      "details": {<!-- -->
        "total": 107373129728,
        "free": 6842404864,
        "threshold": 10485760,
        "exists": true
      }
    },
    "healthIndicatorImpl": {<!-- -->
      "status": "UP",
      "details": {<!-- -->
        "status": "up"
      }
    },
    "hystrix": {<!-- -->
      "status": "UP"
    },
    "ping": {<!-- -->
      "status": "UP"
    },
    "refreshScope": {<!-- -->
      "status": "UP"
    }
  }
}

In order to facilitate the simulation, create a controller

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HealthController {<!-- -->

    @Autowired
    private HealthIndicatorImpl myHealthChecker;

    @RequestMapping("/up")
    public String up(@RequestParam("up") Boolean up) {<!-- -->
        myHealthChecker. setUp(up);
        return myHealthChecker.isUp() ? "UP" : "DOWN";
    }
}

Visit http://127.0.0.1:8611/up?up=false to change the status of the client, and the server can see that the status has changed from UP to DOWN.

Eureka workflow

  1. Eureka Server starts successfully, waiting for server registration
  2. When the Eureka Client starts, go to the registration center to register the service according to the configured Eureka Server address
  3. Eureka Client will send a heartbeat to Eureka Server every 30 seconds to prove that the client service is normal
  4. When the Eureka Server does not receive the heartbeat from the Eureka Client within 90 seconds, the registry will consider the node invalid and log off the instance
  5. If Eureka Server counts a large number of Eureka Clients that have not sent heartbeats per unit time, it may be considered to be a network anomaly, enter the self-protection mechanism, and no longer exclude clients that have not sent heartbeats
  6. When the heartbeat of Eureka Client returns to normal, Eureka Server automatically exits the self-protection mechanism
  7. Eureka Client obtains the service registry from the registry in full or incrementally at regular intervals, and caches the obtained information locally
  8. When the service is called, Eureka Client will first find the called service from the local cache. If you can’t get it, refresh the registry from the registry first, and then synchronize to the local cache
  9. Eureka Client obtains the target server information and initiates a service call
    10. When the Eureka Client program is closed, it sends a cancellation request to the Eureka Server, and the Eureka Server removes the instance from the registry