SpringCloud (Chapter 5~9): Eureka service registration and discovery, Zookeeper service registration and discovery, Consul service registration and discovery, Ribbon load balancing service call, OpenFeign service interface call

5. Eureka service registration and discovery

5.1 Outline diagram

Insert image description here

5.2 Basic knowledge of Eureka

  • Question : Why do we need to use the service registration center? Can't we just use the 80 consumer to call the 8081 generator directly? ? ?
  • Answer : There is no problem with calling a single consumer. If there are many consumers, they need to be managed uniformly.
  • For example : A patient goes to a private hospital for one-to-one expert service without having to register with an outpatient clinic in the middle. If there are many patients, can this microservice still be provided? Does this expert still have an account? How many patients have passed this expert account today? We need to monitor the permission flow control, etc. At this time, the hospital needs to have a Outpatient as a Service Registry.

5.2.1 What is service governance

  • Spring Cloud encapsulates the Eureka module developed by Netflix to implement service governance

  • In the traditional RPC remote calling framework, it is more complicated to manage the dependencies between each service and the management. Therefore, service governance is needed to manage the dependencies between services, which can achieve service invocation, load balancing, and fault tolerance. etc., to realize service discovery and registration.

5.2.2 What is service registration

  • Eureka adopts the CS design architecture. Eureka Sever serves as the server for the service registration function. It is the service registration center. Other microservices in the system use Eureka clients to connect to Eureka Server and maintain heartbeat connections. In this way, system maintenance personnel can use Eureka Server to monitor whether each microservice in the system is running normally .

  • In service registration and discovery, there is a registration center. When the server starts, it will register the current server information such as service address, communication address, etc. to the registration center in an alias manner . The other party (consumer service provider) uses the alias to obtain the actual service communication address from the registration center, and then implements local RPC calls. The core design idea of ​​the RPC remote calling framework: lies in the registration center, because it is managed by the registration center. A dependency relationship between each service (service governance concept) . In any RPC remote framework, there will be a registration center to store service address related information (interface address)

Insert image description here

5.2.3 Eureka two components

1) Eureka Server provides service registration service

  • After each microservice node is started through configuration, it will be registered in EurekaServer. In this way, the service registry in EurekaServer will store the information of all available service nodes. The information of the service nodes can be intuitively seen in the interface.
  • eg: Pay money to the property company and fill in the basic information of the community.

2) EurekaClient accesses through the registration center

  • It is a Java client used to simplify the interaction with Eureka Server. The client also has a built-in load balancer that uses a round-robin load algorithm. After the application starts, a heartbeat will be sent to Eureka Server (default period is 30 seconds). If Eureka Server does not receive the heartbeat of a node within multiple heartbeat cycles, EurekaServer will remove the service node from the service registry (90 seconds by default)
  • eg: The property management company will not provide services to the community until it receives the money. If it does not receive subsequent money within a few months, it will no longer provide services to the community.

5.3 Single-machine Eureka construction steps

5.3.1 Current system architecture

  • A consumer, a producer, a public project, and a service registry.
    Insert image description here

5.3.2 IDEA generates eurekaServer service registration center

  • Similar property companies

1)建Module:cloud-eureka-server7001

Insert image description here

2) Change POM

  • Comparative explanation of Springcloud Season 1 and Season 2 (this video)
<!-- eureka新旧版本 -->
<!-- 以前的老版本(2018)-->
<dependency>
    <groupid>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>

<!-- 现在新版本(2020.2)--><!-- 我们使用最新的 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>

  • Write a complete pom.xml file: This is a new project, so all dependencies must be added.
    Insert image description here
<?xml version="1.0" encoding="UTF-8"?>
<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>cloud2020</artifactId>
        <groupId>com.angenin.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-eureka-server7001</artifactId>

    <dependencies>
        <!-- eureka-server -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
        <!-- 引用自己定义的api通用包,可以使用Payment支付Entity -->
        <dependency>
            <groupId>com.angenin.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        <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>
        <!-- 一般通用配置 -->
        <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>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>


</project>

4) Write YML

  • Create a new application.yml file in the resources directory
    Insert image description here
server:
  port: 7001

eureka:
  instance:
    hostname: localhost  #eureka服务端的实例名称
  client:
    #false表示不向注册中心注册自己(想注册也可以,不过没必要)
    register-with-eureka: false
    #false表示自己端就是注册中心,职责就是维护服务实例,并不需要去检索服务
    fetch-registry: false
    service-url:
      #设置与eurekaServer交互的地址查询服务和注册服务都需要依赖这个地址,就是上面配置的eureka服务端的实例名称和端口号
      defaultZone: http://${
    
    eureka.instance.hostname}:${
    
    server.port}/eureka/

5) Main startup

  • Create new com.angenin.springcloud.EurekaMain7001 under the java package
  • This project is used for registration in the service registration center, so there is no need to write a business class.
    Insert image description here
package com.angenin.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;


@SpringBootApplication
@EnableEurekaServer   // 表示它是服务注册中心
public class EurekaMain7001 {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(EurekaMain7001.class, args);
    }
}


6) Test

  • Start this project and enter http://localhost:7001/ in the browser
    Insert image description here

5.3.3 EurekaClient: Register 8001 to the registration center

  • EurekaClient cloud-provider-payment8001 will be registered in EurekaServer and become a service provider , similar to Shang Silicon Valley School's external teaching services

1) Modify the 8001 payment module project

  • The provider here is still the cloud-provider-payment8001 module created before, with the following modifications:

2) Modify POM

Comparative explanation of Springcloud Season 1 and Season 2 (this video)

<!--以前老版本,别再使用-->
<!-- 以前的老版本(2018)-->
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-eureka</artifactId>
<dependency>


<!--现在新版本,当前使用-->
<!-- 现在新版本(2020.2)--><!-- 我们使用最新的 -->
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<dependency>

  • Complete pom file: This is the 8001 project dependency that has been added before modification, so you only need to add the eureka-client dependency here.
    Insert image description here
<?xml version="1.0" encoding="UTF-8"?>
<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>cloud2020</artifactId>
        <groupId>com.angenin.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-provider-payment8001</artifactId>



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

        <!-- 引用自己定义的api通用包,可以使用Payment支付Entity -->
        <dependency>
            <groupId>com.angenin.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        <!--web场景启动依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--boot指标监控依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <!--子工程写了版本号,就使用子工程的版本号,如果没写版本,找父工程中规定的版本号-->
            <version>1.1.20</version>
        </dependency>
        <!--mysql-connector-java-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!--jdbc-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <!--热部署-->
        <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>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>

3) Modify YML

Insert image description here

#微服务建议一定要写服务端口号和微服务名称
server:
  #端口号
  port: 8001

spring:
  application:
    #微服务名称,将此服务项目入住到注册中心,那么就需要给此项目取个名字
    name: cloud-payment-service
  #数据库配置
  datasource:
    #引入的数据库驱动类型
    type: com.alibaba.druid.pool.DruidDataSource
    #mysql5.x的没有cj
    driver-class-name: com.mysql.jdbc.Driver
    #记得先创建数据库
    url: jdbc:mysql://localhost:3306/db2020?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: root

eureka:
  client:
    #true表示向注册中心注册自己,默认为true
    register-with-eureka: true
    #是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
    fetch-registry: true
    service-url: #入住到哪个主机上面的哪个端口,即设置与 Eureka Server 交互的地址
      defaultZone: http://localhost:7001/eureka


