Spring-Cloud-Alibaba的搭建到开发

345 阅读4分钟

一,spring-cloud搭建开发环境相关:

搭建springbot工程所需的步骤

pom.xml的导包
配置文件
主启动类

1,创建一个空的父工程,

2,在fileEncoding里设置为相应的编码需求,(utf-8),

3,Maven设置为自己的本地镜像仓库,

4,搭建父工程:

<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/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>


  <groupId>com.chenshi</groupId>
  <artifactId>spring-cloud-parent</artifactId>
  <version>1.0.0</version>
    <packaging>pom</packaging>

    <modules>
        <module>eureka-provider</module>
        <module>eureka-consumer</module>
        <module>eureka-server</module>
    </modules>

    <!--spring-boot环境-->
   <parent>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-parent</artifactId>
     <version>2.2.11.RELEASE</version>
   </parent>
    
    <!--配置cloud版本-->
    <properties>
        <spring-cloud.version>Hoxton.SR12</spring-cloud.version>
    </properties>

    <!--依赖管理-->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>


</project>

5,根据实际情况搭建相应的子工程

二,eureka注册中心相关:

注册中心的核心功能:

1,服务注册,

2,服务发现,

3,服务维护

  • eureka微服务实现方式(三步走):

1, 在pom中导入eureka依赖,搭建eureka-server:

<?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>

    <parent>
        <groupId>com.chenshi</groupId>
        <artifactId>spring-cloud-parent</artifactId>
        <version>1.0.0</version>
    </parent>

    <artifactId>eureka-server</artifactId>

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

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

    </dependencies>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

</project>

2,在pom.xml文件中导入依赖

#在yml文件配置eureka服务
eureka:
  instance:
    hostname: localhost
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/ #注册中心的地址
spring:
  application:
    name: eureka-provider #给当前的(微服务)application取名字,方便在注册中心方便管理

3,在主启动类中加入注解:

package com.chenshi;

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


@SpringBootApplication
@EnableEurekaClient//启动eureka服务
public class ProviderApplication {
    public static void main(String[] args) {
        SpringApplication.run(ProviderApplication.class,args);
    }

}

三,eureka部署相关:

  • 生产端或者消费端的部署相关:

instance:	
	#instance内容:
	prefer-ip-address: true #将自己的ip地址注册到eureka上
	ip-address: 127.0.0.1 #这个ip地址为多少,
	instance-id: ${eureka.instance.hostname}:${spring.application.name}:${server.port}#该服务在注册中心的名字,
	lease-renewal-interval-in-seconds: 30 #每30秒发送一次心跳,向注册中心确定存活
	lease-expiration-duration-in-seconds: 90 #如果90秒没有发送心跳就挂掉,则注销服务
	#如果实现了高可用集群配置,不能用localhost而是配置的域名,有几台机器就写几台机器上,消费端和生产端都需要。
	defaultZone: http://eureka-server1:8762/eureka,http://eureka-server2:8763/eureka 
	
client:
	#client内容:
	registry-with-eureka: true #是否将自己的路径注册到eureka上,默认为true	
	fetch-registry: true #是否需要从eureka中抓取数据,供消费端使用
	
  • eureka服务器的部署相关:

server:
	#server内容:
	enable-self-preservation : true #是否开启自我保护模式,默认开启
    eviction-interval-timer-in-ms: 120000 #如果超过这个时间才算彻底过期,,默认是90000毫秒
    
  #仪表板:
  dashboard:
    enabled: true
    path: /

四,eureka高可用集群配置:

高可用本质: 就是启动多个服务,以防单一个挂掉,导致整个服务挂掉

  • eureka高可用实现步骤:

1,搭建环境:

第一台机器:

server:
  port: 8762

eureka:
  instance:
    hostname: eureka-server1
    client:
      service-url:
        defaultZone: http://eureka-server2:8762/eureka #eureka服务端地址
      register-with-eureka: false #是否将自己的路径注册到eureka上,服务端不需要,客户端需要。
      fetch-registry: false #是否需要从eureka抓取路径,服务端不需要,客户端需要。

spring:
  application:
    name: eureka-server-ha #服务名可以一样


