I. Introduction to Eureka

1. What is service governance

Spring Cloud encapsulates the Eureka module developed by Netflix to achieve service governance. In the traditional RPC remote call framework, it is complicated to manage the dependency relationship between each service and service, so it is necessary to use service governance to manage the dependency relationship between services, which can realize service invocation, load balancing, fault tolerance, etc., and realize service discovery and registration.

2. What is service registration and discovery

Eureka adopts CS design architecture. Eureka Sever serves as the server for service registration function. It is the service registry. Other microservices in the system use Eureka’s clients to connect to Eureka Server and maintain heartbeat connections. In this way, the maintenance personnel of the system can monitor the normal operation of each micro-service in the system through Eureka Server.

In service registration and discovery, there is a registry. When the server is started, it aliases the information of the current server to the registry, such as the service address and correspondence address. Another party (consumer service provider), in the form of the alias to registry access to the actual service address, and then realize local RPC calls RPC remote invocation framework core design idea: lies in the registry, because use registry management a dependency between each service and the service (service governance concept). In any RPC remote framework, there is a registry that holds information about the service address (interface address).

3. Eureka consists of two components :Eureka Server and Eureka Client

Eureka Server provides service registration services

After each micro-service node is configured and started, it will be registered in EurekaServer. In this way, the service registry in EurekaServer will store the information of all available service nodes, and the information of service nodes can be directly seen on the interface.

EurekaClient is accessed through a registry

It is a Java client designed to simplify Eureka Server interactions and also has a built-in load balancer that uses round-robin load algorithms. After the application is started, the heartbeat is sent to the Eureka Server (default interval is 30 seconds). If EurekaServer does not receive a heartbeat from a node within multiple heartbeat cycles, EurekaServer will remove the node from the service registry (default: 90 seconds).

Ii. Construction of single point Eureka

1. Create the module environment (Cloud-Eureka-Server7001)

Pom file

Differences between the old version and the new version:

<! -- Eureka old and new -->
<! -- Old version (2018) -->
<dependency>
    <groupid>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>

<! -- Now new version (2020.2) --><! -- We use the latest -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
Copy the code

Now use the new version and introduce all dependencies:


      
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>cloud2021</artifactId>
        <groupId>com.atguigu</groupId>
        <version>1.0.0 - the SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.atguigu.springcloud</groupId>
    <artifactId>cloud-eureka-server7001</artifactId>

    <dependencies>
        <! --eureka-server-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
        <! -- Introduced a generic API package that allows you to pay Entity using Payment -->
        <dependency>
            <groupId>com.atguigu.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        <! --boot web actuator-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <! -- General General configuration -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>
    </dependencies>

</project>
Copy the code

Yaml files

server:
  port: 7001

eureka:
  instance:
    hostname: locathost # Eureka server instance name
  client:
    #false: do not register yourself with the registry.
    register-with-eureka: false
    #false indicates that my end is the registry and my responsibility is to maintain the service instance, not to retrieve the service
    fetch-registry: false
    service-url:
      This address is used by the Eureka server.
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
Copy the code

Write programs

Start the class:

@SpringBootApplication
@EnableEurekaServer
public class EurekaMain7001 {
    public static void main(String[] args) { SpringApplication.run(EurekaMain7001.class,args); }}Copy the code

Note that this is the Eureka server.

Start and go to Eureka. You can see the Eureka registry page.

2. Inject other modules into Eureka

Introduction of depend on

Module 8001 introduces dependencies.

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
Copy the code

annotations

Annotate the Eureka customer as the user.

@SpringBootApplication
@EnableEurekaClient
public class PaymentMain8001 {
    public static void main(String[] args) { SpringApplication.run(PaymentMain8001.class,args); }}Copy the code

Yaml configuration

eureka:
  client:
    # indicates to register with eurekaServer server
    register-with-eureka: true
    The default value is true. Clusters must be set to true to work with the ribbon to ensure load balancing
    fetch-registry: true
    service-url: 
      defaultZone: http://localhost:7001/eureka
Copy the code

Open discovery registered in:

The same is true for module 80.

Introduce dependencies, annotate, and write YAML.

eureka:
  client:
    # indicates whether to register yourself in Eurekaserver. The default is true.
    register-with-eureka: true
    Whether to fetch existing registration information from EurekaServer. Default is true. The cluster must be set to True to use load balancing with the ribbon
    fetchRegistry: true
    service-url:
      defaultZone: http://localhost:7001/eureka
Copy the code

The test found that the service center was joined.

3. Construction of Eureka cluster

1. Eureka cluster principle description

In the case of multiple Eureka service clusters, each Eureka needs to register the information of other EureKas to ensure that they can call each other.