#mybatis配置
mybatis:
  mapper-locations: classpath:mapper/*.xml #mapper.xml文件的位置
  type-aliases-package: com.angenin.springcloud.entities  #所有Entity别名类所在包(所有实体类所在的包)

4) Modify the main startup class

Insert image description here

package com.angenin.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@EnableEurekaClient //表示这个项目是eureka的客户端。
@SpringBootApplication
public class PaymentMain8001 {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(PaymentMain8001.class, args);
    }
}

5) Test

  • First start the EurekaServer registration center, and then start the 8001 producer
  • You can see that the 8001 project was successfully registered in the registration center.
    Insert image description here

6) Microservice registration name configuration instructions

  • In the yml file application.name (8001) is the application name (7001) when registered in the registration center.
    Insert image description here

7) Self-protection mechanism

  • Detailed explanation later
    Insert image description here

5.3.4 EurekaClient: Register 80 to the registration center

  • EurekaClient cloud-consumer-order80 will register into EurekaServer and become a service consumer, similar to the students who come to Shang Silicon Valley for class consumption.

1) Modify the 80 consumer order module

  • The consumer here is still the cloud-consumer-order80 module created before, with the following modifications:

2) Modify pom

Insert image description here

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

3) Modify yml

Insert image description here

#访问一个网站时,默认是80端口,给用户80端口,用户就可以不用加端口直接访问页面
server:
  port: 80


spring:
  application:  
    name: cloud-order-service

eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://localhost:7001/eureka

4) Modify the main startup class

Insert image description here

package com.angenin.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

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

5) Test

  • First start EurekaServer, 7001 service
  • Then start the service provider provider, 8001 service
    Insert image description here
  • Test query: http://localhost/consumer/payment/get/4, the query can still be successful.
    Insert image description here

5.4 Cluster Eureka construction steps

5.4.1 Eureka cluster principle description

Insert image description here

  • Question : What is the core of microservice RPC remote service invocation?
    • High availability , imagine that you have only one registration center. If it fails, it will be a disaster ( ̄▽ ̄)", which will cause the entire service environment to be unavailable.
  • Solution : Build an Eureka registration center cluster to achieve load balancing + fault tolerance
  • Understand the Eureka cluster yourself: register with each other and watch each other
    Insert image description here

5.4.2 EurekaServer cluster environment construction steps

1)建Module:cloud-eureka-server7002

Insert image description here

2) Write POM

Insert image description here

<?xml version="1.0" encoding="UTF-8"?>
<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>cloud2020</artifactId>
        <groupId>com.angenin.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-eureka-server7002</artifactId>

    <dependencies>
        <!-- eureka-server -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
        <!-- 引用自己定义的api通用包,可以使用Payment支付Entity -->
        <dependency>
            <groupId>com.angenin.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        <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>
        <!-- 一般通用配置 -->
        <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>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>

3) Modify mapping configuration hosts

  • Now there are two machines (Eureka). Each machine needs to configure the host name of its own server in the configuration file. Because it is local, it is called localhost. At this time, the two machines are configured with localhost, so the duplicate names cannot be distinguished, so they need to pass Modify the hosts file to differentiate so that 127.0.0.1 is mapped to two different domain names.
  • Because the real physical machine now only has one laptop, we use different port numbers to map the same address. 7001 simulates machine No. 1, and 7002 simulates machine No. 2.
    Insert image description here
    Insert image description here
#Eureka集群配置
127.0.0.1  eureka7001.com
127.0.0.1  eureka7002.com

4) Write YML (previously stand-alone)

Previous stand-alone configuration form:

  • Instance name of eureka server: localhost is written
  • Address: Write the IP and port number set in your project configuration file.
    Insert image description here
server:
  port: 7001

eureka:
  instance:
    hostname: localhost  #eureka服务端的实例名称
  client:
    #false表示不向注册中心注册自己(想注册也可以,不过没必要)
    register-with-eureka: false
    #false表示自己端就是注册中心,职责就是维护服务实例,并不需要去检索服务
    fetch-registry: false
    service-url:
      #设置与eurekaServer交互的地址查询服务和注册服务都需要依赖这个地址,就是上面配置的eureka服务端的实例名称和端口号
      defaultZone: http://${
    
    eureka.instance.hostname}:${
    
    server.port}/eureka/

Now both cluster configuration methods need to be modified: mutual registration

  • The instance name of the eureka server: it is written to distinguish between two different domain names set in the hosts file.

  • Address: Write the IP and port number set in another project configuration file.

  • Modify the first Eureka configuration file of the cluster
    Insert image description here

server:
  port: 7001

eureka:
  instance:
    hostname: eureka7001.com  #eureka服务端的实例名称
  client:
    #false表示不向注册中心注册自己(想注册也可以,不过没必要)
    register-with-eureka: false
    #false表示自己端就是注册中心,职责就是维护服务实例,并不需要去检索服务
    fetch-registry: false
    service-url:
      #设置与eurekaServer交互的地址查询服务和注册服务都需要依赖这个地址,就是上面配置的eureka服务端的实例名称和端口号
      defaultZone: http://eureka7002.com:7002/eureka/

  • Modify the second Eureka configuration file of the cluster
server:
  port: 7002

eureka:
  instance:
    hostname: eureka7002.com  #eureka服务端的实例名称
  client:
    #false表示不向注册中心注册自己(想注册也可以,不过没必要)
    register-with-eureka: false
    #false表示自己端就是注册中心,职责就是维护服务实例,并不需要去检索服务
    fetch-registry: false
    service-url:
      #设置与eurekaServer交互的地址查询服务和注册服务都需要依赖这个地址,就是上面配置的eureka服务端的实例名称和端口号
      defaultZone:  http://eureka7001.com:7001/eureka/

5) Main startup

  • Add the main startup class of 7002
    Insert image description here
package com.angenin.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@SpringBootApplication
@EnableEurekaServer   // 表示它是服务注册中心
public class EurekaMain7002 {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(EurekaMain7002.class, args);
    }
}

6) Test

  • http://eureka7001.com:7001, access the first station and find that 1 points to 2
    Insert image description here

  • http://eureka7002.com:7002, access the second station and find that 2 points to 1.
    Insert image description here

5.4.3 Publish the payment service 8001 microservice to the above two Eureka cluster configurations

Modify yml configuration file

  • Previous stand-alone version
    Insert image description here
  • Now the cluster version
    Insert image description here
#微服务建议一定要写服务端口号和微服务名称
server:
  #端口号
  port: 8001

spring:
  application:
    #微服务名称,将此服务项目入住到注册中心,那么就需要给此项目取个名字
    name: cloud-payment-service
  #数据库配置
  datasource:
    #引入的数据库驱动类型
    type: com.alibaba.druid.pool.DruidDataSource
    #mysql5.x的没有cj
    driver-class-name: com.mysql.jdbc.Driver
    #记得先创建数据库
    url: jdbc:mysql://localhost:3306/db2020?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: root

eureka:
  client:
    #true表示向注册中心注册自己,默认为true
    register-with-eureka: true
    #是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
    fetch-registry: true
    service-url: #入住到哪个主机上面的哪个端口,即设置与 Eureka Server 交互的地址
     #defaultZone: http://localhost:7001/eureka     #单机版
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/  # 集群版


#mybatis配置
mybatis:
  mapper-locations: classpath:mapper/*.xml #mapper.xml文件的位置
  type-aliases-package: com.angenin.springcloud.entities  #所有Entity别名类所在包(所有实体类所在的包)

5.4.4 Publish the order service 80 microservice to the above two Eureka cluster configurations

Modify yml configuration file

  • Previous stand-alone version
    Insert image description here

  • Now the cluster version
    Insert image description here

#访问一个网站时,默认是80端口,给用户80端口,用户就可以不用加端口直接访问页面
server:
  port: 80


spring:
  application:
    name: cloud-order-service

eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      #defaultZone: http://localhost:7001/eureka #单机版
      defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka  # 集群版

5.4.5 Test 01

  • First start EurekaServer, 7001/7002 service

  • To start the service provider provider again, 8001

  • To activate consumers again, 80

  • http://eureka7001.com:7001, the discovery service is registered to the cluster
    Insert image description here

  • http://eureka7002.com:7002, also found that registered to the cluster
    Insert image description here

  • http://localhost/consumer/payment/get/4,search successful.
    Insert image description here

  • The completed architecture now:

    • A cluster composed of two registration centers registers with each other. The producer calls the consumer and publishes services to the registration center.
      Insert image description here

5.4.6 Payment service provider 8001 cluster environment construction

  • That is: add the second producer project, content and the first 8001Insert image description here

1) Create new cloud-provider-payment8002

Insert image description here

2) Change POM

  • The added dependencies are consistent with 8001
    Insert image description here
<?xml version="1.0" encoding="UTF-8"?>
<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>cloud2020</artifactId>
        <groupId>com.angenin.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-provider-payment8002</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

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

        <!-- 引用自己定义的api通用包,可以使用Payment支付Entity -->
        <dependency>
            <groupId>com.angenin.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        <!--web场景启动依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--boot指标监控依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <!--子工程写了版本号,就使用子工程的版本号,如果没写版本,找父工程中规定的版本号-->
            <version>1.1.20</version>
        </dependency>
        <!--mysql-connector-java-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!--jdbc-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <!--热部署-->
        <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>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>


</project>

3) Write YML

  • Copy the yml file of 8001 and modify the port number to 8002
    Insert image description here
#微服务建议一定要写服务端口号和微服务名称
server:
  #端口号
  port: 8002

spring:
  application:
    #微服务名称,将此服务项目入住到注册中心,那么就需要给此项目取个名字
    name: cloud-payment-service
  #数据库配置
  datasource:
    #引入的数据库驱动类型
    type: com.alibaba.druid.pool.DruidDataSource
    #mysql5.x的没有cj
    driver-class-name: com.mysql.jdbc.Driver
    #记得先创建数据库
    url: jdbc:mysql://localhost:3306/db2020?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: root

eureka:
  client:
    #true表示向注册中心注册自己,默认为true
    register-with-eureka: true
    #是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
    fetch-registry: true
    service-url: #入住到哪个主机上面的哪个端口,即设置与 Eureka Server 交互的地址
     #defaultZone: http://localhost:7001/eureka     #单机版
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/  # 集群版


#mybatis配置
mybatis:
  mapper-locations: classpath:mapper/*.xml #mapper.xml文件的位置
  type-aliases-package: com.angenin.springcloud.entities  #所有Entity别名类所在包(所有实体类所在的包)

4) Main startup

Insert image description here

package com.angenin.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@EnableEurekaClient //表示这个项目是eureka的客户端。
@SpringBootApplication
public class PaymentMain8002 {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(PaymentMain8002.class, args);
    }
}

5) Business category

  • Copy the business classes of 8001: controller, service, Dao, mapper
    Insert image description here
  • Copied directory
    Insert image description here

6) Modify the Controller of 8001/8002

  • Because it is now a cluster composed of two producers, the names exposed to the outside world are the same.
    Insert image description here
  • So which one of the producer cluster services (8001, 8002) does consumer 80 call? ? ?
    • You can use the @value annotation to inject the port number of the configuration file into the code and print it out, so that you can know which producer is being used based on the port number when calling.
    • Both producer control layers need to be modified.
      Insert image description here
      Insert image description here
package com.angenin.springcloud.controller;

import com.angenin.springcloud.entities.CommonResult;
import com.angenin.springcloud.entities.Payment;
import com.angenin.springcloud.service.PaymentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;

@RestController
@Slf4j  //日志
public class PaymentController {
    
    

    @Resource
    private PaymentService paymentService;

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

    //前后端分离,所以不能直接返回对象,数据要先经过CommonResult封装再返回
    @PostMapping("/payment/create")
    public CommonResult<Payment> create(@RequestBody Payment payment){
    
    
        int result = paymentService.create(payment);
        log.info("******插入的数据为:" + payment);
        log.info("******插入结果:" + result);


        if(result > 0){
    
    
            //插入成功
            return new CommonResult(200, "插入数据库成功,serverPort:"+serverPort, result);
        }else{
    
    
            return new CommonResult(444, "插入数据库失败,serverPort:"+serverPort,null);

        }
    }


    @GetMapping("/payment/get/{id}")
    public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id){
    
    
        Payment payment = paymentService.getPaymentById(id);
        log.info("******查询结果:" + payment);

        if(payment != null){
    
    
            //查询成功
            return new CommonResult(200, "查询成功,serverPort:"+serverPort, payment);
        }else{
    
    
            return new CommonResult(444, "没有对应记录,查询ID:" + id,null);
        }
    }

}

7) Test

  • Start 7001 and 7002 first
  • On startup 8001/8002
  • Finally activate the 80
    effect
  • Access the Eureka management page of 2 machines ( http://eureka7001.com:7001/、http://eureka7002.com:7002/)
    Insert image description here
    Insert image description here
  • By calling the producer cluster through consumer 80, you can see that every call is made to producer 8001. We thought that the url address was hard-coded in the control layer code in consumer 80. ( http://localhost/consumer/payment/get/4)
    Insert image description here
    Insert image description here
  • Solution: The stand-alone version writes the URL address, but now the cluster exposes a unified service name, so the URL needs to be changed to the service name of the cluster.
    Insert image description here
  • That is: the service name previously set in the configuration file
    Insert image description here
    Insert image description here
    Insert image description here
package com.angenin.springcloud.controller;

import com.angenin.springcloud.entities.CommonResult;
import com.angenin.springcloud.entities.Payment;
import lombok.extern.slf4j.Slf4j;
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;

@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;

    //因为浏览器只支持get请求,为了方便这里就用get
    @GetMapping("/consumer/payment/create")
    public CommonResult<Payment> create(Payment payment){
    
    
        log.info("********插入的数据:" + payment);
        //postForObject分别有三个参数:请求地址,请求参数,返回的对象类型----写操作
        return restTemplate.postForObject(PAYMENT_URL + "/payment/create", payment, CommonResult.class);
    }

    @GetMapping("/consumer/payment/get/{id}")
    public CommonResult<Payment> getPayment(@PathVariable("id") Long id){
    
    
        log.info("********查询的id:" + id);
        //getForObject两个参数:请求地址,返回的对象类型----读操作
        return restTemplate.getForObject(PAYMENT_URL + "/payment/get/" + id, CommonResult.class);
    }
}


  • Restart 80 and test again:http://localhost/consumer/payment/get/4
    Insert image description here
  • An exception will appear as a result. The reason is that the producer cluster is now exposing the microservice name to the outside world, but it cannot identify which specific producer under the cluster is using the service.
    Insert image description here
  • Solution: Use the @LoadBalanced annotation to give RestTemplate the ability to load balance
    • View 5.4.7 Load Balancing

5.4.7 Load balancing

Insert image description here

package com.angenin.springcloud.config;

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class ApplicationContextConfig {
    
    

    //往容器中添加一个RestTemplate
    //RestTemplate提供了多种便捷访问远程http访问的方法
    @Bean
    @LoadBalanced //使用@LoadBalanced注解赋予RestTemplate负载均衡的能力
    public RestTemplate restTemplate(){
    
    
        return new RestTemplate();
    }

}

5.4.8 Test 02

  • Because 80 has been modified, we need to restart and visit again.http://localhost/consumer/payment/get/4
  • Effect: Every time it is refreshed, 8001 and 8002 will switch.
  • Note: The default load balancing is the polling mechanism.Insert image description hereInsert image description here
  • Let me talk about this in advance, which is what I will talk about later. Ribbon’s load balancing function defaults to polling.
  • After the integration of Ribbon and Eureka, the Consumer can directly call the service without having to worry about the address and port number, and the service also has a load function.

5.4.9 Architecture diagram so far

  • A cluster composed of 2 registration centers registers with each other
  • A cluster composed of 2 producers and registered in the registration center
  • 1 consumer has registered in the registration center.
  • Consumer 80 calls the cluster composed of producers 8001 and 8002.
    Insert image description here

5.5 Actuator microservice information is improved

  • Can be paired with or without, recommended.

5.5.1 Host name: Service name modification

1) Current issues

  • Contains the host name. According to the requirements of the specification, only the service name is exposed, and the host name is not included.
    Insert image description here

2) Modify cloud-provider-payment8001/8002

Insert image description here
Insert image description here

#微服务建议一定要写服务端口号和微服务名称
server:
  #端口号
  port: 8001

spring:
  application:
    #微服务名称,将此服务项目入住到注册中心,那么就需要给此项目取个名字
    name: cloud-payment-service
  #数据库配置
  datasource:
    #引入的数据库驱动类型
    type: com.alibaba.druid.pool.DruidDataSource
    #mysql5.x的没有cj
    driver-class-name: com.mysql.jdbc.Driver
    #记得先创建数据库
    url: jdbc:mysql://localhost:3306/db2020?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: root

eureka:
  client:
    #true表示向注册中心注册自己,默认为true
    register-with-eureka: true
    #是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
    fetch-registry: true
    service-url: #入住到哪个主机上面的哪个端口,即设置与 Eureka Server 交互的地址
     #defaultZone: http://localhost:7001/eureka     #单机版
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/  # 集群版
  instance: #重点,和client平行
    instance-id: payment8001 # 每个提供者的id不同,显示的不再是默认的项目名



#mybatis配置
mybatis:
  mapper-locations: classpath:mapper/*.xml #mapper.xml文件的位置
  type-aliases-package: com.angenin.springcloud.entities  #所有Entity别名类所在包(所有实体类所在的包)

3) After modification

  • Restart 8001,8002 ( http://eureka7001.com:7001/)
    Insert image description here

5.5.2 Access information has IP information prompts

1) Current issues

  • Click the link, there is no IP address prompt in the lower left corner

  • 新版本的默认带ip显示
    Insert image description here
    Insert image description here

  • Note: After importing these two dependencies, the effect will only be effective if the IP is perfected.
    Insert image description here

2) Modify cloud-provider-payment8001/8002

Insert image description here


  instance: #重点,和client平行
    instance-id: payment8001 # 每个提供者的id不同,显示的不再是默认的项目名
    prefer-ip-address: true   #访问路径可以显示ip地址


3) After modification

Insert image description here

5.6 Service DiscoveryDiscovery

  • For microservices registered in eureka, information about the service can be obtained through service discovery.
  • That is: get the information of these microservices successfully registered in eureka, such as host name, port number...

5.6.1 Modify the Controller of cloud-provider-payment8001

  • Take 8001 as an example. The method of 8002 is the same and will not be modified here.
    Insert image description here
package com.angenin.springcloud.controller;

import com.angenin.springcloud.entities.CommonResult;
import com.angenin.springcloud.entities.Payment;
import com.angenin.springcloud.service.PaymentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.List;

@RestController
@Slf4j  //日志
public class PaymentController {
    
    

    @Resource
    private PaymentService paymentService;

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

    @Resource
    private DiscoveryClient discoveryClient;	//springframework的DiscoveryClient(不要导错包了)

    @GetMapping("/payment/discovery")
    public Object discovery(){
    
    
        //获取服务列表的信息(即:在Eureka中注册过登录好的微服务有哪些,显示所有注册过的微服务名称)
        List<String> services = discoveryClient.getServices();
        for (String element : services) {
    
    
            log.info("*******element:" + element);
        }

        // 根据微服务的名称进一步获得该微服务的信息
        List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
        for (ServiceInstance instance : instances) {
    
    
            //getServiceId服务器id getHost主机名称 getPort端口号  getUri地址
            log.info(instance.getServiceId() + "\t" + instance.getHost() + "\t" + instance.getPort() + "\t" + instance.getUri());
        }

        return this.discoveryClient;
    }



    //前后端分离,所以不能直接返回对象,数据要先经过CommonResult封装再返回
    @PostMapping("/payment/create")
    public CommonResult<Payment> create(@RequestBody Payment payment){
    
    
        int result = paymentService.create(payment);
        log.info("******插入的数据为:" + payment);
        log.info("******插入结果:" + result);


        if(result > 0){
    
    
            //插入成功
            return new CommonResult(200, "插入数据库成功,serverPort:"+serverPort, result);
        }else{
    
    
            return new CommonResult(444, "插入数据库失败,serverPort:"+serverPort,null);

        }
    }


    @GetMapping("/payment/get/{id}")
    public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id){
    
    
        Payment payment = paymentService.getPaymentById(id);
        log.info("******查询结果:" + payment);

        if(payment != null){
    
    
            //查询成功
            return new CommonResult(200, "查询成功,serverPort:"+serverPort, payment);
        }else{
    
    
            return new CommonResult(444, "没有对应记录,查询ID:" + id,null);
        }
    }

}

5.6.2 8001 main startup class

Insert image description here

package com.angenin.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@EnableEurekaClient //表示这个项目是eureka的客户端。
@SpringBootApplication
@EnableDiscoveryClient  //启用发现客户端-后续详解
public class PaymentMain8001 {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(PaymentMain8001.class, args);
    }
}

5.6.3 Self-test

  • First start EurekaServer

  • Start the 8001 main startup class again, it will take a while.

  • http://localhost:8001/payment/discovery
    Insert image description here
    Insert image description here

  • Now is the self-test: Consumer 8001 accesses its own IP address. If you want consumer access on the client 80, you only need to expose this service interface address to the outside world. Then 80 can obtain various microservices through such access address. information. ( don’t quite understand )
    Insert image description here

5.7 Eureka self-protection

5.7.1 Fault phenomenon

Overview :

  • Protection mode is mainly used for protection in scenarios where there is a network partition between a group of clients and Eureka Server. Once in protected mode,Eureka Server将会尝试保护其服务注册表中的信息,不再删除服务注册表中的数据,也就是不会注销任何微服务。
  • If you see the following prompt on the homepage of Eureka Server, it means that Eureka has entered protection mode:
    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
    Insert image description here

5.7.2 Causes

  • Why is the Eureka self-protection mechanism produced?

    • In order to prevent EurekaClient from running normally but the network is blocked from EurekaServer, EurekaServer will not immediately remove the EurekaClient service.
  • What is self-protection mode?

    • By default, if EurekaServer does not receive the heartbeat of a microservice instance within a certain period of time, EurekaServer will log out of the instance (90 seconds by default). But when a network partition failure occurs (delay, lag, congestion), the microservice and EurekaServer cannot communicate normally, and the above behavior may become very dangerous - because the microservice itself is actually healthy 此时本不应该注销这个微服务. Eureka solves this problem through "self-protection mode" - when the EurekaServer node loses too many clients in a short period of time (a network partition failure may occur), then this node will enter self-protection mode.
      Insert image description here
    • 在自我保护模式中,Eureka Server会保护服务注册表中的信息,不再注销任何服务实例。Its design philosophy is to rather retain erroneous service registration information than blindly log out any potentially healthy service instances.一句话讲解:好死不如赖活着
    • In summary, the self-protection mode is a security protection measure to deal with network anomalies. Its architectural philosophy is to rather retain all microservices at the same time (both healthy microservices and unhealthy microservices will be retained) than to blindly log off any healthy microservices. Using self-protection mode can make the Eureka cluster more robust and stable.
  • In a word: If a certain microservice is unavailable at a certain moment, Eureka will not clean it up immediately, but will still save the information of the microservice.

  • Belongs to the AP branch in CAP

5.7.3 How to prohibit self-protection

  • The default is on
  • Because the registration center and producers are now composed of clusters, it is troublesome to start many services every time it is restarted. Therefore, if you test here, you only need to modify 7001 and 8001 (similar to the stand-alone version). After that, you only need to start 7001 and 8001 for testing. This is faster.

1) Registration center eureakeServer side 7001

  • By factory default, the self-protection mechanism is enabled:eureka.server.enable-self-preservation=true
  • eureka.server.enable-self-preservation = falseSelf-protection mode can be disabled using
    Insert image description here
server:
  port: 7001

eureka:
  instance:
    hostname: eureka7001.com  #eureka服务端的实例名称
  client:
    #false表示不向注册中心注册自己(想注册也可以,不过没必要)
    register-with-eureka: false
    #false表示自己端就是注册中心,职责就是维护服务实例,并不需要去检索服务
    fetch-registry: false
    service-url:
      #设置与eurekaServer交互的地址查询服务和注册服务都需要依赖这个地址,就是上面配置的eureka服务端的实例名称和端口号
      #defaultZone: http://eureka7002.com:7002/eureka/   #集群模式
      defaultZone: http://eureka7001.com:7001/eureka/   #切换为单机模式,为了方便测试自我保护机制
  server:    #server与client对齐
    #关闭自我保护,默认为true
    enable-self-preservation: false
    #心跳的间隔时间,单位毫秒
    eviction-interval-timer-in-ms: 2000

  • Closing effect: (Start the 7001 registration center and access it http://eureka7001.com:7001/. Only 7001 is started at this time. The reason is mentioned above for the convenience of testing)
    Insert image description here

2) Producer client eureakeClient 8001

  • Configuration
    Insert image description here
#微服务建议一定要写服务端口号和微服务名称
server:
  #端口号
  port: 8001

spring:
  application:
    #微服务名称,将此服务项目入住到注册中心,那么就需要给此项目取个名字
    name: cloud-payment-service
  #数据库配置
  datasource:
    #引入的数据库驱动类型
    type: com.alibaba.druid.pool.DruidDataSource
    #mysql5.x的没有cj
    driver-class-name: com.mysql.jdbc.Driver
    #记得先创建数据库
    url: jdbc:mysql://localhost:3306/db2020?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: root

eureka:
  client:
    #true表示向注册中心注册自己,默认为true
    register-with-eureka: true
    #是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
    fetch-registry: true
    service-url: #入住到哪个主机上面的哪个端口,即设置与 Eureka Server 交互的地址
      defaultZone: http://localhost:7001/eureka     #单机版
      #defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/  # 集群版
  instance: #重点,和client平行
    instance-id: payment8001 #每个提供者的id不同,显示的不再是默认的项目名
    prefer-ip-address: true   #访问路径可以显示ip地址
    #心跳检测与续约时间
    #开发时没置小些,保证服务关闭后注册中心能即使剔除服务
    #Eureka客户端向服务端发送心跳的时间间隔,单位为秒(默认是30秒)
    lease-renewal-interval-in-seconds: 1
    #Eureka服务端在收到最后一次心跳后等待时间上限,单位为秒(默认是90秒),超时将剔除服务
    lease-expiration-duration-in-seconds: 2




#mybatis配置
mybatis:
  mapper-locations: classpath:mapper/*.xml #mapper.xml文件的位置
  type-aliases-package: com.angenin.springcloud.entities  #所有Entity别名类所在包(所有实体类所在的包)


3) Test

  • Both 7001 and 8001 are configured.

  • Start 7001 first and then 8001 ( http://eureka7001.com:7001/and find that the 8001 service is correctly injected into the 7001 registration center)
    Insert image description here

  • Closing 8001 means that the 8001 service is down, so it should be deleted from the registration center immediately.
    Insert image description here

6. Zookeeper service registration and discovery

6.1 What should you do if Eureka stops updating?

  • https://github.com/Netflix/eureka/wiki, check the official website
    Insert image description here

6.2 SpringCloud integrates Zookeeper to replace Eureka

  • The premise is that you have a clear understanding of Zookeeper that Brother Yang has talked about and successfully configured it on your Centos7 server (using virtual machine configuration).
    Insert image description here

6.2.1 Registration Center Zookeeper

  • Concept : zookeeper is a distributed coordination tool that can realize the registration center function

  • The zookeeper server replaces the Eureka server, and zk serves as the service registration center

  • Start the zookeeper server after turning off the Linux server firewall
    Insert image description here

# 关闭防火墙
systemctl stop firewalld.service

# 禁止防火墙开机启动
systemctl disable firewalld.service

# 查看防火墙状态
systemctl status  firewalld.service

# Zookeeper启动详情查看----Zookeeper基础操作 博客
  • Test whether the service pings successfully
    Insert image description here

6.2.2 Service Provider

1) Create new cloud-provider-payment8004

Insert image description here

2)POM

Insert image description here

<?xml version="1.0" encoding="UTF-8"?>
<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>cloud2020</artifactId>
        <groupId>com.angenin.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-provider-payment8004</artifactId>

    <dependencies>
        <!-- SpringBoot整合Web组件 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency><!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
            <groupId>com.angenin.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>

        <!-- SpringBoot整合zookeeper客户端 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
        </dependency>
        
        <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>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>

3)YML

Insert image description here

#8004表示注册到zookeeper服务器的支付服务提供者端口号
server:
  port: 8004


spring:
  application:
    #服务别名----注册zookeeper到注册中心名称
    name: cloud-provider-payment
  cloud:
    zookeeper:
      #linux主机ip+zookeeper端口号
      connect-string: 192.168.10.140:2181


4) Main startup class

Insert image description here

package com.angenin.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient//该注解用于向使用consul或者zookeeper作为注册中心时注册服务
public class PaymentMain8004 {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(PaymentMain8004.class, args);
    }
}

5)Controller

  • Note: The main thing to learn now is the integration of zookeeper as a service registration center, so here we only write a Controller for testing, and no longer write the business layer, data layer, and operation database.
    Insert image description here
package com.angenin.springcloud.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.UUID;

@Slf4j
@RestController
public class PaymentController {
    
    

    @Value("${server.port}")        //获取端口号
    private String serverPort;

    //查询端口号,8004生产者能否注册进入zookeeper,获得端口号
    @RequestMapping("/payment/zk")
    public String paymentzk(){
    
    
        return "springcloud with zookeeper:" + serverPort + "\t" + UUID.randomUUID().toString();
    }

}


6) Start 8004 to register into zookeeper

  • First start zookeeper (the default port number is 2181)
    Insert image description here
# 启动Zookeeper服务端
./zkServer.sh start

#启动客户端
# 如果连接本地Zookeeper,那么ip:port可省略
./zkCli.sh -server ip:port
  • Problems will occur when starting the 8004 service producer (the new version has no problem 23/8/21)
    Insert image description here

  • Solve the zookeeper version jar package conflict problem

    • Reason: The version of zookeeper installed by the teacher in the video is version 3.4.9, and the default version when introducing zookeeper dependency coordinates is 3.5.3, so a jar package conflict will be reported.
    • solve:
      • Method 1: Uninstall zookeeper installed in the Linux system and install zookeeper that matches the version (not recommended, zookeeper will not be easily changed after installation is completed, because other systems may be using it)
      • Method 2: Use jar package to exclude import
        Insert image description here
  • New POM.xml after deleting zk conflicts

    • Since I installed version 3.5.7 when I was studying, no errors were reported, so this step can be omitted.
      Insert image description here
<?xml version="1.0" encoding="UTF-8"?>
<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>cloud2020</artifactId>
        <groupId>com.angenin.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-provider-payment8004</artifactId>

    <dependencies>
        <!-- SpringBoot整合Web组件 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency><!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
            <groupId>com.angenin.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>

        <!-- SpringBoot整合zookeeper客户端 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
            <!--先排除自带的zookeeper3.5.3-->
            <exclusions>
                <exclusion>
                    <groupId>org.apache.zookeeper</groupId>
                    <artifactId>zookeeper</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!--添加zookeeper3.4.9版本-->
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.4.9</version>
        </dependency>

        <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>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>

7) Verification test

  • Check whether 8004 is registered in zookeeper
    Insert image description here
    Insert image description here

  • Browser input:http://localhost:8004/payment/zk
    Insert image description here

8) Verification test 2

  • Dig deeper into the content: the content in the purple box is the basic information on zookeeper
    Insert image description here
  • Copy this content into an online json parsing tool (Baidu search)
    Insert image description here

9) Thinking: Is the service node a temporary node or a persistent node?

  • On the zookeeper server, we all understand that there is something called a znode node, and each microservice is placed in zookeeper as a node.
  • Zookeeper node classification:
    • Temporary node
    • Temporary node with serial number
    • persistent node
    • Persistent node with serial number
  • Question: Are the nodes registered in the zookeeper registration center temporary nodes or persistent nodes? ? ?
  • Answer: Temporary node
    • The node we registered on zk is a temporary node. When our service does not send a heartbeat within a certain period of time, zk will delete the znode of this service. There is no self-protection mechanism. After re-establishing the connection, the znode-id number will also change.
      Insert image description here

6.2.3 Service consumers

1) Create a new cloud-consumerzk-order80

Insert image description here

2)POM

Insert image description here

<?xml version="1.0" encoding="UTF-8"?>
<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>cloud2020</artifactId>
        <groupId>com.angenin.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-consumerzk-order80</artifactId>

    <dependencies>
        <!-- SpringBoot整合Web组件 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- SpringBoot整合zookeeper客户端 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
        </dependency>
        <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>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>

3)YML

Insert image description here

#8004表示注册到zookeeper服务器的支付服务提供者端口号
server:
  port: 80


spring:
  application:
    #服务别名----注册zookeeper到注册中心名称
    name: cloud-consumer-order
  cloud:
    zookeeper:
      #linux主机ip+zookeeper端口号
      connect-string: 192.168.10.140:2181


4) Main startup

Insert image description here

package com.angenin.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;


@SpringBootApplication
@EnableDiscoveryClient //该注解用于向使用consul或者zookeeper作为注册中心时注册服务
public class OrderZKMain80 {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(OrderZKMain80.class, args);
    }
}

5) Business category

  • Configure beans
    Insert image description here
package com.angenin.springcloud.config;

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class ApplicationContextConfig {
    
    

    //往容器中添加一个RestTemplate
    //RestTemplate提供了多种便捷访问远程http访问的方法
    @Bean
    @LoadBalanced //使用@LoadBalanced注解赋予RestTemplate负载均衡的能力
    public RestTemplate restTemplate(){
    
    
        return new RestTemplate();
    }

}

  • Controller
    Insert image description here
package com.angenin.springcloud.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;

@RestController
@Slf4j
public class OrderZKController {
    
    
    //调用服务生产者的服务名称
    public static final String INVOKE_URL = "http://cloud-provider-payment";

    @Resource
    private RestTemplate restTemplate;

    @RequestMapping("/consumer/payment/zk")
    public String paymentInfo(){
    
    
        //getForObject两个参数:请求地址,返回的对象类型----读操作
        String result = restTemplate.getForObject(INVOKE_URL + "/payment/zk", String.class);
        return result;
    }

}


6) Verification test

  • Start consumer 80 and check whether it is registered and entered the registration center.
    Insert image description here
    Insert image description here

7) Access the test address

  • http://localhost/consumer/payment/zk
    Insert image description here

8) About Zookeeper cluster

  • Regarding the cluster construction of zookeeper, it is currently rarely used, and the configuration in the yml file is similar. Multiple addresses of zookeeper can be written in list form, and the zookeeper cluster has been explained in the zookeeper course . All in all, as long as you cooperate with the zookeeper cluster and the configuration of the yml file, you can complete the cluster construction.

9) Current architecture

  • A zookeeper registration center, a producer 8004, and a consumer 80, and both 80 and 8004 are registered in the service registration center, and the consumer 80 calls the producer 8004.
    Insert image description here

7. Consul service registration and discovery

7.1 Introduction to Consul

  • What is:

    • https://www.consul.io/intro/index.html
      Insert image description here
    • Consul is an open source distributed service discovery and configuration management system used by HashiCorp Go 语言开发.
    • Provides service governance, configuration center, control bus and other functions in the microservice system. Each of these features can be used individually as needed, or used together to build a comprehensive service mesh. In short, Consul provides a complete service mesh solution.
    • It has many advantages. Including: Based on the raft protocol, which is relatively simple; supports health check, supports both HTTP and DNS protocols; supports WAN clusters across data centers; provides a graphical interface across platforms, supporting Linux, Mac, and Windows
  • What can you do

    • Service discovery: Provides two discovery methods: HTTP and DNS.
    • Health monitoring: supports multiple methods, customized monitoring of HTTP, TCP, Docker, and Shell scripts
    • KV storage: storage method of Key and Value
    • Multiple data centers: Consul supports multiple data centers
    • Visual web interface
  • Where to go: Choose the version you want

    • https://www.consul.io/downloads.html
      Insert image description here
  • How to play

    • https://www.springcloud.cc/spring-cloud-consul.html
      Insert image description here
  • The default port number is 8500

7.2 Install and run Consul

  • Official website installation instructions:https://learn.hashicorp.com/consul/getting-started/install.html
    Insert image description here

  • Take downloading the windows version of Consul as an example:
    Insert image description here

  • After the download is completed, there is only one consul.exe file decompressed. Enter cmd into the command line window to view the version number information.
    Insert image description here
    Insert image description here

  • Start using development mode

    • consul agent -dev
      Insert image description here

    • You can access Consul’s homepage through the following address: http://localhost:8500

    • Results page
      Insert image description here

7.3 Service providers

7.3.1 Create new module payment service provider8006

  • cloud-providerconsul-payment8006
    Insert image description here

7.3.2 POM

Insert image description here

<?xml version="1.0" encoding="UTF-8"?>
<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>cloud2020</artifactId>
        <groupId>com.angenin.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-providerconsul-payment8006</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
        <dependency>
            <groupId>com.angenin.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        <!--SpringCloud consul-server -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
        </dependency>
        <!-- SpringBoot整合Web组件 -->
        <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>
        <!--日常通用jar包配置-->
        <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>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>RELEASE</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>RELEASE</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>

7.3.3 YML

Insert image description here

#consul服务端口号
server:
  port: 8006

#对外暴露的服务名
spring:
  application:
    name: consul-provider-payment
  #consul注册中心地址
  cloud:
    consul:
      host: localhost
      port: 8500
      discovery:
        #hostname: 127.0.0.1
        service-name: ${
    
    spring.application.name}

7.3.4 Main startup class

Insert image description here

package com.angenin.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient //用于启用服务注册与发现功能。
public class PaymentMain8006
{
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(PaymentMain8006.class, args);
    }
}


7.3.5 Business Controller

Insert image description here

package com.angenin.springcloud.controller;


import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.UUID;

@RestController
@Slf4j
public class PaymentController
{
    
    
    @Value("${server.port}")
    private String serverPort;

    @RequestMapping(value = "/payment/consul")
    public String paymentConsul()
    {
    
    
        return "springcloud with consul: "+serverPort+"\t   "+ UUID.randomUUID().toString();
    }
}



7.3.6 Verification testing

  • Start the consul service registration center and start the service producer 8006

  • Check the homepage of the Consul registration center (http://localhost:8500) and you can see that the producer has been registered in the service registration center.
    Insert image description here

  • http://localhost:8006/payment/consul
    Insert image description here

7.4 Serving consumers

7.4.1 Create new Module consumption service order80

  • cloud-consumerconsul-order80
    Insert image description here

7.4.2 POM

Insert image description here

<?xml version="1.0" encoding="UTF-8"?>
<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>cloud2020</artifactId>
        <groupId>com.angenin.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-consumerconsul-order80</artifactId>

    <dependencies>
        <!--SpringCloud consul-server -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
        </dependency>
        <!-- SpringBoot整合Web组件 -->
        <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>
        <!--日常通用jar包配置-->
        <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>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

7.4.3 YML

Insert image description here

###consul服务端口号
server:
  port: 80

spring:
  application:
    name: cloud-consumer-order
  ####consul注册中心地址
  cloud:
    consul:
      host: localhost
      port: 8500
      discovery:
        #hostname: 127.0.0.1
        service-name: ${
    
    spring.application.name}

7.4.4 Main startup class

Insert image description here

package com.angenin.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient //该注解用于向使用consul或者zookeeper作为注册中心时注册服务
public class OrderConsulMain80
{
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(OrderConsulMain80.class, args);
    }
}

7.4.5 Configuring Beans

Insert image description here

package com.angenin.springcloud.config;

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class ApplicationContextConfig
{
    
    
    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate()
    {
    
    
        return new RestTemplate();
    }
}

7.4.6 Controller

Insert image description here

package com.angenin.springcloud.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;

@RestController
@Slf4j
public class OrderConsulController{
    
    
    public static final String INVOKE_URL = "http://consul-provider-payment";

    @Resource
    private RestTemplate restTemplate;

    @GetMapping(value = "/consumer/payment/consul")
    public String paymentInfo(){
    
    
        String result = restTemplate.getForObject(INVOKE_URL+"/payment/consul",String.class);
        return result;
    }
}

7.4.7 Verification testing

  • Start 80 consumers
  • Open the Consul homepage (http://localhost:8500)
    Insert image description here

7.4.8 Access test address

  • http://localhost/consumer/payment/consul
    Insert image description here

7.5 Similarities and differences among the three registration centers

Component name Language CAP Service health check Externally exposed interface Spring Cloud integration
Eureka Java AP Available support HTTP
Consul Go CP support HTTP/DNS
Zookeeper Java CP Support client Integrated

7.5.1 CAP

CAP theory focuses on the granularity of data rather than the overall system design strategy.

  • C: Consistency (strong consistency)
  • A: Availability
  • P: Partition tolerance (partition fault tolerance)

7.5.2 Classic CAP graph

  • 最多只能同时较好的满足两个。
  • The core of CAP theory is: 一个分布式系统不可能同时很好的满足一致性,可用性和分区容错性这三个需求, therefore, according to the CAP principle, NoSQL databases are divided into three categories: satisfying the CA principle, satisfying the CP principle and satisfying the AP principle:
    • CA - Single-point cluster, system that meets consistency and availability, usually not very powerful in scalability.
    • CP - A system that satisfies consistency, partition tolerance, and usually does not perform particularly well.
    • AP - A system that meets availability, partition tolerance, and may generally have lower consistency requirements.
      Insert image description here

1) AP architecture (Eureka)

  • When a network partition occurs, in order to ensure availability, system B 可以返回旧值ensures system availability.
  • 结论:违背了一致性C的要求,只满足可用性和分区容错,即AP
  • Eureka has a self-protection mechanism. What he emphasizes is that AP ensures the high availability of microservices. It is better to die than to live. Even if it occasionally goes down and is offline for a while and cannot receive it, it will not be deleted immediately.
    Insert image description here

2) CP architecture (Zookeeper/Consul)

  • When a network partition occurs, in order to ensure consistency, the request must be rejected, otherwise consistency cannot be guaranteed.
  • 结论:违背了可用性A的要求,只满足一致性和分区容错,即CP
  • Once the service is stopped, it will be deleted immediately.
    Insert image description here

8 Ribbon load balancing service call

8.1 Overview

  • Restore the eureka cluster environment for the next exercise.

    • Previously, in order to facilitate testing of the self-protection mechanism (it is troublesome to start all services each time), only the 7001 service registration center and 8001 producer were started, so here we need to restore the single-click mode configuration to the cluster mode configuration. (Modify the 7001yml file to the cluster configuration mode, and modify the 8001yml configuration file to the cluster mode)
      Insert image description here
      Insert image description here
  • Start the 7001 and 7002 service registration center clusters

  • Start 8001 and 8002 producer clusters

  • Start 80 consumer cluster

  • Consumer 80 calls the producer cluster
    Insert image description here

  • Visit the homepage of Eureka7001:http://eureka7001.com:7001/
    Insert image description here

  • Visit the homepage of Eureka7002:http://eureka7002.com:7002/
    Insert image description here

8.1.1 What is

  • Spring Cloud Ribbon is a set implemented based on Netflix Ribbon 客户端负载均衡的工具.
  • Simply put, Ribbon is an open source project released by Netflix, and its main function is to provide 客户端的软件负载均衡算法和服务调用. The Ribbon client component provides a series of complete configuration items such as connection timeout, retry, etc. To put it simply, list all the machines behind the Load Balancer (LB for short) in the configuration file, and Ribbon will automatically help you connect to these machines based on certain rules (such as simple polling, random connections, etc.). We can easily use Ribbon to implement custom load balancing algorithms.

8.1.2 Official website information

  • https://github.com/Netflix/ribbon/wiki/Getting-Started
    Insert image description here

  • Ribbon is also currently in maintenance mode
    Insert image description here

  • Future replacement options

    • Ribbon may be replaced by Spring Cloud LoadBalacer in the future.

8.1.3 Can you do it?

  • What is LB load balancing (Load Balance)

    • Simply put, user requests are evenly distributed to multiple services to achieve system HA (high availability).
    • Common load balancing include software Nginx, LVS, hardware F5, etc.
  • The difference between Ribbon local load balancing client VS Nginx server load balancing

    • Nginx is server load balancing. All client requests will be handed over to nginx, and then nginx will forward the requests. That is, load balancing is implemented by the server.
    • Ribbon local load balancing, when calling the microservice interface, will obtain the registration information service list from the registration center and cache it locally in the JVM, thereby implementing RPC remote service invocation technology locally.
  • LB (Load Balancing)

    • Centralized LB : that is, an independent LB facility (can be hardware, such as F5, or software, such as nginx) is used between the consumer and provider of the service. This facility is responsible for forwarding access requests to service provider;
    • In-process LB : Integrate LB logic into the consumer. The consumer learns from the service registration center which addresses are available, and then selects a suitable server from these addresses. Ribbon就属于进程内LB, it is just a class library 集成于消费方进程through which the consumer obtains the address of the service provider.
  • Earlier we explained that 80 accesses 8001/8002 through polling load (the default is polling)
    Insert image description here
    Insert image description here

  • In one sentence:负载均衡+RestTemplate调用

    • The client's load balancing tool cooperates with RestTemplate to implement remote RPC calls.

8.2 Ribbon load balancing demonstration

8.2.1 Architecture description

  • Ribbon works in two steps
    • The first step is to select EurekaServer, which gives priority to servers with less load in the same area.
    • The second step is to select an address from the service registration list obtained from the server according to the policy specified by the user.
  • Ribbon provides a variety of strategies: such as polling, random and weighted according to response time.
  • Summary: Ribbon is actually a soft load balancing client component. It can be used in conjunction with other clients that require required requests. Combining with eureka is just one example.
    Insert image description here

8.2.2 POM

  • Explanation: The Ribbon dependency was not introduced before, why can load balancing be achieved.
    Insert image description here
    Insert image description here
  • Whether to introduce Ribbon dependency
    Insert image description here
        <!--Ribbon的依赖:因为下面这个eureka-client依赖已经只带了Ribbon的依赖,所以此依赖加不加都可以-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
        </dependency>

8.2.3 Second, the use of RestTemplate

  • Official website

    • https://docs.spring.io/spring-framework/docs/5.2.2.RELEASE/javadoc-api/org/springframework/web/client/RestTemplate.html
      Insert image description here
  • getForObject method/getForEntity method
    Insert image description here

  • postForObject / postForEntity
    Insert image description here

  • GET request method (read)
    Insert image description here

  • POST request method (write)
    Insert image description here

  • Test: Test the query using the getForEntity method
    Insert image description here

    //使用getForEntity方法测试查询
    @GetMapping("/consumer/payment/getForEntity/{id}")
    public CommonResult<Payment> getPayment2(@PathVariable("id") Long id) {
    
    
        ResponseEntity<CommonResult> entity = restTemplate.getForEntity(PAYMENT_URL+"/payment/get/"+id,CommonResult.class);

        //getStatusCode获取状态码,is2xxSuccessful如果是状态码是200代表成功
        if(entity.getStatusCode().is2xxSuccessful()){
    
    
            //如果成功了返回请求体
            return entity.getBody();
        }else{
    
    
            return new CommonResult<>(444,"操作失败");
        }
    }
  • Restart 80 and found that using the getForEntity method to test the query is still successful.
    Insert image description here

8.3 Ribbon core component IRule

8.3.1 IRule interface

  • IRule: Select a service to be accessed from the service list according to a specific algorithm
  • The main implementation class of IRule (Ribbon comes with 7 load balancing algorithms)
    Insert image description here
    • com.netflix.loadbalancer.RoundRobinRule: Polling
    • com.netflix.loadbalancer.RandomRule: Random
    • com.netflix.loadbalancer.RetryRule: First obtain the service according to the RoundRobinRule strategy. If the service fails to be obtained, it will be retried within the specified time to obtain available services.
    • WeightedResponseTimeRule: An extension of RoundRobinRule. The faster the response speed, the greater the selection weight and the easier it is to be selected.
    • BestAvailableRule: Will first filter out services that are in a circuit breaker trip state due to multiple access failures, and then select a service with the smallest amount of concurrency
    • AvailabilityFilteringRule: First filter out failed instances, and then select instances with smaller concurrency
    • ZoneAvoidanceRule: Default rule, composite judgment on the performance of the zone where the server is located and the availability of the server to select the server

8.3.2 How to replace

1) Modify cloud-consumer-order80

2) Pay attention to configuration details

The official documentation clearly gives the warning:

  • This custom configuration class cannot be placed under the current package or sub-package scanned by @ComponentScan, otherwise our custom configuration class will be shared by all Ribbon clients, and the purpose of special customization will not be achieved.
  • That is: the main startup class will be annotated with @SpringBootApplication. The bottom layer of this annotation contains @ComponentScan, which is used to scan the package and sub-packages where the main startup class is located by default. The current requirement is that the Ribbon configuration class cannot be placed in the package where the main startup class is located or the sub-package where it is located, so a new package must be created.

Insert image description here

3) Create a new package: com.angenin.myrule

Insert image description here

4) Create a new MySelfRule rule class under the above package

Insert image description here

package com.angenin.myrule;

import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MySelfRule {
    
    
    @Bean
    public IRule myrule(){
    
    
        return new RandomRule(); //负载均衡规则定义为随机
    }
}

5) Add @RibbonClient to the main startup class

Insert image description here

package com.angenin.springcloud;

import com.angenin.myrule.MySelfRule;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.ribbon.RibbonClient;

/**
 * 在启动该微服务的时候就能去加载我们的自定义Ribbon配置类,从而使配置生效,形如:
 * 服务生产者的服务名(配置文件是小写,这里是大写)、配置类的类型
 */