第二台机器:

server:
  port: 8763

eureka:
  instance:
    hostname: eureka-server2
    client:
      service-url:
        defaultZone: http://eureka-server1:8762/eureka  #eureka服务端地址
      register-with-eureka: false #是否将自己的路径注册到eureka上,服务端不需要,客户端需要。
      fetch-registry: false #是否需要从eureka抓取路径,服务端不需要,客户端需要。

spring:
  application:
    name: eureka-server-ha #服务名可以一样


2,让这几台机器相互注册对方,

3,启动这几台机器

本地修改hosts文件,添加eureka域名,

windows路径:C:\Windows\System32\drivers\etc\hosts

五,nacos注册中心相关:

分布式和微服务的区别:

​ 微服务:是指系统架构的一种设计方式,将复杂的业务拆分成多个微小的服务,让这些服务可以单独运行和部署。

​ 分布式:是指系统的部署方式,将同一个服务拆分部署到多台机器上,用于分摊单台机器的负载压力,一般是采用集群,主备来部署

共同点:分布式和微服务都尤其注重一致性和负载均衡

  • 什么是Naocs:

nacos = eureka + config + bus

代替Eureka做服务中心,代替config做配置中心。

1,服务端配置详情:

  • spring-nacos搭建环境:

1,下载nacos服务,在nacos.io前往 官方文档快速开始查看最新nacos版本以及下载。

2,下载解压压缩包之后,执行startup命名启动nacos服务。

#单机模式启动
startup.cmd -m standalone

#关闭nacos服务
shutdown.cmd

3,启动nacos服务之后,前往控制台:http://192.168.28.1:8848/nacos/index.html ,如果有账户密码即默认都是nacos

  • spring-cloud搭建环境:

1,搭建父工程:

<?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>

    <!--spring-boot版本一定要在2.6以上-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.17</version>
    </parent>

    <groupId>com.chenshi</groupId>
    <artifactId>spring-cloud-alibaba</artifactId>
    <version>1.0.0</version>
    <packaging>pom</packaging>
    
    <!--子类-->
    <modules>
        <module>nacos-provider8000</module>
    </modules>

    <!--依赖控制-->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2021.0.1.0</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
			
             <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2021.0.1.0</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

        </dependencies>
    </dependencyManagement>


    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

</project>

2,子工程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">
    <modelVersion>4.0.0</modelVersion>
    <!--继承父工程,实现版本统一-->
    <parent>
        <groupId>com.chenshi</groupId>
        <artifactId>spring-cloud-alibaba</artifactId>
        <version>1.0.0</version>
    </parent>

    <artifactId>nacos-provider8000</artifactId>

    <!--导入相关依赖-->
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
	    <!--导入spring-cloud-nacos依赖-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

    </dependencies>



    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

</project>

3,yml文件:

server:
  port: 8000

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

4,搭建三层架构,实现后端接口(模拟):

package com.chenshi.controller;

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.RequestMapping;
import org.springframework.web.bind.annotation.RestController;


@RestController
@RequestMapping("/goods")
public class GoodsController {

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

    @GetMapping("/findById/{id}")
    public String findById(@PathVariable("id") Integer id){
        //模拟业务逻辑
        return "nacos-provider.port:" + serverPort + ",: id:" + id;
    }
}

5,重复再搭建一个nacos-provider8001,并且使他们application.name不变就能实现在一个集群内方便管理。

2,消费端配置详情:

  • 首先要搭建一个消费端框架:

1,由于spring-cloud-alibaba完全脱离了spring-cloud-starter-netflix-ribbon所以加载依赖要排除掉,

2,导入loadbalancer依赖。

<?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>

    <parent>
        <groupId>com.chenshi</groupId>
        <artifactId>spring-cloud-alibaba</artifactId>
        <version>1.0.0</version>
    </parent>

    <artifactId>nacos-consumer9000</artifactId>

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

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
		<!--导入loadbalancer依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
        </dependency>

    </dependencies>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

</project>

3,消费端yml文件:

server:
  port: 9000

