SpringCloud introductory study notes (part)

Here are some links first

This article explains the microservice architecture in detail : Beginners to microservices must read this article. Understanding microservices will be very helpful for future learning.

In-depth understanding of service registration and discovery : the explanation is easy to understand, and you can have an understanding of service discovery and registration.

1. Create a parent project Project space

1.1 Create an empty maven project

Insert image description here
Insert image description here

1.2 File filtering (not displayed)

Add the following two useless files
Insert image description here

1.3 Delete src and modify pom

1.3.1 The project structure is as follows

Insert image description here

1.3.2 pom add dependencies

<?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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.atguigu.springcloud</groupId>
    <artifactId>cloud2020</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>pom</packaging>

    <!-- 统一管理jar包版本 -->
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <junit.version>4.12</junit.version>
        <log4j.version>1.2.17</log4j.version>
        <lombok.version>1.16.18</lombok.version>
        <mysql.version>5.1.47</mysql.version>
        <druid.version>1.1.16</druid.version>
        <mybatis.spring.boot.version>1.3.0</mybatis.spring.boot.version>
    </properties>

    <!-- 子模块继承之后,提供作用:锁定版本+子 module不用写groupId和version  -->
    <dependencyManagement>
        <dependencies>
            <!--spring boot 2.2.2-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.2.2.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--spring cloud Hoxton.SR1-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.SR1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--spring cloud alibaba 2.1.0.RELEASE-->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.1.0.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>${mysql.version}</version>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>${druid.version}</version>
            </dependency>
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>${mybatis.spring.boot.version}</version>
            </dependency>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>${junit.version}</version>
            </dependency>
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>${log4j.version}</version>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>${lombok.version}</version>
                <optional>true</optional>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>

1.3.2.1 dependencyManagement function

Allow all subprojects to reference a dependency without explicitly listing the version number. If the subproject needs to import this package and the version number must be the same as the label in dependencyManagement, there is no need to write it.
Insert image description here
The advantage of this is: if there are multiple sub-projects that all reference the same dependency, you can avoid declaring a version number in each sub-project used, so that when you want to upgrade or switch to another version, you only need to declare a version number at the top level Updates in the parent container do not require modification of sub-projects one by one; in addition, if a sub-project requires another version, you only need to declare the version.

  • DependencyManagement only declares dependencies and does not implement introduction, so sub-projects need to display the required dependencies.

  • If the dependency is not declared in the sub-project, it will not be inherited from the parent project; only if the dependency is written in the sub-project and no specific version is specified, the item will be inherited from the parent project, and the version and scope Both are read from the parent pom;

  • If a version number is specified in the subproject, the jar version specified in the subproject will be used.

1.3.2.2 The role of spring-boot-dependencies

When we use spring or spring-boot to develop a project, we need to introduce many dependencies, including spring's own components, various spring-boot-starters, and other third-party dependencies (such as: slf4j, redis).
With too many dependencies, the choice of version is a problem. I am afraid that the wrong version will cause some unexpected bugs.

So spring provides spring-boot-dependencies to facilitate the management of project dependencies. You only need to configure the version of spring-boot-dependencies in dependencyManagement. There is no need to specify other version numbers in dependencies, just like the pom above.

We click on spring-boot-dependencies to view, and you can see something like the following, which is also a pom with specific version numbers.

<dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot</artifactId>
        <version>2.2.2.RELEASE</version>
      </dependency>
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-test</artifactId>
        <version>2.2.2.RELEASE</version>
      </dependency>
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-test-autoconfigure</artifactId>
        <version>2.2.2.RELEASE</version>
      </dependency>
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-actuator</artifactId>
        <version>2.2.2.RELEASE</version>
      </dependency>
      <dependency>
</dependencyManagement>

1.3.2.3 spring-boot-dependencies role

Spring provides spring-boot-dependencies to facilitate the management of project dependencies, unify version numbers , and manage them. It provides many dependencies. We only need to fill in the version of spring-boot-dependencies.

spring-boot-dependencies is also a pom, the following is part of its content

 <properties>
    <commons-lang3.version>3.9</commons-lang3.version>
    <commons-pool.version>1.6</commons-pool.version>
 </properties>
<dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot</artifactId>
        <version>2.2.2.RELEASE</version>
      </dependency>
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-test</artifactId>
        <version>2.2.2.RELEASE</version>
      </dependency>
      <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
        <version>${commons-lang3.version}</version>
      </dependency>
      <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-pool2</artifactId>
        <version>${commons-pool2.version}</version>
      </dependency>
</dependencyManagement>

One of the ways to use it is that the parent project uses spring-boot-dependencies, and the sub-module only needs to introduce the dependencies without filling in the version number.

2. Create payment module cloud-provider-payment8001

2.1 Create a new module, module name cloud-provider-payment8001

Insert image description here

2.2 Create pom

<?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.atguigu.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

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

    <dependencies>
        <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.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.10</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.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>

</project>

2.3 Create application.yml and PaymentMapper.xml

server:
  port: 8001

spring:
  application:
    name: cloud-payment-service
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource            # 当前数据源操作类型
    driver-class-name: com.mysql.jdbc.Driver              # mysql驱动包
    url: jdbc:mysql://localhost:3306/cloud2020?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: 123456

mybatis:
  mapperLocations: classpath:mapper/*.xml
  type-aliases-package: com.atguigu.springcloud.entities    # 所有Entity别名类所在包

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >

<mapper namespace="com.atguigu.springcloud.dao.PaymentDao">

    <insert id="create" parameterType="Payment" useGeneratedKeys="true" keyProperty="id">
        insert into payment(serial)
        values (#{serial});
    </insert>

    <resultMap id="BaseResultMap" type="com.atguigu.springcloud.entities.Payment">
        <id column="id" property="id" jdbcType="BIGINT"/>
        <id column="serial" property="serial" jdbcType="VARCHAR"/>
    </resultMap>
    <select id="getPaymentById" parameterType="Long" resultMap="BaseResultMap">
        select *
        from payment
        where id = #{id};
    </select>

</mapper>

2.4 Create entity-dao-service-controller

package com.atguigu.springcloud.entities;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @auther zzyy
 * @create 2020-02-18 17:23
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class CommonResult<T>
{
    
    
    private Integer code;
    private String  message;
    private T       data;

    public CommonResult(Integer code,String message)
    {
    
    
        this(code,message,null);
    }
}

package com.atguigu.springcloud.entities;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

/**
 * @auther zzyy
 * @create 2020-02-18 17:22
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Payment implements Serializable
{
    
    
    private Long id;
    private String serial;
}

package com.atguigu.springcloud.dao;

import com.atguigu.springcloud.entities.Payment;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

/**
 * @auther zzyy
 * @create 2020-02-18 10:27
 */
@Mapper
public interface PaymentDao
{
    
    
    public int create(Payment payment);

    public Payment getPaymentById(@Param("id") Long id);
}

package com.atguigu.springcloud.service;

import com.atguigu.springcloud.entities.Payment;
import org.apache.ibatis.annotations.Param;

/**
 * @auther zzyy
 * @create 2020-02-18 10:40
 */
public interface PaymentService
{
    
    
    public int create(Payment payment);

    public Payment getPaymentById(@Param("id") Long id);
}


`package com.atguigu.springcloud.service.impl;

import com.atguigu.springcloud.dao.PaymentDao;
import com.atguigu.springcloud.entities.Payment;
import com.atguigu.springcloud.service.PaymentService;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**
 * @auther zzyy
 * @create 2020-02-18 10:40
 */
@Service
public class PaymentServiceImpl implements PaymentService
{
    
    
    @Resource
    private PaymentDao paymentDao;

    public int create(Payment payment)
    {
    
    
        return paymentDao.create(payment);
    }

    public Payment getPaymentById(Long id)
    {
    
    
        return paymentDao.getPaymentById(id);
    }
}
``
```java
package com.atguigu.springcloud.controller;