@RibbonClient(name = "CLOUD-PAYMENT-SERVICE",configuration=MySelfRule.class)
@EnableEurekaClient
@SpringBootApplication
public class OrderMain80 {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(OrderMain80.class, args);
    }
}


6) Test

  • Start the 7001 and 7002 service registration center clusters

  • Start 8001 and 8002 producer clusters

  • Start 80 consumer cluster

  • Consumer 80 calls the producer cluster

  • http://localhost/consumer/payment/get/4 (The displayed result is random, no longer polling 8001 and 8002 replaced back and forth)
    Insert image description here

8.4 Ribbon load balancing algorithm

  • Revert to default polling rules
    Insert image description here

8.4.1 Principle of polling rules

  • Load balancing algorithm: The number of requests to the rest interface % The total number of server clusters = The actual calling server location subscript, 每次服务重启动后rest接口计数从1开始.
  • Get the number of clusters in the service list:List instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
  • like:
    • List [0] instances = 127.0.0.1:8002
    • List [1] instances = 127.0.0.1:8001
  • 8001+ 8002 are combined into a cluster. They have a total of 2 machines and the total number of clusters is 2. According to the principle of polling algorithm :
    • When the total number of requests is 1: 1 % 2 =1 and the corresponding subscript position is 1, then the service address obtained is 127.0.0.1:8001
    • When the total number of requests is 2: 2 % 2 =0 and the corresponding subscript position is 0, then the service address obtained is 127.0.0.1:8002
    • When the total number of requests is 3: 3% 2 =1 and the corresponding subscript position is 1, then the service address obtained is 127.0.0.1:8001
    • When the total number of requests is 4: 4 % 2 =0 and the corresponding subscript position is 0, then the service address obtained is 127.0.0.1:8002
    • And so on…