spring:
  application:
    name: nacos-consumer
  cloud:
    loadbalancer:
      ribbon:
        enabled: false
    nacos:
      discovery:
        server-addr: localhost:8848


        

4,主启动类:

package com.chenshi;

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


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

5,配置类:

package com.chenshi.config;

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


@Configuration
public class RestTemplateConfig {

    @Bean
    @LoadBalanced//ribbon 负载均衡的客户端
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}

6,搭建三层架构,最后调用服务端接口(模拟代码):

package com.chenshi.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;


@RestController
@RequestMapping("/order")
public class OrderController {

    @Autowired RestTemplate restTemplate;

    @GetMapping("/add/{id}")
    public String add(@PathVariable("id") Integer id){
        //业务逻辑
        String url = "http://nacos-provider/goods/findById" + id;
        return restTemplate.getForObject(url, String.class);
    }
}

六,使用feign调用微服务:

1,导入相关依赖

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

2,在启动类上加上注解开启 Feign功能

@SpringBootApplication
@EnableDiscoveryClient//开启服务发现功能
@EnableFeignClients//开启Feign功能
public class NacosConsumer9001App {
    public static void main(String[] args) {
        SpringApplication.run(NacosConsumer9001App.class,args);
    }
}

3,创建一个Feign接口,用于调用服务

package com.chenshi.feign;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

//写入服务端的application.name
@FeignClient("nacos-provider")
public interface GoodsFeign {
	
    @GetMapping("/order/findById/{id}")
    String findById(@PathVariable("id")Integer id);

}

4,controller层,注入Feign,并调用该接口

package com.chenshi.controller;

import com.chenshi.feign.GoodsFeign;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;


@RestController
@RequestMapping("/order")
public class OrderController {

    @Resource RestTemplate restTemplate;

    @Resource GoodsFeign goodsFeign;

    @GetMapping("/add2/{id}")
    public String add2(@PathVariable("id")Integer id){
        //业务逻辑
        return goodsFeign.findById(id);
    }

}

七,nacos配置中心相关:

1,导入相关依赖

<?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>
    <parent>
        <groupId>com.chenshi</groupId>
        <artifactId>spring-cloud-alibaba</artifactId>
        <version>1.0.0</version>
    </parent>

    <artifactId>nacos-client7777</artifactId>

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

        <!--配置中心客户端-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>

        <!--和nacos相连接-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        
        <!--导入bootstap相关依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bootstrap</artifactId>
        </dependency>
    </dependencies>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

</project>

2,application.yml配置文件:

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

3,bootstrap.yml配置文件:

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

4,主启动类:

@SpringBootApplication
@EnableDiscoveryClient//开启服务发现客户端
public class NacosClient7777App {
    public static void main(String[] args) {
        SpringApplication.run(NacosClient7777App.class, args);
    }
}

5,在nacos面板里新建配置并发布:

${prefix}-${spring.profiles.active}.${file-extension}#DataId的标准格式
nacos-config-client-dev.yaml
{名字}-{环境}.{文件类型}

6,在需要刷新配置的地方加入自动刷新注解:

package com.chenshi.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/config")
@RefreshScope//开启自动刷新功能
public class ConfigClientController {
    
    //从nacos配置中心取的值
    @Value("${name}")
    String name;

    @GetMapping("/name")
    public String getName() {
        return name;
    }
}

7,nacos配置中心的值一改变访问的服务也会立即随着改变,相当于bus

image-20240122163119676.png

8,N G D/S规则的使用

ngd.jpg

八, nacos集群和持久化配置:

目的:将nacos本身的derby-data数据库切换存储到MySQL数据库中,实现多个nacos可以同时使用一个数据库。

  • 单机模式:

1,在nacos目录中找到如下文件

mysql-schema.sql

2,在dbeaver可视化工具中创建一个nacos数据库,nacos_devtest再将 mysql-schema.sql 文件放入数据库执行:

3,修改conf/application.properties文件,增加支持mysql数据源配置,添加mysql数据源的url、用户名和密码。

  • 集群模式:

集群需要3台或以上的nacos机器才能组成一个集群。

1,使用虚拟机搭建nacos环境

九,sentinel的使用相关:

1,sentinel的控制台下载