import com.atguigu.springcloud.entities.CommonResult;
import com.atguigu.springcloud.entities.Payment;
import com.atguigu.springcloud.service.PaymentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

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

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

    @PostMapping(value = "/payment/create")
    public CommonResult create(Payment payment)
    {
    
    
        int result = paymentService.create(payment);
        log.info("*****插入结果:"+result);

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

    @GetMapping(value = "/payment/get/{id}")
    public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id)
    {
    
    
        Payment payment = paymentService.getPaymentById(id);

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

2.5 Create startup class

package com.atguigu.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @auther zzyy
 * @create 2020-02-17 21:13
 */
@SpringBootApplication
public class PaymentMain8001
{
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(PaymentMain8001.class, args);
    }
}

2.6 Test creation interface

Insert image description here

3 Create the consumer order module cloud-consumer-order80

The order is as above, no subtitles will be written.

<?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.atguigu.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

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

    <dependencies>
        <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>
    </dependencies>

</project>
server:
  port: 80

spring:
  application:
    name: cloud-order-service
package com.atguigu.springcloud.entities;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @auther zzyy
 * @create 2020-02-18 17:23
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class CommonResult<T>
{
    
    
    private Integer code;
    private String  message;
    private T       data;

    public CommonResult(Integer code,String message)
    {
    
    
        this(code,message,null);
    }
}

package com.atguigu.springcloud.entities;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

/**
 * @auther zzyy
 * @create 2020-02-18 17:22
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Payment implements Serializable
{
    
    
    private Long id;
    private String serial;
}

package com.atguigu.springcloud.config;

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

/**
 * @auther zzyy
 * @create 2020-02-18 17:27
 */
@Configuration
public class ApplicationContextConfig {
    
    
    @Bean
    public RestTemplate getRestTemplate() {
    
    
        return new RestTemplate();
    }
}
package com.atguigu.springcloud.controller;

import com.atguigu.springcloud.entities.CommonResult;
import com.atguigu.springcloud.entities.Payment;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;

/**
 * @auther zzyy
 * @create 2020-02-18 17:23
 */
@RestController
@Slf4j
public class OrderController {
    
    
    public static final String PAYMENT_URL = "http://localhost:8001";

    @Resource
    private RestTemplate restTemplate;

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

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

}

Insert image description here

4. Extract the public part

4.1 Create the common module cloud-api-commons

Move the entity classes of the payment and consumption modules here

package com.atguigu.springcloud.entities;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @auther zzyy
 * @create 2020-02-18 17:23
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class CommonResult<T>
{
    
    
    private Integer code;
    private String  message;
    private T       data;

    public CommonResult(Integer code,String message)
    {
    
    
        this(code,message,null);
    }
}

package com.atguigu.springcloud.entities;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