8.4.2 Source code of RoundRobinRule polling rule

  • ctrl+n opens the IRule interface
    Insert image description here
  • ctrl+alt+b: View the implementation class of this interface
    Insert image description here
  • Source code:
    Insert image description here
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.netflix.loadbalancer;

import com.netflix.client.config.IClientConfig;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class RoundRobinRule extends AbstractLoadBalancerRule {
    
    
	//AtomicInteger原子整形类
    private AtomicInteger nextServerCyclicCounter;
    private static final boolean AVAILABLE_ONLY_SERVERS = true;
    private static final boolean ALL_SERVERS = false;
    private static Logger log = LoggerFactory.getLogger(RoundRobinRule.class);

    public RoundRobinRule() {
    
    
	    //此时nextServerCyclicCounter是一个原子整形类,并且value为0
        this.nextServerCyclicCounter = new AtomicInteger(0);
    }

    public RoundRobinRule(ILoadBalancer lb) {
    
    
        this();
        this.setLoadBalancer(lb);
    }

   //ILoadBalancer选择哪一个负载均衡机制,这里lb为轮询
    public Server choose(ILoadBalancer lb, Object key) {
    
    
    //如果传入的lb没有负载均衡,为空,那么报错
        if (lb == null) {
    
    
            log.warn("no load balancer");
            return null;
        } else {
    
    
            Server server = null;
            int count = 0;
			//还没选到执行的server,并且选择的次数没超过10次,进行选择server
            while(true) {
    
    
                if (server == null && count++ < 10) {
    
    
                	//lb.getReachableServers获取所有状态是up的服务实例
                    List<Server> reachableServers = lb.getReachableServers();
                    //lb.getAllServers获取所有服务实例
                    List<Server> allServers = lb.getAllServers();
                    //状态为up的服务实例的数量
                    int upCount = reachableServers.size();
                    //所有服务实例的数量
                    int serverCount = allServers.size();
                    //如果up的服务实例数量为0或者服务实例为0,打印日志log.warn并返回server=null
                    if (upCount != 0 && serverCount != 0) {
    
    
                        //获取到接下来server的下标
                        int nextServerIndex = this.incrementAndGetModulo(serverCount);
                        //获取下一个server
                        server = (Server)allServers.get(nextServerIndex);
                        //如果
                        if (server == null) {
    
    
                        //线程让步,线程会让出CPU执行权,让自己或者其它的线程运行。(让步后,CPU的执行权也有可能又是当前线程)
                            Thread.yield();
                        } else {
    
    
                        //获取的server还活着并且还能工作,则返回该server
                            if (server.isAlive() && server.isReadyToServe()) {
    
    
                                return server;
                            }
							//否则server改为空
                            server = null;
                        }
                        //进入下次循环
                        continue;
                    }

                    log.warn("No up servers available from load balancer: " + lb);
                    return null;
                }
				//选择次数超过10次,打印日志log.warn并返回server=null
                if (count >= 10) {
    
    
                    log.warn("No available alive servers after 10 tries from load balancer: " + lb);
                }

                return server;
            }
        }
    }

    private int incrementAndGetModulo(int modulo) {
    
    
        int current;
        int next;
        //CAS加自旋锁
    	//CAS(Conmpare And Swap):是用于实现多线程同步的原子指令。CAS机制当中使用了3个基本操作数:内存地址V,旧的预期值A,要修改的新值B。更新一个变量的时候,只有当变量的预期值A和内存地址V当中的实际值相同时,才会将内存地址V对应的值修改为B。
    	//自旋锁:是指当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环。 
        do {
    
    
            //获取value,即0
            current = this.nextServerCyclicCounter.get();
            //取余,为1
            next = (current + 1) % modulo;
     //进行CAS判断,如果此时在value的内存地址中,如果value和current相同,则为true,返回next的值,否则就一直循环,直到结果为true
        } while(!this.nextServerCyclicCounter.compareAndSet(current, next));

        return next;
    }

    public Server choose(Object key) {
    
    
        return this.choose(this.getLoadBalancer(), key);
    }

    public void initWithNiwsConfig(IClientConfig clientConfig) {
    
    
    }
}