Release v1.8.7 · alibaba/Sentinel · GitHub

2,在cmd控制台中写入,启动运行jar包

java -jar sentinel-dashboard-1.8.7.jar

3,搭建sentinel的环境,新建模块(导入依赖)

<?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>
    <parent>
        <groupId>com.chenshi</groupId>
        <artifactId>spring-cloud-alibaba</artifactId>
        <version>1.0.0</version>
        <relativePath>/pom.xml</relativePath>
    </parent>

    <artifactId>cloud-sentinel-service8000</artifactId>

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

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>

    </dependencies>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

</project>

4,application.yml配置详细:

server:
  port: 8000

spring:
  application:
    name: cloud-sentinel-service
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
    sentinel:
      transport:
        dashboard: localhost:8080
        port: 8719 # sentinel默认8719端口,会自动扫描是否占用,占用会向后+1直到找到未被占用的端口

5,主启动类:

package com.chenshi;

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

/**
 *
 * @author chenyq
 * @date 2024/1/29
 */
@SpringBootApplication
@EnableDiscoveryClient
public class SentinelService8000App {
    public static void main(String[] args) {
        SpringApplication.run(SentinelService8000App.class, args);
    }
}

6,启动端口,

​ 由于sentinel是懒加载策略,需要调用接口才能加载到sentinel控制台。

​ 规则的配置是热加载,无需重启服务即可修改规则。

1,流控规则:

7,流控规则:

簇点电路里可以配置,流控熔断, 热点授权

在新增流控规则中有以下配置信息可供配置:

  • 资源名:

    来访问的路径

  • 针对来源:

    默认为:default,可以指定特定的来源来源进行流控。

  • 阈值类型:

    QPS:每秒请求量

    并发线程数:达到某个线程数进行限流

  • 单机阈值:

    阈值/s

  • 是否集群:

    true/false

  • 流控模式:

    直接,该资源名到达阈值,直接访问失败

    关联:列如A关联B,A或B访问失败都会导致任意一方无法访问。

    链路:具体给某个链路上的资源限流,列如:下单操作goodsService限流,减库存操作goodsService不进行限流。

  • 流控效果:

    快速失败:直接访问失败。

    Warm Up: 冷启动,默认为QPS/3 及为 3,当达到预热时间,3/s逐渐升至阈值/s。

    排队等待:让请求匀速访问,列如每10000ms执行一次,相当于一个消息队列

    PS: QPS阈值 >= 2时,排队等待才会生效,目前匀速排队不支持QPS > 1000 20240130

  • 几种流控情况:

1,QPS,直接,快速失败:访问端口时当QPS大于阈值,直接访问失败。

​ 2,QPS,关联,快速失败:访问端口时当资源A失败,B也会无法访问,当B失败时,A也会访问失败。

3,并发线程,直接:访问端口时当并发线程到达阈值时,再次访问都会被直接阻拦。

​ 4,QPS,链路,快速失败:当入口资源URL访问超过阈值后,该资源名也会一起失效无法访问。

5,QPS,直接,Warm Up:假设 设置QPS阈值为10,当冷启动达到5s,接口访问从原先的3/s,到达10/s。

8,在service层, 里面的方法加上注解 @SentinelResource即被视为入口资源。

package com.chenshi.service;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import org.springframework.stereotype.Service;
/**
 *
 * @author chenyq
 * @date 2024/1/29
 */

@Service
public class GoodsService {
    
    @SentinelResource("querygoods")
    public void query(){
        System.out.println("查询商品");
    }
}

9,配置文件关闭收敛URL

    sentinel:
      transport:
        dashboard: localhost:8080
        port: 8719 # sentinel默认8719端口,会自动扫描是否占用,占用会向后+1直到找到未被占用的端口
      web-context-unify: false #关闭收敛URL

2,熔断降级:

熔断降级作为保护自身的手段,避免局部不稳定导致整体的雪崩,通常在客户端(调用端)进行配置。

  • 资源名:

    访问的接口

  • 熔断策略:

    慢调用比列:在统计时长内,请求数量 > 最小请求数,并且慢调用比例 > 阈值,则熔断器生效。

    异常比列:在统计时长内,请求数量 > 设置的最小请求数量,并且异常的比例 > 阈值,则熔断器生效。

    异常数

  • 最大RT:

    Round Trip Time(相应时间)。

  • 比例阈值:

    比例阈值范围为:[0.0,1.0],例如0.5 为 50%。

  • 熔断时长:

    保险的熔断持续多久

  • 最小请求数:

    设置一个应该达到最小的请求数量,大于这个数量保险丝就会勘测是否熔断。

  • 统计时长:

    在这个时长之间,就会到达熔断策略例如1000ms内。

  • 几种熔断情况(例子):

1,慢调用,最大RT:500,阈值:0.5,熔断时长:1s,最小请求数:6,统计时长1000ms;

​ 在统计时长1000ms内最小请求数:6 有0.5(50%)的比率失败,及熔断器生效,时长为1s。

2,异常比例,比例阈值:0.2,熔断时长:2s,最小请求数:5,统计时长1000ms;

​ 在统计时长1000ms内最小请求数:5有0.2(20%)的异常,及熔断器生效,时长为2s。

3,异常数,异常数:2,熔断时长:5s,最小请求数:6,统计时长1000ms;

​ 在统计时长1000ms内最小请求数:6有 2次异常错误,及熔断器生效,时长为5s;

3,热点参数:

经常被访问的数据,可以是对商品访问频次最好的TOP数据,也可以是用户频繁访问的数据,来进行限流。

1,pom文件中导入依赖:

		<!--热点参数限流-依赖-->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-parameter-flow-control</artifactId>
            <version>1.8.6</version>
        </dependency>

2,controller层代码:

/*热点参数限流*/
@GetMapping("/order")//问号传参
@SentinelResource(value = "hotKey")
public String order(@RequestParam(value = "goodsId",required = false) String goodsId,
                    @RequestParam(value = "userId",required = false) String userId){
    //业务逻辑
    return "用户下单: success";
}

3,热点规则的限流模式,目前只有QPS模式,

  • 几种热点参数限流情况(例子):

1,QPS,参数索引(从0开始):0,阈值:1,统计窗口时间:1s; ps:该参数为源代码中的参数索引为准,而非用户访问的参数索引

​ 对传入参数0限流,访问 > 阈值 1,则熔断器生效,1s;

4,自定义回显内容,代码如下:

/*热点参数限流*/
@GetMapping("/order")//问号传参
@SentinelResource(value = "hotKey",blockHandler = "orderBlock")//一旦出错,给前端页面返回一个blockHandler
public String order(@RequestParam(value = "goodsId",required = false) String goodsId,
                    @RequestParam(value = "userId",required = false) String userId){
    //业务逻辑
    return "用户下单: success";
}

/*自定义回显内容*/
public String orderBlock(@RequestParam(value = "goodsId",required = false) String goodsId,
                         @RequestParam(value = "userId",required = false) String userId, BlockException e){
    //以形参方式传入blockException,日后记录报错日志。
    return "用户: + userId +下单失败,请稍后重试";
}

ps:自定义回显内容只会回显sentinel自身的错误,代码中的业务错误并不会调用该回显。

5,热点参数例外情况:

例如在商品秒杀情况下,为某个参数单独设置一个阈值。

  • 热带参数列外情况(例子):

1,参数索引为 0 的情况,参数类型 string,参数值:99,限流阈值:1000;

​ 访问该地址时,当索引为 0 的参数 == 99,限流阈值从原来的10,会改变为1000;

4,系统自适应:

结合应用的load,cpu使用率,总体平均RT,入口QPS和并发线程等几个维度的监控指标,让系统保证最大吞吐量的同时,保证系统的稳定性。

  • LOAD:

    仅对 Linux/Unix-like 机器生效):系统的 load1 作为启发指标,进行自适应系统保护。当系统 load1 超过设定的启发值,且系统当前的并发线程数超过估算的系统容量时才会触发系统保护(BBR 阶段)。系统容量由系统的 maxQps * minRt 估算得出。设定参考值一般是 CPU cores * 2.5

  • RT:

    平均 RT:当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。

  • 线程数:

    并发线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。

  • 入口QPS:

    入口 QPS:当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。

  • CPU使用率:

    CPU usage(1.5.0+ 版本):当系统 CPU 使用率超过阈值即触发系统保护(取值范围 0.0-1.0),比较灵敏。