2. Set up EurekaServer cluster

Create the cloud-Eureka-Server7002 module, same as 7001. Introduce the POM files into the corresponding dependencies.

Create the Eureka cluster

Eureka-instance-hostname for 7001 and 7002 needs to be modified. Find the C:\Windows\System32\drivers\etc\hosts file.

Add a configuration using an administrator.

127.0.0.1 eureka7001.com
127.0.0.1 eureka7002.com
Copy the code

Yaml modified configuration, module 7001:

server:
  port: 7001

eureka:
  instance:
    hostname: eureka7001.com # Eureka server instance name
  client:
    #false: do not register yourself with the registry.
    register-with-eureka: false
    #false indicates that my end is the registry and my responsibility is to maintain the service instance, not to retrieve the service
    fetch-registry: false
    service-url:
      This address is used by the Eureka server.
      defaultZone: http://eureka7002.com:7002/eureka/
Copy the code

7002 module:

server:
  port: 7002

eureka:
  instance:
    hostname: eureka7002.com
  client:
    register-with-eureka: false
    fetch-registry: false
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/
Copy the code

7002 Build main startup class:

@SpringBootApplication
@EnableEurekaServer
public class EurekaMain7002 {
    public static void main(String[] args) { SpringApplication.run(EurekaMain7002.class,args); }}Copy the code

Start the test.

Testing:

  • localhost:7001
  • localhost:7002
  • eureka7001:7001
  • eureka7002:7002

Found no problem.

The payment and order modules join the cluster

Module 8001 YAML needs to be modified:

# Used to be a single point Eureka
#defaultZone: http://localhost:7001/eureka

# Now it's cluster, both eurekas need to register
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
Copy the code

Same for port 80:

#defaultZone: http://localhost:7001/eureka
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
Copy the code

Start the test.

Localhost/consumer/payment/get / 1 = = = > test successfully.

3. Set up payment service provider cluster

What this means is that if Eureka doesn’t create the cluster, if Eureka has a single point of failure, the program will crash. Similarly, service providers may also fail. If a server fails and no one is left to handle it, it will also fail. In this case, create a cluster for the provider to avoid a single point of failure.

Creating a new order module (Cloud-provider-Payment8002)

As with 8001, create and paste POM files, as well as the code of each layer (DAO, Service, controller) can be pasted.

The port number of the YAML file should be changed to 8002.

Modify the configuration

You can modify the configuration of the 8001 and 8002 payment modules to see who handles it. The Controller layer adds serverPort, which can be obtained directly from YAML. When you output it, you can see who did it.

@RestController
@Slf4j
public class PaymentController {
    @Resource
    private PaymentService paymentService;

    @Value("${server.port}")
    private String serverPort;

    @PostMapping(value = "/payment/create")
    public CommonResult<Payment> create(@RequestBody Payment payment){
        int result = paymentService.create(payment);
        log.info([insert result] :{},result);
        if (result > 0) {return new CommonResult(200."Database inserted successfully,serverPort=" + serverPort,result);
        }else{
            return new CommonResult(444."Failed to insert database".null); }}@GetMapping(value = "/payment/get/{id}")
    public CommonResult getPaymentById(@PathVariable("id") Long id){
        Payment payment = paymentService.getPaymentById(id);
        log.info("[Query result] :{}",payment);
        if(payment ! =null) {return new CommonResult(200."Database query succeeded,serverPort=" + serverPort,payment);
        }else{
            return new CommonResult(444."There's no record... Where id = "; + id,null); }}}Copy the code

To start, see the registry:

Port 7001, registered with 7002, has 1 order-service and 2 Payment-service. Same thing with 7002.

Test: localhost/consumer/payment/get / 1, the findings are also 8001 port processing logic.

This is because the consumption module calls the payment module, but the consumption module line contains the port number to access:

public static final String PAYMENT_URL = "http://localhost:8001";
Copy the code

The code needs to be modified so that both payment modules can work together.

Cloud-payment-service is the name of the PAYMENT SERVICE. In this way, we can find two ports 8001,8002 according to the SERVICE name instead of the port number. Modification:

public static final String PAYMENT_URL = "http://CLOUD-PAYMENT-SERVICE";
Copy the code

In addition, the load balancing function of the RestTemplate must be enabled.

@Configuration
public class ApplicationContextConfig {
    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate(a){
        return newRestTemplate(); }}Copy the code

This restarts the test and finds ports 8001 and 8002 polling.

Other operations

1. Delete the host name

Once again, we found that the name of the host was exposed at the back of the registry. We don’t want to expose this information.

Add one more line at the end of YAML so that the test is displayed with its configured name.

server:
  port: 8001

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