8.4.3 Handwriting: Try writing a local load balancer yourself (polling)

1) 7001/7002 cluster startup

  • Start 7001 and 7002 clusters

2) 8001/8002 microservice transformation: controller

  • Add this method to the PaymentController of 8001 and 8002 to test our custom polling:
    Insert image description here
    Insert image description here
    //用于测试自定义负载均衡的规则
    @GetMapping("/payment/lb")
    public String getPaymentLB(){
    
    
        return serverPort;
    }

3) 80 order microservice transformation

  • ApplicationContextBean removes the annotation @LoadBalance

    • Remove the load balancing that comes with Ribbon. If it works, it means that the load balancing configuration you wrote is successful.
      Insert image description here
  • LoadBalancer interface
    Insert image description here

package com.angenin.springcloud.lb;

import org.springframework.cloud.client.ServiceInstance;

import java.util.List;


public interface LoadBalancer {
    
    
    //传入具体实例的集合,返回选中的实例
    ServiceInstance instances(List<ServiceInstance> serviceInstance);
}


  • MyLB interface implementation class
    Insert image description here
package com.angenin.springcloud.lb;

import org.springframework.cloud.client.ServiceInstance;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;


@Component //加入容器
public class MyLB implements LoadBalancer
{
    
    

    //新建一个原子整形类
    private AtomicInteger atomicInteger = new AtomicInteger(0);