/**
 * @auther zzyy
 * @create 2020-02-18 17:22
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Payment implements Serializable
{
    
    
    private Long id;
    private String serial;
}

<?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.atguigu.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-api-commons</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.6.4</version>
        </dependency>
    </dependencies>
</project>

4.2 Remove the entity classes of payment and consumption modules and add common module dependencies

Just add those two modules separately.

 <!--公有的通用包-->
        <dependency>
            <groupId>com.atguigu.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>

5. Create the EurekaServer server cloud-eureka-server7001

5.1 Create pom, yml, and startup class. Remember to annotate the startup class with @EnableEurekaServer and use the project as the registration center in Spring Cloud.

<?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.atguigu.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.atguigu.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        <!--boot web actuator-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
    </dependencies>

</project>
server:
  port: 7001

eureka:
  instance:
    hostname: locathost #eureka服务端的实例名称
  client:
    #false表示不向注册中心注册自己。
    register-with-eureka: false
    #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
    fetch-registry: false
    service-url:
      #设置与Eureka server交互的地址查询服务和注册服务都需要依赖这个地址。
      defaultZone: http://${
    
    eureka.instance.hostname}:${
    
    server.port}/eureka/

package com.atguigu.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);
    }
}

5.2 Testing

Run the test and enter http://localhost:7001/. If you see the corresponding page, it is successful.

6. Payment and consumer order services are registered to EurekaServer

6.1 Payment registration

6.1.1 Add dependencies and configuration registration

<dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
eureka:
  client:
    #表示是否将自己注册进Eurekaserver默认为true。
    register-with-eureka: true
    #是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
    fetchRegistry: true
    service-url:
      defaultZone: http://localhost:7001/eureka

6.1.2 Add the @EnableEurekaClient annotation to the startup class

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

Then start the registration center 7001, start the payment service 8001, enter http://127.0.0.1:7001/ and you can see the service instance.Insert image description here

6.2 Order registration

Similar to above

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
eureka:
  client:
    #表示是否将自己注册进Eurekaserver默认为true。
    register-with-eureka: true
    #是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
    fetchRegistry: true
    service-url:
      defaultZone: http://localhost:7001/eureka
@SpringBootApplication
@EnableEurekaClient
public class CloudConsumerorder80 {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(CloudConsumerorder80.class, args);
    }
}

7.Eureka cluster environment construction

7.1 host modification

Modify host

127.0.0.1 eureka7001.com
127.0.0.1 eureka7002.com

7.2 cloud-eureka-server7001 yml modification

server:
  port: 7001

eureka:
  instance:
    hostname: eureka7001.com #eureka服务端的实例名称
  client:
    #false表示不向注册中心注册自己。
    register-with-eureka: false
    #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
    fetch-registry: false
    service-url:
      #集群指向其它eureka
      defaultZone: http://eureka7002.com:7002/eureka/
      #单机就是7001自己
      #defaultZone: http://eureka7001.com:7001/eureka/

Because the mapping is added, accessing eureka7001.com will actually access 127.0.0.1

7.3 Create cloud-eureka-server7002 module

<?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.atguigu.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.atguigu.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        <!--boot web actuator-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
    </dependencies>

</project>
server:
  port: 7002

eureka:
  instance:
    hostname: eureka7002.com #eureka服务端的实例名称
  client:
    #false表示不向注册中心注册自己。
    register-with-eureka: false
    #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
    fetch-registry: false
    service-url:
      #集群指向其它eureka
      defaultZone: http://eureka7001.com:7001/eureka/
      #单机就是7001自己
      #defaultZone: http://eureka7001.com:7001/eureka/
package com.atguigu.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);
    }
}

7.4 Start testing

Start 7001 and 7002 respectively
and visit http://127.0.0.1:7001/ and http://127.0.0.1:7002.
You can see that there are other parties in DS Replicas.

8. Order and payment services are registered in the Eureka cluster


Modify the original yml of cloud-consumer-order80 and cloud-provider-payment8001 modules defaultZoneand replace it with the following one

defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka

Start the test and you can see two registration centers, both with order and payment services.
Insert image description here
Insert image description here

9. Payment microservice cluster configuration

9.1 cloud-consumer-order80 changes

9.1.1 Change access address

OrderControllerModify the address in PAYMENT_URLand call it through the microservice name registered on eureka. Because the payment service is a cluster, the original http://localhost:8001 can only access 8001 instead of any one in the cluster.

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

9.1.2 Use the @LoadBalanced annotation to give RestTemplate the ability to load balance

Add annotations when configuring RestTemplate, so that the default rotation access to the two payment services can be seen through the output results of the payment service control layer.
Add the following payment service to the cluster
and then directly access http://localhost/consumer/payment/get/1 without adding this annotation. An error will be reported because the two payment services expose CLOUD-PAYMENT-SERVICE and the order service does not know Which specific payment service needs to be accessed, so after adding the load balancing annotation, one can be selected for access based on the algorithm.

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

9.2 cloud-provider-payment8001 modification

It is also necessary to change the registration address and change it to cluster mode.

defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka

9.3 Create cloud-provider-payment8002 module for clustering

Like cloud-provider-payment8001, after creating a new module, copy other things over, change the startup class, and change the port to 8002.

9.4 Testing

  1. First start EurekaServer, 7001/7002 service
  2. Then start the service provider provider, 8001/8002 service
  3. http://localhost/consumer/payment/get/1
  4. Result: The load balancing effect is achieved, and ports 8001/8002 appear alternately.

Register with each other and watch each other
Insert image description here

10.OpenFeign

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, and an interface is often called in multiple places, some client classes are usually encapsulated for each microservice to package the calls of these dependent services. 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, we only need to create an interface and configure it using annotations (in the past, the Dao interface was marked with Mapper annotations, and now it is a microservice interface with a Feign annotation) to complete the service The provider's interface binding simplifies
the development of automatically encapsulated service call clients 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. Different from Ribbon, with feign you only need to define the service binding interface and use a declarative method to implement service calls elegantly and simply.

10.1 Overall process description:

OpenFeign replaces the previous RestTemplate code. It is also written in Application Client. Put the OpenFeign interface separately in the feign package to represent the service calling layer. When you need to call other services, directly inject the OpenFeign interface object to call the remote service just like calling the local method.

  1. ApplicationService registers the service with Eureka Server.
  2. Application Client discovers service information from Eureka Server.
  3. Call the method in the OpenFeign interface in Application Client
  4. In Application Client, OpenFeign calls Application Service through the application name.

Insert image description here

10.2 Relative Feign differences

OpenFeign is Spring Cloud's support for SpringMVC annotations based on Feign, such as @RequesMapping and so on. OpenFeign's @FeignClient can parse the interface under SpringMVC's @RequestMapping annotation, generate implementation classes through dynamic proxy, perform load balancing and call other services in the implementation classes.

10.3 Create cloud-consumer-feign-order80

10.3.1 Create pom.xml

<?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.atguigu.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

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

    <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.atguigu.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>
    </dependencies>
</project>

10.3.2 Create application.yml

server:
  port: 80

eureka:
  client:
    register-with-eureka: false
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/

logging:
  level:
    # feign日志以什么级别监控哪个接口
    com.atguigu.springcloud.service.PaymentFeignService: debug

10.3.3 Create a startup class and add the @EnableFeignClients annotation to enable openfeign

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

10.3.4 Create service layer

What is created is an interface, and the method is exactly the same as the control layer of the payment service.
Copy everything from the annotation to the end of the method parameters.
@FeignClient default parameters represent: specify the name of FeignClient. If the project uses Ribbon, the name attribute will be used as the name of the microservice for service discovery.

@FeignClient("CLOUD-PAYMENT-SERVICE")
public interface PaymentFeignService {
    
    

    @GetMapping(value = "/payment/get/{id}")
    public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id);
}

10.3.5 Create control layer

Just call the service layer method directly like calling a normal service to access the payment service.

@RestController
public class OrderFeignController {
    
    
    @Resource
    private PaymentFeignService paymentFeignService;

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

}

10.3.6 Testing

  1. First start 2 eureka clusters 7001/7002
  2. Start 2 more microservices 8001/8002
  3. Start OpenFeign startup
  4. http://localhost/consumer/payment/get/31
  5. Feign comes with load balancing configuration items

10.4 OpenFeign timeout control

在cloud-provider-payment8001plus PaymentControllerdelay interface

   @GetMapping(value = "/payment/feign/timeout")
    public String paymentFeignTimeOut()
    {
    
    
        System.out.println("*****paymentFeignTimeOut from port: "+serverPort);
        //暂停几秒钟线程
        try {
    
     TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) {
    
     e.printStackTrace(); }
        return serverPort;
    }

cloud-consumer-feign-order80Add PaymentFeignServicemethods corresponding to the request interface

 @GetMapping(value = "/payment/feign/timeout")
    String paymentFeignTimeOut();

cloud-consumer-feign-order80Add OrderFeignControllertimeout method

  @GetMapping(value = "/consumer/payment/feign/timeout")
    public String paymentFeignTimeOut()
    {
    
    
        return paymentFeignService.paymentFeignTimeOut();
    }

Visit the payer http://localhost:8001/payment/feign/timeout and find that it is normal.
However, when accessing the consumer http://localhost/consumer/payment/feign/timeout, an error is reported because OpenFeign waits for 1 second by default and reports an error after exceeding it. The solution is to Insert image description here
enable OpenFeign client timeout control in the YML file.

#设置feign客户端超时时间(OpenFeign默认支持ribbon)
ribbon:
#指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间
  ReadTimeout: 5000
#指的是建立连接后从服务器读取到可用资源所用的时间
  ConnectTimeout: 5000

Found normal during access

11. Gateway new generation gateway

11.1 What is

A very important component in Cloud Family Bucket is the gateway. In the 1.x version, the Zuul gateway was used;
but in the 2.x version, the upgrade of zuul kept being delayed. SpringCloud finally developed a gateway to replace Zuul. ,
that is one sentence of SpringCloud Gateway:gateway是原zuul1.x版的替代

Insert image description here
Gateway is an API gateway service built on top of the Spring ecosystem, based on technologies such as Spring 5, Spring Boot 2 and Project Reactor.

Gateway aims to provide a simple and effective way to route APIs, as well as provide some powerful filter functions, such as circuit breaker, current limiting, retry, etc.

SpringCloud Gateway is a brand new project of Spring Cloud. It is a gateway developed based on Spring 5.0 + Spring Boot 2.0 and Project Reactor. It aims to provide a simple and effective unified API routing management method for microservice architecture.

As a gateway in the Spring Cloud ecosystem, SpringCloud Gateway aims to replace Zuul. In Spring Cloud 2.0 and above, the latest high-performance version of Zul 2.0 and above is not integrated. Zuul 1.x non-Reactor mode is still used. old version. In order to improve the performance of the gateway, SpringCloud Gateway is implemented based on the WebFlux framework, and the bottom layer of the WebFlux framework uses the high-performance Reactor mode communication framework Netty.

The goal of Spring Cloud Gateway is to provide a unified routing method and provide basic functions of the gateway based on the Filter chain, such as: security, monitoring/indicators, and current limiting.

11.2 Function

  • direction agent
  • Authentication
  • flow control
  • fuse
  • Log monitoring

11.3 Where is the gateway in microservice architecture?

Insert image description here

11.4 GateWay non-blocking asynchronous model

Why did Zuull come out of Gateway again? Why did we choose Gateway?

  1. Netflix is ​​not very reliable. Zuul 2.0 has been delayed and has not been released.

    1. On the one hand, because Zuul 1.0 has entered the maintenance stage, and Gateway was developed by the Spring Cloud team, it is a son product and is trustworthy. Moreover, many functions of Zuul are very simple and convenient to use.
    2. Gateway is developed based on an asynchronous non-blocking model, so there is no need to worry about performance. Although Netflix has already released the latest Zuul 2.x, Spring Cloud seems to have no integration plans. Moreover, Netflix related components have announced that they have entered the maintenance period; I wonder what the future is?
    3. Considering all aspects, Gateway is an ideal gateway choice.
  2. SpringCloud Gateway has the following characteristics

    1. Built on Spring Framework 5, Project Reactor and Spring Boot 2.0;
    2. Dynamic routing: able to match any request attribute;
    3. You can specify Predicate and Filter for routes;
    4. Integrated Hystrix circuit breaker function;
    5. Integrate Spring Cloud service discovery function;
    6. Easy-to-write Predicates and Filters;
    7. Request current limiting function;
    8. Supports path rewriting.
    9. The difference between SpringCloud Gateway and Zuul
  3. Before the official version of Spring Cloud Finchley, the recommended gateway for Spring Cloud was Zuul provided by Netflix.

    1. Zuul 1.x is an API Gateway based on blocking I/O.
    2. Zuul 1.x is based on Servlet 2.5 and uses a blocking architecture. It does not support any long connections (such as WebSocket). Zuul's design pattern is more similar to Nginx. Each I/O operation selects one execution from the worker thread, and the request thread is blocked until the worker The thread is completed, but the difference is that Nginx is implemented in C++, Zuul is implemented in Java, and the JVM itself will have slower loading for the first time, making Zuul's performance relatively poor.
    3. The Zuul 2.x concept is more advanced and wants to be non-blocking and support long connections based on Netty, but Spring Cloud has not yet integrated it. The performance of Zuul .x has been greatly improved compared to Zuul 1.x. In terms of performance, according to the official benchmark test, Spring Cloud Gateway's RPS (requests per second) is 1.6 times that of Zuul.
    4. Spring Cloud Gateway is built on Spring Framework 5, Project Reactor and Spring Boot2, using non-blocking APIs.
    5. Spring Cloud Gateway also supports WebSocket and is tightly integrated with Spring for a better development experience.

Zuul1.x model

The Zuul version integrated in Springcloud uses the Tomcat container and uses the traditional Serviet IO processing model.

Servlet life cycle? Servlet life cycle management is performed by servlet container.

When the container starts, it constructs a servlet object and calls servlet init() for initialization;
when the container is running, it accepts requests and allocates a thread for each request (usually obtains an idle thread from the thread pool) and then calls service); when the
container closes, it calls servlet destroy () Destroy the servlet.

Disadvantages of the above model:

Servlet is a simple network IO model. When a request enters the Servlet container, the Servlet container will bind a thread to it. This model is applicable in scenarios where concurrency is not high. However, once the concurrency is high (such as using Jmeter to suppress the problem), the number of threads will increase, and the cost of thread resources is expensive (online text switching, large memory consumption), seriously affecting the request processing time. In some simple business scenarios, you do not want to allocate a thread for each request. Only one or a few threads are needed to handle extremely concurrent requests. In this business scenario, the servlet model has no advantage.

Therefore, Zuul 1. So SpringCloud Zuul cannot get rid of the shortcomings of the servlet model.

Gateway model

What is WebFlux?

Traditional Web frameworks, such as Struts2, SpringMVC, etc., all run based on Servlet API and Servlet container.

But after Servlet3.1, there is asynchronous non-blocking support. WebFlux is a typical non-blocking asynchronous framework, and its core is implemented based on Reactor-related APIs. Compared with traditional web frameworks, it can run on containers such as Netty, Undertow and Servlet3.1. Non-blocking + functional programming (Spring 5 must let you use Java 8).

Spring WebFlux is a new reactive framework introduced in Spring 5.0. Different from Spring MVC, it does not need to rely on Servlet API. It is completely asynchronous and non-blocking, and is based on Reactor to implement reactive flow specifications.

11.5 Gateway workflow

11.5.1 Three core concepts

  1. Route - Route is the basic module for building a gateway. It consists of ID, target URI, a series of assertions and filters. If the assertion is true, the route will be matched;
  2. Predicate (Assertion) - Referring to Java8's java.util.function.Predicate, developers can match everything in the HTTP request (such as request headers or request parameters), and route the request if it matches the assertion;
  3. Filter - refers to an instance of GatewayFilter in the Spring framework. Using filters, requests can be modified before or after the request is routed.

The web request locates the real service node through some matching conditions. And perform some refined control before and after this forwarding process.

predicate is our matching condition; and filter can be understood as an omnipotent interceptor. With these two elements, plus the target uri, a specific route can be implemented.

11.5.2 Workflow

Insert image description here

The client makes a request to Spring Cloud Gateway. Then find the route that matches the request in Gateway Handler Mapping and send it to Gateway Web Handler.

The Handler then sends the request to our actual service to execute the business logic through the specified filter chain, and then returns.
Filters are separated by dotted lines because filters may execute business logic before ("pre") or after ("post") sending the proxy request.

Filters of the "pre" type can perform parameter verification, permission verification, traffic monitoring, log output, protocol conversion, etc.
Filters of the "post" type can modify response content and response headers, and modify logs. Output, traffic monitoring, etc. play a very important role.

11.6 Gateway construction

11.6.1 cloud-gateway-gateway9527

11.6.2 Create POM.XML

<?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.atguigu.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-gateway-gateway9527</artifactId>

    <dependencies>
        <!--gateway-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</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.atguigu.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>

</project>

11.6.3 Create application.yml

We currently do not want to expose port 8001, and hope to cover 8001 with a layer of 9527. Configure the rules under
. If the access path contains the one written in, then the original accessed address prefix will be changed to the configured one.routespredicateshost+端口uri


server:
  port: 9527

spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      routes:
        - id: payment_routh #payment_route    #路由的ID,没有固定规则但要求唯一,建议配合服务名
          uri: http://localhost:8001          #匹配后提供服务的路由地址
          predicates:
            - Path=/payment/get/**         # 断言,路径相匹配的进行路由

        - id: payment_routh2 #payment_route    #路由的ID,没有固定规则但要求唯一,建议配合服务名
          uri: http://localhost:8001          #匹配后提供服务的路由地址
          predicates:
            - Path=/payment/lb/**         # 断言,路径相匹配的进行路由

eureka:
  instance:
    hostname: cloud-gateway-service
  client: #服务提供者provider注册进eureka服务列表内
    service-url:
      register-with-eureka: true
      fetch-registry: true
      defaultZone: http://eureka7001.com:7001/eureka

11.6.4 Create startup class

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

11.6.5 Testing

  • Start 7001
  • Start 8001: -cloud-provider-payment8001
  • Start 9527 gateway
  • Access instructions
    • Before adding gateway - http://localhost:8001/payment/get/1
    • After adding gateway - http://localhost:9527/payment/get/1
    • Both accesses are successful and return the same result.

11.7 Configuring dynamic routing (load balancing)

By default, Gateway will create a dynamic route based on the service list registered in the registration center and forward it based on the path of the microservice name on the registration center, thereby realizing the function of dynamic routing. It was originally written as, but now it is changed to, indicating that the load balancing function of
Gateway uriis http://localhost:8001enabled lb://cloud-payment-service. .
The load balancing uri automatically created by gateway for us in microservices


server:
  port: 9527

spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      routes:
        - id: payment_routh #payment_route    #路由的ID,没有固定规则但要求唯一,建议配合服务名
          uri: lb://cloud-payment-service          #匹配后提供服务的路由地址
          predicates:
            - Path=/payment/get/**         # 断言,路径相匹配的进行路由

        - id: payment_routh2 #payment_route    #路由的ID,没有固定规则但要求唯一,建议配合服务名
          uri: lb://cloud-payment-service          #匹配后提供服务的路由地址
          predicates:
            - Path=/payment/lb/**         # 断言,路径相匹配的进行路由

eureka:
  instance:
    hostname: cloud-gateway-service
  client: #服务提供者provider注册进eureka服务列表内
    service-url:
      register-with-eureka: true
      fetch-registry: true
      defaultZone: http://eureka7001.com:7001/eureka

11.8 Predicate usage

Spring Cloud Gateway's route predicate factory (Route Predicate Factories), the role of the route predicate factory is: if it meets the conditions of the predicate, use the configuration of the route, otherwise it will be ignored. As long as you master this sentence, it will be easier to master the routing predicate factory.

predicate factory
After
Before
Between
Cookie
Header
Host
Method
Path
Query
RemoteAddr

11.8.1 After factory

spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      routes:
        - id: payment_routh #payment_route    #路由的ID,没有固定规则但要求唯一,建议配合服务名
          uri: lb://cloud-payment-service          #匹配后提供服务的路由地址
          predicates:
            - Path=/payment/get/**         # 断言,路径相匹配的进行路由
            - After=2021-08-18T21:49:21.011+08:00[Asia/Shanghai]

It means that it can only be accessed after this time period, otherwise access will be 404. The test address is http://localhost:9527/payment/get/1.
The rest will not be demonstrated. Go to Spring Cloud Gateway-Route Predicate Factories . Check out this article.

11.9 Filter

Routing filters can be used to modify incoming HTTP requests and returned HTTP responses. Routing filters can only specify routes for use.

Spring Cloud Gateway has a variety of built-in routing filters, all of which are generated by the factory class of GatewayFilter to generate
Spring Cloud Gateway's Filter:

  • life cycle:
    • pre
    • post
  • Type (see official documentation for details)
    • GatewayFilter - There are 31 types
    • GlobalFilter - There are 10 types

Commonly used GatewayFilter: AddRequestParameter GatewayFilter
Custom global GlobalFilter:
Introduction to the two main interfaces :

  • GlobalFilter
  • Ordered

What you can do :

  • Global logging
  • Unified gateway authentication

Code example:
If you access the link without the uname parameter, you cannot access the link.
getOrder method: load the filter order. The smaller the return value, the higher the priority order.

@Component
@Slf4j
public class MyLogGateWayFilter implements GlobalFilter,Ordered
{
    
    

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
    {
    
    
        log.info("***********come in MyLogGateWayFilter:  "+new Date());

        String uname = exchange.getRequest().getQueryParams().getFirst("uname");

        if(uname == null)
        {
    
    
            log.info("*******用户名为null,非法用户,o(╥﹏╥)o");
            exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
            return exchange.getResponse().setComplete();
        }

        return chain.filter(exchange);
    }

    @Override
    public int getOrder()
    {
    
    
        return 0;
    }
}

Accessing http://localhost:9527/payment/get/1?uname=ZX is normal.
Accessing the http://localhost:9527/payment/get/1 web page cannot be accessed, and the console prints out the log.

12.Config

12.1 Function

Configuration issues faced by distributed systems

Microservices means splitting the business in a single application into sub-services. The granularity of each service is relatively small, so there will be a large number of services in the system. Since each service requires necessary configuration information to run, a centralized, dynamic configuration management facility is essential.

SpringCloud provides ConfigServer to solve this problem. Each of our microservices has its own application.yml, which can manage hundreds of configuration files...

Insert image description here

what is

SpringCloud Config provides centralized external configuration support for microservices in the microservice architecture. The configuration server provides a centralized external configuration for all environments of different microservice applications.

How to play

SpringCloud Config is divided into two parts : server and client .

  • The server is also called the distributed configuration center. It is an independent microservice application that is used to connect to the configuration server and provide access interfaces for clients to obtain configuration information, encrypt/decrypt information, etc.

  • The client manages application resources and business-related configuration content through the designated configuration center, and obtains and loads configuration information from the configuration center at startup. The configuration server uses git to store configuration information by default, which is helpful. Version management of environment configuration, and configuration content can be easily managed and accessed through git client tools.

What can you do

  • Centrally manage configuration files
  • Different configurations for different environments, dynamic configuration updates, and environment-specific deployment such as dev/test/prod/beta/release
  • Dynamically adjust the configuration during operation. There is no need to write configuration files on the machines where each service is deployed. The service will uniformly pull its own configuration information from the configuration center.
  • When the configuration changes, the service does not need to be restarted to sense the configuration changes and apply the new configuration.
    Expose the configuration information in the form of a REST interface - just refresh it by accessing post/crul...

Integrate configuration with GitHub

Since SpringCloud Config uses Git to store configuration files by default (there are other ways, such as supporting SVN and local files), the most recommended one is Git, and it uses http/https access.

12.2 Server configuration and testing

Corresponding to the Config Server module in the above figure

12.2.1 Github creates configuration file

Fork https://github.com/zzyybs/springcloud-config directly, and then change the uri of yml to the address after forking.

12.2.2 Create ConfigCenterMain3344 module

12.2.3 Create POM, YML, startup class

<?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.atguigu.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-config-center-3344</artifactId>

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

</project>
server:
  port: 3344

spring:
  application:
    name:  cloud-config-center #注册进Eureka服务器的微服务名
  cloud:
    config:
      server:
        git:
          uri: https://github.com/Aerozb/springcloud-config.git #GitHub上面的git仓库名字
          username: github用户名
          password: github密码
        ####搜索目录
          search-paths:
            - springcloud-config
      ####读取分支
      label: master

#服务注册到eureka地址
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7001/eureka

Enable the configuration center annotation @EnableConfigServer

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

12.2.4 Testing

Visit http://127.0.0.1:3344/master/config-dev.yml
and find that the content inside can be obtained

12.3 Client configuration and testing

12.3.1 bootstrap.yml

applicaiton.yml is a user-level resource configuration item
bootstrap.yml is system-level and has a higher priority.

Spring Cloud will create a "Bootstrap Context" as Application Contextthe parent context of the Spring application. During initialization, Bootstrap Contextit is responsible for loading configuration properties from external sources and parsing configurations. The two contexts share one obtained from the outside Environment.

BootstrapProperties have high priority and by default they are not overridden by local configuration. Bootstrap contextand Application Contexthave different conventions, so a new bootstrap.ymlfile was added to ensure separation Bootstrap Contextfrom Application Contextconfiguration.

It is critical to change the application.yml file under the Client module to bootstrap.yml,
because bootstrap.yml is loaded before application.yml. bootstrap.yml has higher priority than application.yml
Insert image description here

12.3.2 Create cloud-config-client-3355 module

12.3.3 Create POM, YML, startup class, access class

<?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.atguigu.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-config-client-3355</artifactId>

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

</project>

bootstrap.yml

server:
  port: 3355

spring:
  application:
    name: config-client
  cloud:
    #Config客户端配置
    config:
      label: master #分支名称
      name: config #配置文件名称
      profile: dev #读取后缀名称   上述3个综合:master分支上config-dev.yml的配置文件被读取http://config-3344.com:3344/master/config-dev.yml
      uri: http://localhost:3344 #配置中心地址

#服务注册到eureka地址
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7001/eureka

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

Visit configuration center

@RestController
@RefreshScope
public class ConfigClientController
{
    
    
    @Value("${config.info}")
    private String configInfo;

    @GetMapping("/configInfo")
    public String getConfigInfo()
    {
    
    
        return configInfo;
    }
}

12.3.3 Testing

First visit the configuration center http://127.0.0.1:3344/master/config-dev.yml to see if it is successful, as follows

config:
  info: master branch,springcloud-config/config-dev.yml version=1

When accessing the client http://localhost:3355/configInfo , the same content is shown above, indicating success.

Successfully implemented client 3355 access to SpringCloud Config 3344 to obtain configuration information through GitHub. Questions can come at any time.

Dynamic refresh problem of distributed configuration

  • Linux operation and maintenance modifies the content of the configuration file on GitHub to make adjustments
  • Refresh 3344 and find that the ConfigServer configuration center responded immediately ( no change in my test )
  • Refreshed 3355 and found that the ConfigClient client did not respond.
  • 3355 There is no change unless you restart or reload
  • It is so difficult that every time operation and maintenance modify the configuration file, the client needs to be restarted?? Nightmare

12.4 Dynamic refresh of client

12.4.1 POM introduces actuator monitoring

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

12.4.2 Modify YML to expose monitoring port

# 暴露监控端点
management:
  endpoints:
    web:
      exposure:
        include: "*"

12.4.3 Modify Controller

Add @RefreshScope

12.4.4 Modify the github config-dev.yml configuration file

12.4.5 Access client

http://localhost:3355/configInfo
found that it still has not changed

12.4.6 Actively initiate a request to notify the client that it has been updated

curl -X POST "http://localhost:3355/actuator/refresh"

The advantage is that you don’t have to restart the client.

12.4.7 Access the client again

Found that the change has been successful

13.Nacos Service Registration and Configuration Center

13.1 Why is it called Nacos?

The first four letters are the first two letters of Naming and Configuration respectively, and the last s is Service.

13.2 What is

  • A dynamic service discovery, configuration management and service management platform that makes it easier to build cloud-native applications.
  • Nacos: Dynamic Naming and Configuration Service
  • Nacos is a combination of registration center + configuration center -> Nacos = Eureka+Config+Bus

13.3 What can you do?

  • Replace Eureka as service registration center
  • Replace Config as service configuration center

13.4 Download, install, start

  1. https://nacos.io/zh-cn/index.html, click V1.XX in the middle to download the version on their page.
  2. Open bin/startup.cmd
  3. Modify the cluster set MODE="cluster"to a single machine set MODE="standalone", otherwise an error will be reported at startup
  4. Run startup.cmd

13.5 Create the service provider cloudalibaba-provider-payment9001 module

13.5.1 Add dependencies to parent POM

			<dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.1.0.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

13.5.2 This POM

<?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.atguigu.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloudalibaba-provider-payment9001</artifactId>

    <dependencies>
        <!--SpringCloud ailibaba nacos -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-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>
    </dependencies>

</project>

13.5.3 YML

Indicates that nacos-payment-provider is registered in nacos: localhost:8848

server:
  port: 9001

spring:
  application:
    name: nacos-payment-provider
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 #配置Nacos地址

management:
  endpoints:
    web:
      exposure:
        include: '*'

13.5.4 Main startup

Use the @EnableDiscoveryClient annotation to register a microservice to the nacos registration center

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

13.5.5 Business class (control layer)

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

    @GetMapping(value = "/payment/nacos/{id}")
    public String getPayment(@PathVariable("id") Integer id)
    {
    
    
        return "nacos registry, serverPort: "+ serverPort+"\t id"+id;
    }
}

13.5.6 Testing

  1. Start cloudalibaba-provider-payment9001
  2. Check the nacos console and find that it has been registered into nacos.Insert image description here
  3. Visit http://localhost:9001/payment/nacos/1 and display the returned information, indicating success.

13.6 Create service provider cloudalibaba-provider-payment9002 to demonstrate load balancing of nacos

The creation steps are the same as 9001

13.7 Create service consumer cloudalibaba-consumer-nacos-order83

13.7.1 POM

<?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.atguigu.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloudalibaba-consumer-nacos-order83</artifactId>

    <dependencies>
        <!--SpringCloud ailibaba nacos -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!--openfeign-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
        <dependency>
            <groupId>com.atguigu.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </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>
    </dependencies>

</project>

13.7.2 yml

server:
port: 83

spring:
application:
name: nacos-order-consumer
cloud:
nacos:
discovery:
server-addr: localhost:8848

13.7.3 Startup class

Pay attention to the annotation, enable openFeign and service discovery

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

13.7.4 PaymentFeignService remote call payment service

@FeignClient("nacos-payment-provider")
public interface PaymentFeignService {
    
    

    @GetMapping(value = "/payment/nacos/{id}")
    public String getPayment(@PathVariable("id") Integer id);
}

13.7.5 Control layer

@RestController
public class OrderNacosController
{
    
    
    @Resource
    PaymentFeignService paymentFeignService;

    @GetMapping(value = "/consumer/payment/nacos/{id}")
    public String paymentInfo(@PathVariable("id") Integer id)
    {
    
    
        return paymentFeignService.getPayment(id);
    }

}

13.7.6 Testing

  1. Start PaymentMain9001, PaymentMain9002, OrderNacosMain83
  2. Continuously visit http://localhost:83/consumer/payment/nacos/13

The return results are as follows:

nacos registry, serverPort: 9001 id13
nacos registry, serverPort: 9002 id13

13.8 Switching between AP and CP modes

C means that the data seen by all nodes at the same time is consistent; and the definition of A is that all requests will receive responses.

When do you choose which mode to use?
Generally speaking,
if there is no need to store service level information and the service instance is registered through nacos-client and can maintain heartbeat reporting, then you can choose AP mode. Current mainstream services such as Spring cloud and Dubbo services are all suitable for AP mode. AP mode weakens consistency for the sake of service possibility, so AP mode only supports registration of temporary instances.

If you need to edit or store configuration information at the service level, then CP is required, and K8S services and DNS services are suitable for CP mode.
CP mode supports the registration of persistent instances. At this time, the Raft protocol is used as the cluster operating mode. In this mode, the service must be registered before registering the instance. If the service does not exist, an error will be returned.

curl -X PUT '$NACOS_SERVER:8848/nacos/v1/ns/operator/switches?entry=serverMode&value=CP'

13.9 Create configuration center cloudalibaba-config-nacos-client3377 Demonstration of obtaining configuration

13.9.1 POM

<?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.atguigu.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloudalibaba-config-nacos-client3377</artifactId>

    <dependencies>
        <!--nacos-config-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
        <!--nacos-discovery-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!--web + actuator-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
    </dependencies>

</project>

13.9.2 bootstrap.yml,application.yml

Nacos is the same as springcloud-config. When initializing the project, you must first pull the configuration from the configuration center. Only
after pulling the configuration can the normal startup of the project be guaranteed.

There is a priority order for loading configuration files in springboot, bootstrap has higher priority than application

bootstrap.yml

server:
  port: 3377

spring:
  application:
    name: nacos-config-client
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 #Nacos服务注册中心地址
      config:
        server-addr: localhost:8848 #Nacos作为配置中心地址
        file-extension: yaml #指定yaml格式的配置

application.yml

spring:
  profiles:
    active: dev # 表示开发环境

13.9.3 Startup class

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

13.9.4 Control layer

Automatically update the configuration through Spring Cloud's native annotation @RefreshScope:

@RestController
@RefreshScope //支持Nacos的动态刷新功能。
public class ConfigClientController
{
    
    
    @Value("${config.info}")
    private String configInfo;

    @GetMapping("/config/info")
    public String getConfigInfo() {
    
    
        return configInfo;
    }
}

13.9.5 Add configuration information in nacos

Insert image description here
In Nacos Spring Cloud, the complete format of dataId is as follows:

${
    
    prefix}-${
    
    spring.profiles.active}.${
    
    file-extension}
  • prefix defaults to the value of spring.application.name, and can also be configured through the configuration item spring.cloud.nacos.config.prefix.
  • spring.profiles.active is the profile corresponding to the current environment. For details, please refer to the Spring Boot documentation. Note: When spring.profiles.active is empty, the corresponding connector - will not exist, and the splicing format of dataId becomes prefix. {prefix}.prefix.{file-extension}
  • file-exetension is the data format of the configuration content, which can be configured through the configuration item spring.cloud.nacos.config.file-extension. Currently only properties and yaml types are supported.

13.9.6 Testing

  1. Visit http://localhost:3377/config/info
  2. It was found that the filled-in configuration was successfully obtained.
  3. Go to nacos to modify the configuration, refresh the link, and find that it has been updated.

14 Sentinel

14.1 Introduction

As microservices become more popular, stability between services and services becomes increasingly important. Sentinel is a traffic management component for distributed, multi-language heterogeneous service architecture. It mainly uses traffic as the entry point, covering traffic routing, traffic control, traffic shaping, circuit breaker degradation, system adaptive overload protection, hot spot traffic protection, etc. Dimension to help developers ensure the stability of microservices.
Insert image description here
Insert image description here

14.2 Start the console

Download the console JAR package.
Start: java -jar sentinel-dashboard-XXX.jar
visit: http://127.0.0.1:8080/The
default account password is. If sentinel
you need to change the port password or something, see the official
Insert image description here
website. These configuration pages will be displayed only when there are requests, which is lazy loading.

14.3 Create module cloudalibaba-sentinel-service8401

14.3.1 POM

<?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.atguigu.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloudalibaba-sentinel-service8401</artifactId>


    <dependencies>
        <!--SpringCloud ailibaba nacos -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!--SpringCloud ailibaba sentinel-datasource-nacos 后续做持久化用到-->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
        </dependency>
        <!--SpringCloud ailibaba sentinel -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <!--openfeign-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!-- SpringBoot整合Web组件+actuator -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>4.6.3</version>
        </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>com.atguigu.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>1.0-SNAPSHOT</version>
            <scope>compile</scope>
        </dependency>

    </dependencies>

</project>

14.3.2 yml

server:
  port: 8401

spring:
  application:
    name: cloudalibaba-sentinel-service
  cloud:
    nacos:
      discovery:
        #Nacos服务注册中心地址
        server-addr: localhost:8848
    sentinel:
      transport:
        #配置Sentinel dashboard地址
        dashboard: localhost:8080
        #默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口
        port: 8719

management:
  endpoints:
    web:
      exposure:
        include: '*'

14.3.3 Main startup

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

14.3.4 Business class FlowLimitController

@RestController
public class FlowLimitController
{
    
    

    @GetMapping("/testA")
    public String testA()
    {
    
    
        return "------testA";
    }

    @GetMapping("/testB")
    public String testB()
    {
    
    
        return "------testB";
    }
}

14.3.5 Start up, access testA, go to the console to view

14.4 Flow control rules

Insert image description here

Insert image description here
Let’s talk about the meaning of options

  1. QPS+direct+fast failure : When the single-machine threshold is set to 3, it means that m only processes 3 requests per second, and the rest will directly return failure.Blocked by Sentinel (flow limiting)

  2. QPS+Warm Up+Fast Failure : The single-machine threshold is set to 10. When warm-up is 5, it means that the threshold is 3 (10/3) in the first 5 seconds from the first request, and then the threshold becomes 10.
    For example: when the flash sale system is turned on, there will be a lot of traffic, which is very likely to kill the system. The preheating method is to protect the system by slowly letting in the traffic and slowly increasing the threshold to the set value. threshold value.

  3. QPS+direct+uniform speed : This method strictly controls the interval time between requests passing, that is, allowing requests to pass at a uniform speed, which corresponds to the leaky bucket algorithm.
    The function of this method is shown in the figure below:
    Insert image description hereThis method is mainly used to handle intermittent burst traffic, such as message queues. Imagine a scenario where a large number of requests arrive in a certain second and are idle for the next few seconds. We hope that the system can gradually process these requests during the next idle period instead of directly rejecting them in the first second. Superfluous request.
    Just let the requests be queued and processed one by one.

  4. QPS+association+fast failure : Insert image description here
    means that when accessing testB reaches the threshold, accessing testA at the same time will directly return failure information.

14.5 Downgrade rules

14.5.1 Definition of terms

Insert image description here

RT (average response time, seconds, calculation formula = total request time/number of requests) The
average response time exceeds the threshold and the requests passed within the time window >=5, the downgrade is triggered after both conditions are met at the same time.
The circuit breaker is closed after the window period.
The maximum RT is 4900 (larger ones need to pass -Dcsp.sentinel.statistic.max.rt=XXXX to take effect)

Abnormal ratio (second level)
QPS >= 5 and the abnormal ratio (second level statistics) exceeds the threshold, trigger downgrade; after the time window is over, downgrade is turned off

When the number of exceptions (minute-level)
exceeds the threshold, downgrade is triggered; after the time window is over, downgrade is turned off.

14.5.2 Description

Sentinel circuit breaker downgrade will limit the call of this resource when a resource in the call link is in an unstable state (such as call timeout or an increase in abnormal ratio), so that the
request fails quickly and avoids affecting other resources and causing degradation. Connection error.

When a resource is downgraded, calls to the resource will be automatically disconnected within the next downgrade time window (the default behavior is to throw a DegradeException).

14.5.3 RT (second-level average response time, calculation formula = total request time/number of requests)

Insert image description here

Insert image description here
test

@GetMapping("/testD")
public String testD()
{
    
    
    //暂停几秒钟线程
    try {
    
     TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) {
    
     e.printStackTrace(); }
    log.info("testD 测试RT");
    return "------testD";
}

Insert image description here
Insert image description here
According to the above configuration,

There are always 10 threads (more than 5) calling testD in one second. We hope that this task will be processed in 200 milliseconds.
If it is not completed within 200 milliseconds, the circuit breaker will be opened in the next 1 second time window. (Fuse tripped) The microservice is unavailable, the fuse tripped and the power was cut off.

Later, I stopped jmeter, and there was no such large number of visits. The circuit breaker was turned off (the fuse was restored), and the microservices were restored OK.

14.5.4 Abnormal proportions

Insert image description here
Insert image description here

@GetMapping("/testD")
public String testD()
{
    
    
    log.info("testD 测试RT");
    int age = 10/0;
    return "------testD";
}

Insert image description here
Insert image description here
According to the above configuration, if you access it alone, an error will be reported once (int age = 10/0), and an error will occur once you adjust it.
After opening jmeter, you can directly send requests with high concurrency, and multiple calls will meet our configuration conditions.
The circuit breaker is turned on (the fuse is tripped), the microservice is no longer available, and the error is no longer reported but the service is degraded.

14.5.5 Exception numbers

Insert image description here
Insert image description here

14.6 Hotspot key current limit

14.6.1 What is a hotspot?

Hotspots are frequently accessed data. Many times we want to count or limit the TopN data with the highest access frequency in a certain hotspot data, and perform current limiting or other operations on their access.
Insert image description here

14.6.2 Use

The cover-up method
is divided into system default and customer-defined. In the
previous case, after the outflow limit problem, the default prompt of the Sentinel system was used: Blocked by Sentinel (flow limiting).
Can we customize it? Similar to hystrix, a certain method If something goes wrong, find the corresponding downgrade method?
Conclusion
From HystrixCommand to @SentinelResource

    @GetMapping("/testHotKey")
    @SentinelResource(value = "testHotKey", blockHandler = "deal_testHotKey")
    public String testHotKey(@RequestParam(value = "p1", required = false) String p1,
                             @RequestParam(value = "p2", required = false) String p2) {
    
    
        //int age = 10/0;
        return "------testHotKey";
    }

    public String deal_testHotKey(String p1, String p2, BlockException exception) {
    
    
        return "------deal_testHotKey,o(╥﹏╥)o";  //sentinel系统默认的提示:Blocked by Sentinel (flow limiting)
    }

The current limiting mode only supports QPS mode and is hard-coded. (This is called a hotspot)
@SentinelResourceThe method parameter index of the annotation, 0 represents the first parameter, 1 represents the second parameter, and so on. The
single-machine threshold and the statistical window duration indicate that if the window time exceeds the threshold, the flow will be limited.
The above screenshot shows that if the first parameter has a value, the QPS per second is 1. If it exceeds the current limit, the dealHandler_testHotKey support method is called after the current limit.

Accessing http://localhost:8401/testHotKey?p1=abc will fail if it reaches the QPS threshold.
However, concurrent access to http://localhost:8401/testHotKey?p2=abc will not work because it is not in the configuration. The configuration is written is the 0th parameter

14.6.3 Special cases

After more than 1 second, the current limit will be limited immediately after reaching the threshold 1. We expect that when the p1 parameter is a special value, its current limit value will be different from usual. If the value of p1 is equal to 5, its current limit value will be different. The threshold can reach 3.
Insert image description here
Visit http://localhost:8401/testHotKey?p1=5 . When p1 is equal to 5, the threshold becomes 200.
Visit http://localhost:8401/testHotKey?p1=3 . When p1 is not equal to 5. , the threshold is set to 3

14.7 @SentinelResource

Previously @SentinelResource, to customize the returned exception information, you need to write the corresponding processing method under each class, which is very inconvenient, as follows

  1. The system default does not reflect our own business requirements.
  2. According to the existing conditions, our customized processing method is coupled with the business code, which is not intuitive.
  3. Adding a cover to each business method will increase the code bloat.
  4. A globally unified approach is not reflected.

Solved as follows

14.7.1 Customer-defined current limiting processing logic

blockHandler : Customize the sentinel console violation configuration, fill in the processing method

/byResourceSpecify the handleException method to handle violation exceptions (must be written in this class)
/rateLimit/customerBlockHandlerSpecify the handlerException2 method of the CustomerBlockHandle class to handle
the business class

@RestController
public class RateLimitController {
    
    
    @GetMapping("/byResource")
    @SentinelResource(value = "byResource", blockHandler = "handleException")
    public CommonResult byResource() {
    
    
        return new CommonResult(200, "按资源名称限流测试OK", new Payment(2020L, "serial001"));
    }

    public CommonResult handleException(BlockException exception) {
    
    
        return new CommonResult(444, exception.getClass().getCanonicalName() + "\t 服务不可用");
    }

    @GetMapping("/rateLimit/byUrl")
    @SentinelResource(value = "byUrl")
    public CommonResult byUrl() {
    
    
        return new CommonResult(200, "按url限流测试OK", new Payment(2020L, "serial002"));
    }


    @GetMapping("/rateLimit/customerBlockHandler")
    @SentinelResource(value = "customerBlockHandler",
            blockHandlerClass = CustomerBlockHandler.class,
            blockHandler = "handlerException2")
    public CommonResult customerBlockHandler() {
    
    
        return new CommonResult(200, "按客戶自定义", new Payment(2020L, "serial003"));
    }
}

Custom failure handling class

public class CustomerBlockHandler {
    
    
    public static CommonResult handlerException(BlockException exception) {
    
    
        return new CommonResult(4444, "按客戶自定义,global handlerException----1");
    }

    public static CommonResult handlerException2(BlockException exception) {
    
    
        return new CommonResult(4444, "按客戶自定义,global handlerException----2");
    }
}

Sentinel console configuration:
Insert image description here
Visit http://127.0.0.1:8401/rateLimit/customerBlockHandler/ . When the QPS threshold is exceeded, it is found that custom exception information is returned.

14.8 Service circuit breaker function

14.8.1 Create provider cloudalibaba-provider-payment9003/9004 module

See the git source code for the code, I won’t write it here.

14.8.2 Create consumer cloudalibaba-consumer-nacos-order84

@SentinelResourceThe meaning of the attributes in

  • fallback : used to provide fallback processing logic when an exception is thrown. The fallback function can handle all types of exceptions (except exception types excluded in exceptionsToIgnore).
    There are requirements for the fallback function location, and it must be in the same class as the original method, but in actual requirements, we need to place it in other classes. @SentinelResource provides a Class object that specifies the corresponding class through fallbackClass, and adds a static function, otherwise it cannot be parsed.
  • exceptionsToIgnore : When both fallback and blockHandler are configured, visit http://localhost:84/consumer/fallback/1

Fallback manages Java running exceptions. blockHandler manages sentinel's console violation configuration.
If both blockHandler and fallback are configured, only the blockHandler processing logic will be entered when a BlockException is thrown due to current limiting downgrade.

They are all used for ordinary requests, @FeignClientand there is also an fallbackattribute in them, which is also used to handle exceptions.

@RestController
@Slf4j
public class CircleBreakerController {
    
    
    public static final String SERVICE_URL = "http://nacos-payment-provider";

    @Resource
    private RestTemplate restTemplate;
    //==================OpenFeign
    @Resource
    private PaymentService paymentService;

    @RequestMapping("/consumer/fallback/{id}")
    //@SentinelResource(value = "fallback") //没有配置
//    @SentinelResource(value = "fallback",fallback = "handlerFallback") //fallback只负责业务异常
//    @SentinelResource(value = "fallback",blockHandler = "blockHandler") //blockHandler只负责sentinel控制台配置违规
    @SentinelResource(value = "fallback", fallback = "handlerFallback", blockHandler = "blockHandler",
            exceptionsToIgnore = {
    
    IllegalArgumentException.class})
    public CommonResult<Payment> fallback(@PathVariable Long id) {
    
    
        CommonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/" + id, CommonResult.class, id);

        if (id == 4) {
    
    
            throw new IllegalArgumentException("IllegalArgumentException,非法参数异常....");
        } else if (result.getData() == null) {
    
    
            throw new NullPointerException("NullPointerException,该ID没有对应记录,空指针异常");
        }

        return result;
    }

    //本例是fallback
    public CommonResult handlerFallback(@PathVariable Long id, Throwable e) {
    
    
        Payment payment = new Payment(id, "null");
        return new CommonResult<>(444, "兜底异常handlerFallback,exception内容  " + e.getMessage(), payment);
    }

    //本例是blockHandler
    public CommonResult blockHandler(@PathVariable Long id, BlockException blockException) {
    
    
        Payment payment = new Payment(id, "null");
        return new CommonResult<>(445, "blockHandler-sentinel限流,无此流水: blockException  " + blockException.getMessage(), payment);
    }

    @GetMapping(value = "/consumer/paymentSQL/{id}")
    public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id) {
    
    
        return paymentService.paymentSQL(id);
    }
}

When accessing http://localhost:84/consumer/paymentSQL/1, you use fegin to call provider 9003/9004, which is added fallback. When only 9003 is enabled, accessing http://localhost:84/consumer/paymentSQL/1 is normal.

At this time, if the 9003 microservice provider is deliberately closed and accessed again, it will be automatically downgraded and will not be consumed. This is to call the method in PaymentFallbackService.

If not added fallback, the error page will be returned directly.
Note: If you want this property to take effect, you must add the Sentinel framework (any fuse framework will do). Otherwise, it will be invalid. You also need to add configuration.

# 激活Sentinel对Feign的支持
feign:
  sentinel:
    enabled: true
@FeignClient(value = "nacos-payment-provider", fallback = PaymentFallbackService.class)
public interface PaymentService {
    
    
    @GetMapping(value = "/paymentSQL/{id}")
    public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id);
}
@Component
public class PaymentFallbackService implements PaymentService {
    
    
    @Override
    public CommonResult<Payment> paymentSQL(Long id) {
    
    
        return new CommonResult<>(44444, "服务降级返回,---PaymentFallbackService", new Payment(id, "errorSerial"));
    }
}

14.9 Rule persistence

14.9.1 What is

We first need to know: after configuring the rules in Sentinel Dashboard and restarting the application, they will be lost. Therefore, in the actual production environment, it is necessary to configure the persistence implementation of the rules. Sentinel provides a variety of different data sources to persist the rule configuration, including file, redis, nacos, zk.

This requires the rule management and push function of Sentinel Dashboard: centralized management and push rules. sentinel-core provides API and extension interfaces to receive information. Developers need to choose a reliable way to push rules based on their own environment; at the same time, rules are best managed centrally in the console.

14.9.2 How to play

Persist the current limiting configuration rules into Nacos. As long as you refresh a rest address
of 8401, the flow control rules on the sentinel console can be seen. As long as the configuration in Nacos is not deleted, the flow control rules on sentinel on 8401 will continue to be valid.

14.9.3 Configuration steps

1. Add dependencies

<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
</dependency>

2. Add Nacos data source configuration

spring:
  application:
    name: cloudalibaba-sentinel-service
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 #Nacos服务注册中心地址
    sentinel:
      transport:
        dashboard: localhost:8081 #配置Sentinel dashboard地址
        port: 8719
      datasource: #Nacos数据源配置
        ds1:
          nacos:
            server-addr: localhost:8848
            dataId: cloudalibaba-sentinel-service
            groupId: DEFAULT_GROUP
            data-type: json
            rule-type: flow

3. Add configuration on nacos

 
[
    {
    
    
        "resource": "/rateLimit/byUrl",
        "limitApp": "default",
        "grade": 1,
        "count": 1,
        "strategy": 0,
        "controlBehavior": 0,
        "clusterMode": false
    }
]

resource:资源名称;
limitApp:流控针对的调用来源,若为 default 则不区分调用来源,默认值default
grade:阈值类型,0表示线程数,1表示QPS;
count:单机阈值;
strategy:流控模式,0表示直接,1表示关联,2表示链路;
controlBehavior:流控效果,0表示快速失败,1表示Warm Up,2表示排队等待;
clusterMode:是否集群。

Insert image description here

14.9.4 Inspection

Start 8401, call http://localhost:8401/rateLimit/byUrl multiple times , refresh sentinel and find that the business rules are there.
Insert image description here
Stop the application and find that they are gone.
Insert image description here
Start the access again and there are them.

Guess you like

Origin blog.csdn.net/Fire_Sky_Ho/article/details/120363127