6,@SentinelResource注解相关:

1,value = "{resouceName}":

​ 因为在sentinel控制面板中资源名都是以order/add/vip/goodsId/1的形式,为了方便辨识在value中写入自定义的资源名。

2,blockHandler = "{methodName}":

​ 创建一个blockHandler方法名,当触发blockHandler后,返回一个自定义的回显内容。

3,blockHandlerClass = {class对象}

/*减库存*/
@GetMapping("/resume")//问号传参
@SentinelResource(value = "resume",blockHandlerClass = CommonBlockHandler.class,blockHandler = "blockHandler0")//
public String resume(@RequestParam(value = "goodsId",required = false) String goodsId){
    //业务逻辑
    //int a = 1 / 0;
    return "减库存成功: success";
}

4,一个blockHandler的公共返回类。

ps:blockHanlder的方法一定要是 static 修饰的

package com.chenshi.ExceptionHandler;

import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.springframework.web.bind.annotation.RequestParam;

//一个公共的sentinel错误回显类;
public class CommonBlockHandler {
	//根据接口的不同,形参要和调用接口保持一致
    public static String blockHandler0(@RequestParam(value = "goodsId",required = false) String goodsId,BlockException e){
        //记录报错日志

        //给用户回显一个自定义内容;
        return "系统出错了,请稍后重试";
    }
	//没有形参则只需要一个BlockException e的形参;
    public static String blockHandler1(BlockException e){
        //记录报错日志

        //给用户回显一个自定义内容;
        return "系统出错了,请稍后重试";
    }

}

5,服务降级:

1,熔断/限流:微服务自己限流,使其不可用。

2,降级:调用方,提供方出错异常,需要返回给用户一个友好对象。

3,搭建3个微服务工程使其相互调用。

4,一个商品不可能id < 0 ,这属于业务逻辑出错所以需要对其服务降级,使用@sentinelResource注解的: fallback

package com.chenshi.controler;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.chenshi.domain.Goods;
import com.chenshi.exception.BlockHandler;
import com.chenshi.exception.FallbackHandler;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;

@RestController
@RequestMapping("/order")
public class OrderController {

    @Resource RestTemplate restTemplate;

    @GetMapping("/add/{id}")
    //回显的blockHandler方法必须是static修饰的
    //@SentinelResource(value = "order",blockHandlerClass = BlockHandler.class,blockHandler = "orderHandler")
    @SentinelResource(value = "order",fallbackClass = FallbackHandler.class,fallback = "orderFallback")
    public Goods order(@PathVariable("id") Integer id){
        //使用ribbon时,调用的应该是这个在nacos中声明的服务名,而不是固定地址。
        String url = "http://cloud-sentinel-provider/goods/findById/" + id;
        if (0 > id) {
            throw new IllegalArgumentException("非法参数,警告你");
        }else if (id > 100){
            throw new NullPointerException("查无此商品");
        }

        return restTemplate.getForObject(url,Goods.class);
    }


}

5,使用一个函数类来提供fallback

package com.chenshi.exception;

import com.chenshi.domain.Goods;
import org.springframework.web.bind.annotation.PathVariable;

/*业务错误,走fallback*/
public class FallbackHandler {

    public static Goods orderFallback(@PathVariable(value = "id",required = false) Integer id,Throwable e){
        return new Goods(id,"商品:极光pro业务逻辑出错",5799.00,20);
    }

}

6,@sentinelResource中可以同时使用fallback,blockhandler且两者都能使用生效。

@SentinelResource(value = "order",blockHandlerClass = BlockHandler.class,blockHandler = "orderHandler",
        fallbackClass = FallbackHandler.class,fallback = "orderFallback")