    public final int getAndIncrement() {
    
    
        int current;
        int next;

        do {
    
    
            current = this.atomicInteger.get();
            //如果current是最大值,重新计算,否则加1(防止越界)
            next = current >= 2147483647 ? 0 : current + 1;

            //进行CAS判断,如果不为true,进行自旋
        }while(!this.atomicInteger.compareAndSet(current,next));
            System.out.println("*****第几次访问,次数next: "+next);
            return next;
    }

    //负载均衡算法:rest接口第几次请求数 % 服务器集群总数量 = 实际调用服务器位置下标  ,每次服务重启动后rest接口计数从1开始。
    @Override
    public ServiceInstance instances(List<ServiceInstance> serviceInstances)
    {
    
    
        //进行取余
        int index = getAndIncrement() % serviceInstances.size();
        //返回选中的服务实例
        return serviceInstances.get(index);
    }
}
  • OrderController
    Insert image description here
    @Resource
    private LoadBalancer loadBalancer;
    @Resource
    private DiscoveryClient discoveryClient;

    //测试自己写的负载均衡
    @GetMapping("/consumer/payment/lb")
    public String getPaymentLB(){
    
    
        //获取CLOUD-PAYMENT-SERVICE服务的所有具体实例
        List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
        if(instances == null || instances.size() <= 0){
    
    
            return null;
        }

        ServiceInstance serviceInstance = loadBalancer.instances(instances);
        URI uri = serviceInstance.getUri();
        System.out.println(uri);

        return restTemplate.getForObject(uri + "/payment/lb", String.class);
    }
  • 测试:http://localhost/consumer/payment/lb
    • Start the service first
      Insert image description here
    • Effect: The polling load rule written by myself was tested successfully
      Insert image description here
      Insert image description here
  • console
    Insert image description here

