Getting started with Spring cloud-5: Service Registry Eureka Service Discovery & self protection mechanism

Posted by danielle on Sat, 08 Jan 2022 12:37:57 +0100

1. Service discovery

  in the last blog post, Eureka cluster environment has been built.

As shown in the figure above, three services have been registered in the eureka cluster: order service (80018002) and consumption order module 80.
At this time, we want to check how many services have been registered in the service registry. What should we do? You can use the service Discovery annotation of spring cloud client.

1.1 modify instance name

  modify the instance names of eureka configuration in order service 80018002 to payment8001 and payment8002

1.2 build service discovery interface

We build the service discovery interface in the consumer order module, then call the interface to see which services are registered in the eureka. And the information corresponding to these services.
First, add the service discovery interface code in the OrderController of the consumption order module:
  

package com.example.springcloud.controller;

import com.example.springcloud.entities.CommonResult;
import com.example.springcloud.entities.Payment;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
@Slf4j
public class OrderController {
//    public static final String PAYMENT_URL = "http://localhost:8001";
    public static final String PAYMENT_URL = "http://CLOUD-PAYMENT-SERVICE";

    @Resource
    private RestTemplate restTemplate;

    @Resource
    private DiscoveryClient discoveryClient;

    /**
     * Service Discovery Interface
     */
    @GetMapping("/consumer/discovery")
    public CommonResult discovery() {
        List<Map<String, Object>> resMap = new ArrayList<>();
        // Get all services
        List<String> services = discoveryClient.getServices();
        for (String service : services) {
            log.info("Registered services: " + service);
            // Get all instances of each service
            List<ServiceInstance> instances = discoveryClient.getInstances(service);
            for (ServiceInstance instance : instances) {
                log.info("\t" + instance.getServiceId() + "\t" + instance.getHost() + "\t"
                        + instance.getPort() + "\t" + instance.getUri());
                Map<String, Object> map = new HashMap<>();
                map.put("Service name", service);
                map.put("Instance name", instance.getInstanceId());
                map.put("Host address", instance.getHost());
                map.put("Port number", instance.getPort());
                map.put("uri address", instance.getUri());
                resMap.add(map);
            }
        }
        return new CommonResult(200, "Service discovery succeeded", resMap);
    }

    @GetMapping(value = "/consumer/payment/create")
    public CommonResult create(Payment payment) {
        return restTemplate.postForObject(PAYMENT_URL+"/payment/create", payment, CommonResult.class);
    }

    @GetMapping(value = "/consumer/payment/get/{id}")
    public CommonResult getPayment(@PathVariable("id") Long id) {
        return restTemplate.getForObject(PAYMENT_URL+"/payment/get/"+id, CommonResult.class);
    }
}

1.3 testing

   as in the previous article, start the cluster environment, and then test whether the service discovery interface just written in the consumer order module can return all services and corresponding information on the current eureka cluster.
As shown in the following figure, the order service in eureka can now display the instance names payment8001 and payment8002 we just customized.
At the same time, we call the query service interface of the consumption module to view all registered service names and corresponding instance names, IP and port numbers.

2. eureka self-protection mechanism

   self protection mechanism is a security protection measure against abnormal network fluctuations. The use of self-protection mode can make Eureka cluster run more robust and stable.
As mentioned in the previous blog post, how does the Eureka server know that the service can still be used after the service is registered with the Eureka server? That's because the service will send heartbeat to Eureka server regularly (30s by default). However, when Eureka server does not receive the heartbeat of a micro service instance after a certain time (90 seconds by default), Eureka server will remove the instance. Therefore, if an instance of a service can provide access, but a short-term network exception causes no heartbeat to be sent, Eureka server will not remove the instance of the service.
So what is the self-protection mechanism?
If more than 85% of the client nodes do not have a normal heartbeat within 15 minutes, Eureka thinks that there is a network failure between the client and the registry, and Eureka Server automatically enters the self-protection mechanism. At this time, the following situations will occur:

  1. Eureka Server no longer removes services that should expire because they have not received a heartbeat for a long time from the registration list.
  2. Eureka Server can still accept the registration and query requests of new services, but it will not be synchronized to other nodes to ensure that the current node is still available.
  3. When the network is stable, the new registration information of the current Eureka Server will be synchronized to other nodes.

  therefore, the red font in eureka server is easy to understand.
  1)EMERGENCY! eureka may be incorrectly claiming instances are UP when that'RE NOT: in an emergency, the service instance may not be callable, but eureka will still show that the service instance is available (UP). It is telling us that eureka has opened the self-protection mode

  next, some parameters in eureka are described:
Renew threshold: the total number of client instance renewals that Eureka Server expects to receive per minute.
Renews (last min): the total number of client instance renewals received by Eureka Server in the last minute.
By default, the service instance sends a heartbeat every 30s, so the expected number of instance heartbeats per minute for the three services is 6.

   after the order service 8001 is quickly and abnormally closed, you can see that the service 8001 has been displayed as unavailable, but the instance will not be removed soon.
  

3 prohibition of self-protection

3.1 eureka closes the self-protection mechanism

server.port=7001

# Instance name of eureka server
#eureka.instance.hostname=localhost
eureka.instance.hostname=eureka7001.com
# false means that you do not register yourself with the registry
eureka.client.register-with-eureka=false
# false means that you are the registry. Your responsibility is to maintain service instances and you do not need to retrieve services
eureka.client.fetch-registry=false
# Set the address to interact with Eureka Server. Both query service and registration service need to rely on this address
#eureka.client.service-url.defaultZone=http://${eureka.instance.hostname=localhost}:${server.port}/eureka/
eureka.client.service-url.defaultZone=http://eureka7002.com:7002/eureka/
# The registry closes the self-protection mechanism
eureka.server.enable-self-preservation=false
# Modify the time when eureka server checks for failed services
eureka.server.eviction-interval-timer-in-ms=3000

3.2 microservices reduce heartbeat sending time

server.port=8001

spring.application.name=cloud-payment-service
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=org.gjt.mm.mysql.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/springcloud?useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.datasource.username=root
spring.datasource.password=123

mybatis.mapperLocations=classpath:mapper/*.xml
mybatis.type-aliases-package=com.example.springcloud.entities

# Add Eureka Client configuration
# Indicates whether to register yourself with Eureka Server. The default value is true
eureka.client.register-with-eureka=true
# Indicates whether to retrieve the existing registration information from Eureka Server. The default value is true.
# This configuration doesn't matter in the case of a single node. It must be set to true in the case of cluster configuration to use load balancing with ribbon
eureka.client.fetchRegistry=true
#eureka.client.service-url.defaultZone=http://localhost:7001/eureka # standalone
eureka.client.service-url.defaultZone=http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka #Cluster version
eureka.instance.instance_id=payment8001
# Microservice modification reduces service heartbeat time
eureka.instance.lease-expiration-duration-in-seconds=1
eureka.instance.lease-renewal-interval-in-seconds=3

3.3 testing

Start the eureka cluster service. When the order service 8001 is shut down abnormally, you can see that the eureka server removes the order service 8001 after a few seconds

Topics: Spring Cloud eureka