public Goods order(@PathVariable("id") Integer id){
    	//使用ribbon时,调用的应该是这个在nacos中声明的服务名,而不是固定地址。
        String url = "http://cloud-sentinel-provider/goods/findById/" + id;
        if (0 > id) {
            throw new IllegalArgumentException("非法参数,警告你");
        }else if (id > 100){
            throw new NullPointerException("查无此商品");
        }

        return restTemplate.getForObject(url,Goods.class);
    }

7,@sentinelResource中的exceptionsToIgnore,可以忽略某个业务上的异常。

@SentinelResource(value = "order",blockHandlerClass = BlockHandler.class,blockHandler = "orderHandler",
        fallbackClass = FallbackHandler.class,fallback = "orderFallback",
        exceptionsToIgnore = {IllegalArgumentException.class})//忽略掉IllegalArgumentException的异常
public Goods order(@PathVariable("id") Integer id){
    //使用ribbon时,调用的应该是这个在nacos中声明的服务名,而不是固定地址。
    String url = "http://cloud-sentinel-provider/goods/findById/" + id;
    if (0 > id) {
        throw new IllegalArgumentException("非法参数,警告你");
    }else if (id > 100){
        throw new NullPointerException("查无此商品");//
    }

    return restTemplate.getForObject(url,Goods.class);
}

8,在sentinel中使用feign功能,导入依赖。

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

9,yml文件中启用feign功能。

#在sentinel中启动feign服务
feign:
  sentinel:
    enabled: true
    

10,主启动类中加上@EnableFeignClients注解

package com.chenshi;

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

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients//开启feign功能
public class ConsumerApp8090 {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApp8090.class, args);
    }
}

11,新建feign接口。

package com.chenshi.feign;

import com.chenshi.domain.Goods;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
											   //feign失败后走向fallback
@FeignClient(value = "cloud-sentinel-provider",fallback = GoodsFeignImpl.class)//这是一个Feign客户端
public interface GoodsFeign {

    @GetMapping("/goods/findById/{id}")
    Goods findById(@PathVariable("id") Integer id);
}

12,feignImpl实现类。

package com.chenshi.feign;

import com.chenshi.domain.Goods;

//feign接口调用失败,返回一个自定义对象
@Serivce
public class GoodsFeignImpl implements GoodsFeign {

    @Override
    public Goods findById(Integer id) {
        return new Goods(id,"feign接口调用出错,这是一个回显",6799.00,20);
    }
}

13,controller层使用feign调用微服务代码。

@Resource GoodsFeign goodsFeign;

@GetMapping("/add1/{id}")
@SentinelResource(value = "order",blockHandlerClass = BlockHandler.class,blockHandler = "orderHandler",
        fallbackClass = FallbackHandler.class,fallback = "orderFallback",
        exceptionsToIgnore = {IllegalArgumentException.class})
public Goods order1(@PathVariable("id") Integer id){
    //使用feign远程调用
    return goodsFeign.findById(id);
}

6,sentinel配置持久化:

目的是将sentinel的配置持久化到nacos配置中心里。

1,导入依赖;

<!--sentinel配置持久化到nacos上-->
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
</dependency>

2,yml文件:

spring:
  application:
    name: cloud-consumer-nacos-consumer
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
    sentinel:
      transport:
        dashboard: localhost:8080
        port: 8719
      web-context-unify: false
      datasource: #和trasnport同级,加入datasource
        ds1:
          nacos:
            server-addr: localhost:8848
            data-id: ${spring.application.name} #项目名
            group-id: DEFAULT_GROUP
            data-type: json #数据类型
            rule-type: flow #流控规则

3,nacos配置中心的配置内容:

#json字符串放入nacos配置中心
[
    {
    "resource": "/order/add1/{id}",
    "limitApp": "default",
    "grade": 1,
    "count": 1,
    "strategy": 0,
    "controlBehavior": 0,
    "clusterMode": false
    }
]#中括号

4,参数含义:

*    "resource":  资源名;

​    "limitApp":  来源应用;

​    "grade": 阈值类型(0:线程数,1:QPS);

​    "count": 单机阈值;

​    "strategy": 流控模式,0:直接,1:关联,2:链路;

​    "controlBehavior": 流控效果,0:快速失败,1:Warm Up,2:排队等待;

​    "clusterMode":  集群模式true/false