9 OpenFeign service interface call

9.1 Overview

9.1.1 What is OpenFeign

Official website documentation explains:

  • https://cloud.spring.io/spring-cloud-static/Hoxton.SR1/reference/htmlsingle/#spring-cloud-openfeign
    Insert image description here

  • Feign is a declarative WebService client. Using Feign can make writing Web Service clients easier.

  • How to use it is 定义一个服务接口然后在上面添加注解. Feign also supports pluggable encoders and decoders. Spring Cloud encapsulates Feign to support Spring MVC standard annotations and HttpMessageConverters. Feign can be combined with Eureka and Ribbon to support load balancing

Summarize:

  • Feign is a declarative web service client that makes writing web service clients very easy.只需创建一个接口并在接口上添加注解即可
  • GitHub source code:https://github.com/spring-cloud/spring-cloud-openfeign
    Insert image description here

9.1.2 What can you do?

  • What can Feign do?

    • Feign aims to make writing Java Http clients easier.
    • When using Ribbon+RestTemplate earlier , RestTemplate was used to encapsulate http requests and form a set of templated calling methods. However, in actual development, since service dependencies may be called in more than one place, 往往一个接口会被多处调用,所以通常都会针对每个微服务自行封装一些客户端类来包装这些依赖服务的调用. Therefore, Feign has further encapsulated it on this basis , and he will help us define and implement the definition of dependent service interfaces. Under the implementation of Feign, 我们只需创建一个接口并使用注解的方式来配置它(以前是Dao接口上面标注Mapper注解,现在是一个微服务接口上面标注一个Feign注解即可), the interface binding to the service provider can be completed, simplifying the development effort of automatically encapsulating the service call client when using Spring cloud Ribbon.
  • Feign integrates Ribbon

    • Ribbon is used to maintain the service list information of Payment, and client load balancing is implemented through polling. What is different from Ribbon is that 通过feign只需要定义服务绑定接口且以声明式的方法it elegantly and simply implements service calls.