mybatis:
  mapperLocations: classpath:mapper/*.xml
  type-aliases-package: com.atguigu.springcloud.entities    Package for all Entity alias classes

eureka:
  client:
    # indicates to register with eurekaServer server
    register-with-eureka: true
    The default value is true. Clusters must be set to true to work with the ribbon to ensure load balancing
    fetch-registry: true
    service-url:
      #defaultZone: http://localhost:7001/eureka
      defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
  instance:
    instance-id: payment8001
Copy the code

If the other two services do not fail, restart the test for both.

2. Access path Displays the IP address

Add prefer-ip-address: true to the configuration.

instance:
  instance-id: payment8002
  prefer-ip-address: true
Copy the code

Once configured, place your mouse over Payment8002 to see the IP address displayed below.

3. Service Discovery

You want services registered with Eureka to display some information that can be configured in this way.

We need to introduce the DiscoveryClient class to help us. Introduced in the PaymentController layer.

@Resource
private DiscoveryClient discoveryClient;
Copy the code

Note that there are two DiscoveryClients, introduce this:

import org.springframework.cloud.client.discovery.DiscoveryClient;
Copy the code

If you introduce it wrong, the method won’t come in.

@GetMapping(value = "/payment/discovery")
public Object discovery(a){
    List<String> services = discoveryClient.getServices();
    for (String service:services){
        log.info(【 contents 】service:{},service);
    }

    List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
    for (ServiceInstance instance :instances){
        log.info(instance.getInstanceId() + 
                 "\t" + instance.getHost() + "\t" + instance.getPort() + "\t" + instance.getUri());
    }
    return this.discoveryClient;
}
Copy the code

Annotate @enableDiscoveryClient on the main startup class:

@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
public class PaymentMain8001 {
    public static void main(String[] args) { SpringApplication.run(PaymentMain8001.class,args); }}Copy the code

Test, website:

Background:

4. Eureka’s self-protection mechanism

In the early days, entering the Eureka registry might result in a red:

EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY’RE NOT. RENEWALS ARE LESSER THANTHRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUSTTO BE SAFE

That’s going into protected mode.

Protection mode function

It is used to protect a group of clients and the Eureka Server when network partitions exist. Once in protected mode, Eureka Server will attempt to protect the information in its service registry and will not delete the data in the service registry, that is, will not unregister any microservices.

In other words, Eureka will not immediately clean up a microservice when it becomes unavailable, but will still save the information of the microservice. Belongs to the AP branch in CAP.

What is self-protection mode?

By default, EurekaServer will log out of a microservice instance if it does not receive a heartbeat for a certain amount of time (90 seconds by default). However, when a partition failure occurs (delay, lag, congestion) and the microservice cannot communicate with EurekaServer properly, this behavior can become very dangerous — the microservice itself is actually healthy and should not be logged out. Eureka solves this problem by going into “self-protected mode” — when the EurekaServer node loses too many clients in a short period of time (possibly due to a network partition failure), the node goes into self-protected mode.

Self-protection mechanism

Self-protection mechanism: By default, EurekaClient periodically sends heartbeat packets to the EurekaServer

If Eureka does not receive a heartbeat packet from EurekaClient within a certain period of time (90 seconds by default), the service will be removed from the service registration list. However, a large number of heartbeat instances of EurekaClient will be lost within a short period (90 seconds). At this time, Eurekaserver will turn on the self-protection mechanism and will not remove the service (this phenomenon may occur if the network is disconnected but EurekaClient is down, then if you change to another registry, if there is no heartbeat within a certain period of time, the service will be removed, so there is a serious error. Because the client can still send heartbeat normally, it is just a network delay problem, and the protection mechanism is created to solve this problem).

How do I turn off self-protection mode

  • Yaml Settings of module 7001:eureka.server.enable-self-preservation = false
eureka:
  .
  server:
    # Turn off the self-protection mechanism to ensure that unavailable services are kicked out in time
    enable-self-preservation: false
    eviction-interval-timer-in-ms: 2000
Copy the code

The following red indicates that self-protection mode has been turned off.

  • 8001 module
instance:
    instance-id: payment8001
    prefer-ip-address: true
    Heartbeat detection and renewal time
    Make sure the registry can remove the service even after the service is closed
    #Eureka Interval in seconds for the client to send heartbeat to the server (default is 30 seconds)
    lease-renewal-interval-in-seconds: 1
    #Eureka Server waiting time limit after receiving the last heartbeat, in seconds (default is 90 seconds)
    lease-expiration-duration-in-seconds: 2
Copy the code

Now it is sent once in 1ms, and will be removed if timeout occurs. Therefore, port 8001 is closed, and the registry detects that 8001 has no heartbeat, so it will be directly removed and will not be retained.