9.1.3 The difference between Feign and OpenFeign

Insert image description here

9.2 OpenFeign usage steps

  • Microservice calling interface+@FeignClient
    • Microservice calling interface: an interface that matches the provider and the caller
  • Feign is used on the consumer side
    Insert image description here
  • Architecture
    Insert image description here

9.2.1 Create new cloud-consumer-feign-order80

Insert image description here

9.2.2 POM

  • You can see that the old version of OpenFeign also integrates Ribbon, but the new version does not.
    Insert image description here
<?xml version="1.0" encoding="UTF-8"?>
<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>cloud2020</artifactId>
        <groupId>com.angenin.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-consumer-feign-order80</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <!--openfeign-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!--eureka client-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
        <dependency>
            <groupId>com.angenin.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        <!--web-->
        <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>
        <!--一般基础通用配置-->
        <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>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>


</project>

9.2.3 YML

  • OpenFeign does not register it into eureka as a microservice, it is just a client.
    Insert image description here
server:
  port: 80

eureka:
  client:
    register-with-eureka: false
    service-url: # 配置服务中心,openFeign去里面找服务
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/


9.2.4 Main startup

Insert image description here

package com.angenin.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;

@EnableFeignClients //使用feign,激活并开启
@SpringBootApplication
public class OrderFeignMain80 {
    
    

    public static void main(String[] args) {
    
    
        SpringApplication.run(OrderFeignMain80.class, args);
    }

}

9.2.5 Business class

1) Create a new PaymentFeignService interface and add the annotation @FeignClient

  • Business logic interface + @FeignClient configuration calls provider service
    Insert image description here
package com.angenin.springcloud.service;

import com.angenin.springcloud.entities.CommonResult;
import com.angenin.springcloud.entities.Payment;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@Component
//找到注册中心上的微服务接口名
@FeignClient(value = "CLOUD-PAYMENT-SERVICE")
public interface PaymentFeignService {
    
    

    //调用8001的控制层方法
    @GetMapping(value = "/payment/get/{id}")
    public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id);


}

2) Control layerController

Insert image description here

package com.angenin.springcloud.controller;

import com.angenin.springcloud.entities.CommonResult;
import com.angenin.springcloud.entities.Payment;
import com.angenin.springcloud.service.PaymentFeignService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

@Slf4j
@RestController
public class OrderFeignController {
    
    

    @Resource
    private PaymentFeignService paymentFeignService;

    @GetMapping("/consumer/payment/get/{id}")
    public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id){
    
    
        return paymentFeignService.getPaymentById(id);
    }

}

9.2.6 Testing

  • First start 2 eureka clusters 7001/7002
  • Start 2 more microservices 8001/8002
  • Start cloud-consumer-feign-order80
  • http://localhost/consumer/payment/get/4
    • Feign comes with its own load balancing configuration item Ribbon
      Insert image description here
      Insert image description here

9.2.7 Summary

Insert image description here

9.3 OpenFeign timeout control

  • Note: The consumer calls the producer, which are two different microservices, so there must be a timeout phenomenon.
  • eg: The provider takes 3 seconds to process the service. The provider thinks that 3 seconds is normal, but the consumer is only willing to wait for 1 second. After 1 second, the provider will not return the data, and the consumer will cause a timeout call error. .
  • Therefore, both parties need to agree on a time and do not use the default one.

9.3.1 Timeout setting, deliberately setting timeout to demonstrate error conditions

  • Service provider 8001 intentionally writes a pause program
    Insert image description here
    //测试OpenFeign超时控制
    @GetMapping("/payment/feign/timeout")
    public String paymentFeignTimeout(){
    
    
        try {
    
    
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
        return serverPort;
    }
  • Service consumer 80 adds timeout method PaymentFeignService
    Insert image description here
    @GetMapping(value = "/payment/feign/timeout")
    public String paymentFeignTimeout();

  • Service consumer 80 adds timeout method OrderFeignController
    Insert image description here
    @GetMapping("/consumer/payment/feign/timeout")
    public String paymentFeignTimeout(){
    
    
        //openFeign底层是---ribbon,客户端(消费者)一般默认等待1秒
        return paymentFeignService.paymentFeignTimeout();
    }
  • test
    • Start 7001, 7002, provider 8001, consumer cloud-consumer-feign-order80
      Insert image description here

    • http://localhost/consumer/payment/feign/timeout

    • error page
      Insert image description here

9.3.2 What is

  • OpenFeign waits for 1 second by default and reports an error after exceeding the time limit.
    • By default, the Feign client only waits for one second, but the server-side processing takes more than 1 second. As a result, the Feign client does not want to wait anymore and directly returns an error. In order to avoid such a situation, sometimes we need to set the timeout control of the Feign client.
  • OpenFeign supports Ribbon by default (eliminated in versions starting with version 3), and its timeout control is also limited by the lowest-level Ribbon.
    Insert image description here

9.3.3 OpenFeign client timeout control needs to be enabled in the YML file

Insert image description here

#设置feign客户端超时时间(OpenFeign默认支持ribbon)(单位:毫秒)
ribbon:
  #指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间
  ConnectTimeout: 5000
  #指的是建立连接后从服务器读取到可用资源所用的时间
  ReadTimeout: 5000
  • Restart 80 for testing: http://localhost/consumer/payment/feign/timeout
    Insert image description here

9.4 OpenFeign log printing function

  • Feign provides a log printing function, and we can adjust the log level through configuration to understand the details of HTTP requests in Feign.
    • 说白了就是对Feign接口的调用情况进行监控和输出
  • Log level:
    • NONE: Default, no logs are displayed;
    • BASIC: Only record the request method, URL, response status code and execution time;
    • HEADERS: In addition to the information defined in BASIC, there are also request and response header information
    • FULL: In addition to the information defined in HEADERS, there is also the body and metadata of the request and response.

Test steps:

  • Configure logging beans
    Insert image description here
package com.angenin.springcloud.config;

import feign.Logger;	//不要导错包
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FeignConfig {
    
    

    @Bean
    Logger.Level feignLoggerLevel(){
    
    
        //打印最详细的日志
        return Logger.Level.FULL;
    }

}

  • Feign client that needs to enable logs in the YML file
    Insert image description here
#开启日志的feign客户端
logging:
  level:
    #feign日志以什么级别监控哪个接口
    com.angenin.springcloud.service.PaymentFeignService: debug	#写你们自己的包名
  • Background log view: Restart 80
    Insert image description here
    Insert image description here
    Insert image description here

Guess you like

Origin blog.csdn.net/aa35434/article/details/132361053