02SpringCloud Nacos注册中心和配置中心与Sentinel服务熔断和流控

news2024/12/22 19:13:30

Nacos注册中心和配置中心

Nacos 是 Alibaba 开发的用于微服务管理的平台,核心功能:服务注册与发现和集中配置管理。

  • Nacos 作为服务注册发现组件,可以替换Spring Cloud 应用中传统的服务注册于发现组件,如:Eureka、Consul 等,支持服务的健康检查。
  • Nacos 作为服务配置中心,可以替换 Spring Cloud Config、Apollo(阿波罗的分布式配置中心) 等。

为什么叫 Nacos?Naming 与 Configuration 的前两个字母的组合,最后的 s 代表 service 。从其命名也能看出其核心功能。

Nacos 的下载和安装

首先去 nacos 的 github 地址下载 release 安装包。下载地址

进入到 nacos/bin 目录下面,startup 命令用于启动 nacos ,shutdown 命令用于停掉 nacos 。

单模式启动一

  • windows 系统

    执行 startup.cmd -m standalone 启动,单模式启动

  • linux/unix 系统

    执行 startup.sh -m standalone 启动。

  • docker

    编写docker-compose.yml文件 启动该文件 命令: docker-compose up

    nacos:
      image: nacos/nacos-server:latest
      container_name: nacos-standalone-8848
      environment:
        - PREFER_HOST_MODE=hostname
        - MODE=standalone   #单机模式启动
      volumes:
        - ./8848/logs/:/home/nacos/logs   #前面是宿主机名  后面是容器目录名
        - ./8848/init.d/custom.properties:/home/nacos/init.d/custom.properties
      ports:
      - "8848:8848"
    

单模式启动二

1、修改startup.cmd文件

image-20221118100616331

2、启动

  • windows 系统

    执行 startup.cmd启动,单模式启动

  • linux/unix 系统

    执行 startup.sh 启动。

运行界面

nacos 的默认服务端口是 8848 ,启动完成之后通过浏览器访问 nacos:http://192.168.1.44:8848/nacos/index.html。

看到如下界面,需要登陆,默认的用户名密码都是 nacos ,登陆之后看到如下界面:

image-20210610204222725

nacos 的单机 standalone 模式是开发环境中使用的启动方式,它对用户而言非常友好,几乎不需要的更多的操作就可以搭建 nacos 单节点。另外,standalone 模式安装默认是使用了 nacos 本身的嵌入式数据库 apache derby(Derby是一个Open source的产品,是一个小型的数据库) 。

注册中心

虽然 Eureka Server 会被我们用 Nacos 替换掉,但是我们仍会使用 Ribbon、OpenFeign 作为远程调用的基础组件。

微服务整合 nacos 服务发现:

  • spring-cloud-starter-alibaba-nacos-discovery 是 spring-cloud-alibaba-dependencies 子项目。所以它们的版本号都不需要我们手动维护,继承自父项目 dependencyManagement 中的定义。
  • 因为我们之前使用了 eureka ,所以用 nacos 的spring-cloud-starter-alibaba-nacos-discovery 将spring-cloud-starter-netflix-eureka-client 在 pom 文件中替换掉。
  • spring-cloud-starter-alibaba-nacos-discovery 也默认包含了 spring-cloud-starter-netflix-ribbon ,不需要单独引入 ribbon 。我们之前学习的所有的 ribbion 和 openfeign 相关的负载均衡、远程服务调用的知识在 nacos 下依然适用。

父POM文件

  • spring cloud alibaba version:2.2.5.RELEASE
  • spring boot version :2.3.11.RELEASE
  • spring cloud version:Hoxton.SR8
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<modules>
		<module>order</module>
		<module>gateway</module>
	</modules>
	<groupId>com.woniu</groupId>
	<artifactId>alibaba</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>alibaba</name>
	<description>Demo project for Spring Boot</description>
	<packaging>pom</packaging>
	<properties>
		<java.version>1.8</java.version>
		<spring.cloud.alibaba.version>2.2.5.RELEASE</spring.cloud.alibaba.version>
		<spring.boot.version>2.3.11.RELEASE</spring.boot.version>
		<spring.cloud.version>Hoxton.SR8</spring.cloud.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>

		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>
	
	<dependencyManagement>
		<dependencies>
			<!--Spring Cloud alibaba的版本管理, 通过dependency完成继承-->
			<dependency>
				<groupId>com.alibaba.cloud</groupId>
				<artifactId>spring-cloud-alibaba-dependencies</artifactId>
				<version>${spring.cloud.alibaba.version}</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
	
			<!--Spring Cloud的版本管理-->
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>${spring.cloud.version}</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
	
			<!--SpringBoot的版本管理-->
			<dependency>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-starter-parent</artifactId>
				<version>${spring.boot.version}</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
	
		</dependencies>
	</dependencyManagement>
	
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<configuration>
					<excludes>
						<exclude>
							<groupId>org.projectlombok</groupId>
							<artifactId>lombok</artifactId>
						</exclude>
					</excludes>
				</configuration>
			</plugin>
		</plugins>
	</build>

</project>

模块POM

<dependency> <!-- 自动引入 Ribbon -->
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency> 
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

在 application.yml(或 bootstrap.yml)中加入必要的服务注册中心信息配置(替换掉 eureka 相关配置):

spring:
  application:
    name: spring-provider
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
        namespace: public
        username: nacos
        password: nacos

加上 @EnableDiscoveryClient 注解(去掉 @EnableEurekaClient 注解),开启 Spring Cloud 的服务注册与发现功能。spring cloud alibaba 遵守 spring cloud 规范,因此 @EnableDiscoveryClient 注解能激活、启用 nacos 的服务发现功能。

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

访问 Nacos 服务,通过 服务管理 -> 服务列表,看到我们注册的服务已经在列表中

zuul网关启动的时候,把springcloud-alibaba的版本升级到 2.2.5

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j9KdaqzM-1684929585891)(null)]

服务注册中心相关概念和配置

微服务 group 分组

Nacos 的微服务分组概念,有两层含义:

  • 不同分组的微服务,彼此之间不能发现对方,也就不能进行远程服务调用。逻辑上,不同的分组意味着这是两个不同的独立项目。即微服务从配置中拉取到的注册表是微服务所在组的注册表。
  • 将微服务分组,方便我们查看,以及方便配置管理分类。

可以通过如下属性对微服务所属分组进行配置:

spring:
  cloud:
    nacos:
      discovery: 
        group: public_group

由于多个项目可能、可以使用同一个 nacos 作为注册中心,这种情况下,group 就是区分你我的标识,每个微服务从 nacos 上拉取的只有本组的注册表。 如果微服务没有指定组,默认分组是 default_group

示例:

spring:
  application:
    name: spring-provider
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
        namespace: public
        username: nacos
        password: nacos
        group: public_group

配置中心

Nacos 作为配置管理中心,实现的核心功能就是配置的统一管理。

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

连接和使用配置中心

新建配置文件 bootstrap.yml ,新增 spring.cloud.nacos.config 节点配置,将服务指向正确的 nacos 服务端。

该配置文件中只保留 nacos 相关的配置即可,其他的配置放到 nacos 中统一管理。

注意,和 Spring Cloud Config 一样,连接配置中心的配置信息『必须』写在 bootstrap.yml 配置文件中,而不是 application 配置文件中。bootstrap 优先级高于apllication

server:
  port: 8180

spring:
  application:
    name: spring-provider
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
        namespace: public
        username: nacos
        password: nacos
        group: public_group
      config:
        server-addr: ${spring.cloud.nacos.discovery.server-addr}
        file-extension: yaml   # nacos 配置文件后缀。注意是 yaml,不是 yml
        group: public_group  # 配置分组。未配置时,默认分组是 DEFAULT_GROUP

通过配置列表右侧的 + 按钮添加配置文件:

image-20221118122508087

点击+之后

image-20210611160107512

Data ID 是该配置文件在 Nacos 系统内的唯一标识。

在 Nacos Spring Cloud 中,dataId 的完整格式语法如下:

${prefix}-${spring.profile.active}.${file-extension}
  • prefix 的值默认与 spring.application.name (即服务名)的值相同。也可以通过配置项 spring.cloud.nacos.config.prefix 来手动配置,指定一个与 spring.application.name 不一样的值,不过一般不会动它。

  • spring.profile.active 即为当前环境对应的 profile ,如:xxx-service-dev.yml 中的 dev 就是指开发环境。

    **注意:**当 spring.profile.active 为空时,对应的环境定义字符部分将不存在,即为 xxx-service.yml,而不是 xxx-service-.yml

  • file-exetension 为配置内容的数据格式,可以通过配置项 spring.cloud.nacos.config.file-extension 来配置。

    注意,我们使用的『是 yaml 类型,不是 yml』。虽然二者是一个意思,但是『nacos 只认 yaml』。

Group 的值同 spring.cloud.nacos.config.group 的配置,界面填写的内容与项目中的配置二者『一定要统一』,否则无法正确读取配置,Group 起到配置『隔离』的作用。

image-20221118122540533

入门案例

核心pom

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

创建application.yml

servername: provider

创建bootstrap.yml

server:
  port: 8180

spring:
  application:
    name: spring-provider
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
        namespace: public
        username: nacos
        password: nacos
        group: public_group
      config:
        server-addr: ${spring.cloud.nacos.discovery.server-addr}
        file-extension: yaml   # nacos 配置文件后缀。注意是 yaml,不是 yml
        group: public_group  # 配置分组。未配置时,默认分组是 DEFAULT_GROUP

controller类

@RestController
@RefreshScope
public class ProviderController {

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

    @Value("${servername}")
    private String servername;

    @RequestMapping(value = "/provider/{id}")
    public String provider(@PathVariable String id){
        if(id.equals("1")){
            throw new RuntimeException("异常");
        }
        return "provider id = " + id + "port = " + port + "  servername = " + servername;
    }
}

验证和动态刷新

执行以下代码进行验证:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uE84jJtc-1684929584931)(null)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dKFZYeGD-1684929586078)(null)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pkLbrz6q-1684929586646)(null)]

如果想要实现动态刷新功能,那么在 @Value 所在的 @Component(@Controller、@Service、@Repository)上加上 @RefreshScope 即可实现动态刷新。

Nacos 的数据存储

Nacos 的数据是存储在它自带的内嵌 derby 数据库中的,数据文件就在 Nacos 的解压目录下的 data 文件夹中。

你也可以通过修改配置,让 Nacos 将它的数据存储在你指定的 mysql 数据库中。

Nacos 在它的 conf 目录下已经为你准备好了建表脚本:nacos-mysql.sql 。不过脚本中没有建库语句,为了后续配置简单起见,建议创建的库命名为 nacos 。

创建一个nacos数据库,然后在nacos的bin目录下找到nacos-mysql.sql文件,把该文件的建表语句拷贝mysql客户端下执行,注意要使用你刚才创建的nacos数据库下

create database nacos 
  DEFAULT CHARACTER SET utf8mb4 -- 乱码问题
  DEFAULT COLLATE utf8mb4_bin -- 英文大小写不敏感问题
;

在 conf 文件夹下的 application.properties 配置文件。从 31 行开始的一段配置就是数据库连接相关配置。把如下行数前面的注释去掉

spring.datasource.platform=mysql

### Count of DB:
db.num=1

### Connect URL of DB:
db.url.0=jdbc:mysql://127.0.0.1:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
db.user.0=root
db.password.0=root

修改完 application.properties 配置文件之后,重启 Nacos,你会发现 Nacos 重新编程了一个『干净』的环境。

测试:登陆localhost:8848/nacos,在配置中心上新建一个配置,如:spring-provider.yaml,发现这个配置保存到了我们自己创建的nacos数据库里面

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7zRbS804-1684929584834)(null)]

nacos集群配置

拷贝cluster.conf.example文件,并改名为cluster.conf

192.168.31.203:8848
192.168.31.203:8849
192.168.31.203:8850

直接双击启动启动脚本

image-20221123160724426

微服务配置:

server-addr: 192.168.31.203:8848,192.168.31.203:8849,192.168.31.203:8850

spring:
  application:
    name: spring-provider
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.31.203:8848,192.168.31.203:8849,192.168.31.203:8850
        namespace: public
        username: nacos
        password: nacos
        group: public_group
      config:
        server-addr: ${spring.cloud.nacos.discovery.server-addr}
        file-extension: yaml   # nacos 配置文件后缀。注意是 yaml,不是 yml
        group: public_group  # 配置分组。未配置时,默认分组是 DEFAULT_GROUP

Sentinel服务熔断和流控

简介

Sentinel

​ 随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 是面向分布式服务架构的流量控制组件,主要以流量为切入点,从限流、流量整形、熔断降级、系统负载保护、热点防护等多个维度来帮助开发者保障微服务的稳定性。
源码地址:https://github.com/alibaba/Sentinel
官方文档:https://github.com/alibaba/Sentinel/wiki

https://sentinelguard.io/zh-cn/docs/circuit-breaking.html

Spring Cloud Alibaba Sentinel 同时兼具了熔断器和流控的功能。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lTpOlTBy-1684929585048)(null)]

Sentinel具有以下特征:

  • 丰富的应用场景: Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控
    制在系统容量可以承受的范围)、消息削峰填谷、实时熔断下游不可用应用等。

  • 完备的实时监控: Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。

  • 广泛的开源生态: Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、
    gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。

  • 完善的 SPI 扩展点: Sentinel 提供简单易用、完善的 SPI 扩展点。您可以通过实现扩展点,快速的定制逻辑。例如定制规则管理、适配数据源等。

    Spring的spi是通过ClassLoader去META-INF/spring.factories加载class,然后反射实例化返回。像SpringBoot用这种方式去加载一些自动配置类,即引入xx-starter就能够自动向spring容器中注入许多配置好的组件。

阿里云提供了 企业级的 Sentinel 服务,应用高可用服务 AHAS

image-20221118153102243

Sentinel和Hystrix对比

https://github.com/alibaba/Sentinel/wiki/Sentinel-%E4%B8%8E-Hystrix-%E7%9A%84%E5%AF%B9%E6%AF%94

SentinelHystrix
隔离策略信号量隔离线程池隔离/信号量隔离
熔断降级策略基于响应时间或失败比率基于失败比率
实时指标实现滑动窗口滑动窗口(基于 RxJava)
规则配置支持多种数据源支持多种数据源
扩展性多个扩展点插件的形式
基于注解的支持支持支持
限流基于 QPS,支持基于调用关系的限流有限的支持
流量整形支持慢启动、匀速器模式不支持
系统负载保护支持不支持
控制台开箱即用,可配置规则、查看秒级监控、机器发现等不完善
常见框架的适配Servlet、Spring Cloud、Dubbo、gRPC 等Servlet、Spring Cloud Netflix

熔断

微服务架构的系统通常会包含多个微服务,各个微服务可能部署在不同的机器上并通过网络进行通信,那么就不可避免会遇到 “网络请求超时” 、“微服务不可用” 等问题,这就会进一步引起依赖它的微服务不可用,这样不断引发服务故障的现象称为『雪崩效应』,最终的结果是整个应用系统瘫痪。

为了解决上述问题,编程领域(参考现实生活)提出了熔断器
使用熔断器模式,如果请求出现异常,所有请求都会直接返回,而不会等待或阻塞,这样可以减少资源的浪费。
熔断器所造成的这种现象也叫『快速失败(fast fall)』。

流控

限流功能指的是 Sentinel(类似于过滤器、拦截器的效果)在收到请求后,拒绝请求的放行(至 Controller),而是直接返回,从而减少对 Controller,乃至 Service 的触发执行。

熔断和限流的区别在于,熔断是确确实实发生了错误,而限流是人为(根据设置)强行让一部分请求被打回。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ErVOWxP9-1684929586312)(null)]

sentinel安装

sentinel-dashboard 的下载安装

sentinel-dashboard 是基于 Spring Boot 开发的控制台。打包后可以直接运行,不需要额外的 Tomcat 等应用容器。Sentinel 控制台不仅能展示服务流控、熔断降级相关的数据,还可以通过配置的方式动态的为 Sentinel 客户端下发流量控制的指令

我们需要下载并安装的是 sentinel-dashBoard ,下载地址:https://github.com/alibaba/Sentinel/releases

注意:启动 sentinel-dashboard 需要 JDK 版本为 1.8 及以上版本。

使用如下命令启动控制台:

java -Dserver.port=8840 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.1.jar
  • -Dserver.port=8840

    用于指定 Sentinel 控制台端口为 8840。默认是 8080 。

  • -Dproject.name=sentinel-dashboard

    指定 Sentinel 控制台程序的名称。

说明

如果你有多张网卡的话,你还需要指定使用哪张网卡(IP)来接受各个微服务上报的信息:

-Dcsp.sentinel.heartbeat.client.ip=192.168.xxx.xxx

访问网址:[http://127.0.0.1:8840]

从 1.6.0 起,sentinel-dashboard 引入基本的登录功能,默认用户名和密码都是 sentinel 。当然也可以通过 JVM 参数的方式进行修改

  • -Dsentinel.dashboard.auth.username=sentinel

    用于指定控制台的登录用户名为 sentinel ;

  • -Dsentinel.dashboard.auth.password=123456

    用于指定控制台的登录密码为 123456;如果省略这两个参数,默认用户和密码均为 sentinel;

  • -Dserver.servlet.session.timeout=7200

    用于指定 Spring Boot 服务端 session 的过期时间,如 7200 表示 7200 秒;60m 表示 60 分钟,默认为 30 分钟;

Sentinel 本身就是一个 Spring Boot 应用,所以jar 包内部的 application.properties 文件也是可以修改配置的。

Sentinel实现限流

Spring Cloud Alibaba Sentinel 可以分别用在服务的 “请求发起方” 和 “请求被调方”

  • 请求发起方使用的是 OpenFeign ,因此这种情况下 Sentinel 是和 OpenFeign 进行整合;
  • 请求被调用使用的是 Spring MVC,因此这种情况下 Sentinel 是和 Spring MVC 进行整合

同时又由于 Sentinel 兼具熔断和流控两个功能,因此这里就有 4 种情况:

  • 在服务发起方项目中,整合 OpenFeign 进行实现熔断功能;
  • 在服务发起方项目中,整合 OpenFeign 进行实现限流功能;
  • 在服务被调方项目中,整合 Spring MVC 进行实现熔断功能;
  • 在服务被调方项目中,整合 Spring MVC 进行实现限流功能。

这样以来功能上就出现了重叠冗余,因此在实际使用中我们是这样安排的:

  • 在服务发起方,Sentinel 整合 OpenFeign 实现熔断功能;
  • 在服务被调方,Sentinel 整合 Spring MVC 实现限流功能。

总结:流控针对provider,熔断降级针对consumer

sentinel实现限流

回顾前面笔记中的 “关于 Sentinel 的使用方式” 章节,在这里,我们在服务的 “被调方” 使用 Sentinel 整合 Spring MVC 进行流量控制。
在这里,Sentinel 借助 Spring MVC 框架的 “拦截器” 机制整合进入 Spring MVC ,“抢先” 在 Controller 执行之前进行流控(和熔断)的判断,从而决定当前请求是否被放行至 Controller

sentinel整合mvc

1.引入相关依赖

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!-- 其实真正起作用的是被关联引入的 sentinel-spring-webmvc-adapter 包 -->

2.添加配置(连接到 sentinel-dashboard)

spring:
  cloud:
    sentinel:
      transport:
        dashboard: 127.0.0.1:8080
        port: 8719

feign:
  sentinel:
    enabled: true

3.访问 sentinel-dashboard

只需要完成上述的配置,代码不需要有任何的调整,我们就可以通过实时监控查看服务内的流量 QPS(每秒查询率) 以及平均响应时长等信息。

只有服务接口被访问的情况下,在 sentinel 里面才可以看到监控信息。这可能会让你『等』一段时间。

image-20220426203243709

相关概念

  • 上下文( Context )和 context-name

Context 代表调用链路上下文。是一个根节点,在整个调用链路的开始处,Sentinel 会创建上下文 Context 对象,并且为它指定一个 name ,相当于根资源。在 Sentinel 中,不同的调用链路可能使用同一个上下文 Context 对象(共一个根节点)。在这里( 和 Spring MVC 整合 ),我们的调用链路都是在 sentinel_spring_web_context 中:

image-20220426173808330

  • 资源(Resource)和 resource-name

在 Sentinel 中,对于每一份资源,Sentinel 会为赋予一个 name(或者你手动指定),和 Spring MVC 整合时,Sentinel 使用的是 URI 来作为 Controller 方法的资源名( 在这里,Controller 方法就是资源 )

image-20220426175835311

流控规则

在菜单左侧的 簇点链路和流控规则都可以针对 服务接口添加流控规则:

当我们的服务接口资源被访问的时候,就会出现在 簇点链路 列表中,我们可以针对该服务接口资源配置流程控制规则

image-20220426191147532

说明:

  • 资源名:表示我们针对哪个接口资源进行流控规则配置,如:/test2/{id}

  • 针对来源:表示针对哪一个服务访问当前接口资源的时候进行限流,default 表示不区分访问来源。如填写服务名称:xxx-service,表示 xxx-service 访问前接口资源的时候进行限流,其他服务访问该接口资源的时候不限流,一般就是默认为default即可。

  • 阈值类型/单机阈值:QPS,每秒钟请求数量。上图配置表示每秒钟超过2次请求的时候进行限流;当然我们可以设置线程数,表示开启 n 个线程处理资源请求,这个不是只每秒2个线程,对服务端 /test1请求,资源接口的 2 个线程都被占用的时候,其他访问失败!一般用的都是QPS

  • 是否集群:默认情况下我们的限流策略都是针对单个服务的,当然sentinel 提供了集群限流的功能。

    除非你的微服务规模特别大,一般不要使用集群模式。集群模式需要各节点与 token server 交互才可以,会增加网络交互次数,一定程度上会拖慢你的服务响应时间。

上面的限流规则用一句话说:对于任何来源的请求,当超过每秒 2 次的标准之后就直接限流,访问失败抛出 BlockException 异常!

流控规则高级选项

1.流控模式
  • 直接:当前资源达到限流标准时就直接限流,默认值
  • 关联:/important接口的重要程度要高于 /normal接口,如果,/important接口的访问压力很大,那么,可以『牺牲』掉 /normal` 接口,全力保证 /important 接口的正常运行

例如:我们在resttemplate-a微服务中,创建两个接口

@GetMapping("/query")
public String query(){
    return "ok:query";
}

@GetMapping("/add")
public String add(){
    return "ok:add";
}

先访问:http://localhost:9527/add和http://localhost:9527/query

image-20220426204140487

我们对/query接口进行限流,这个配置的意思就是,当每秒对/add接口的请求超过2次时,就对/query接口进行限流,要注意这样是优先保证/add不限流,牺牲的是/query接口。10s内对/add接口超过20次请求,那么就对/query接口限流

测试:

image-20220426204812473

image-20220426204832333

image-20220426205021541

  • 链路

链路限流和关联限流的思路很像,假设我们要去请求某个微服务,该微服务有2个接口(/query和/add),而这两个接口又调用了同一个service层的方法(如:doSomething()方法),那么,我们可以『站在 doSomething的方法』的角度上进行设置:如果是 /query接口在调用service层的 doSomething方法,那么就进行限流,而 /add接口的调用就不限流,或设置为更宽松一些的流控

1.配置设置:通过配置关闭 sentinel 的 URL 收敛功能

spring:
  application:
    name: resttemplate-a
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
    sentinel:
      transport:
        dashboard: localhost:8840
      web-context-unify: false  #默认是开启上下文整合,所有链路在根节点下,链路监控就是将请求分开统计

2.代码设计

controller层
@GetMapping("/query")
public String query(){
    return userService.doSomething();
}
@GetMapping("/add")
public String add(){
    return userService.doSomething();
}
//service层
@Component
public class UserService {
    @SentinelResource("doSomething")
    public String doSomething() {
        return "hello world";
    }
}

3.重新运行,先在界面发送请求 http://localhost:9527/query和http://localhost:9527/add,然后sentinel配置

image-20220427143429362

链路配置:

image-20220427143517498

4.测试:在jmeter对/add测试时不限流(如10秒钟对/add请求80次),但是同时在浏览器对/query测试时,每秒只能是2次请求。

2.流控效果
  • 快速失败:很简单的说就是达到限流标准后,请求就被拦截,直接失败。(HTTP状态码:429 too many request),默认值
  • Warm up:预热模式,也有叫冷启动,主要是为系统启动时设置预热时间,底层有预热因子是3,在系统刚启动时,使用的阈值不再是每秒多少个请求,而是设置的阈值除以预热因子,在预热的时间内,逐渐提升阈值,最后达到设置的阈值(也就是每秒多少个请求),好处是预防系统刚启动时,突发大量的请求,服务容易宕机。

1.代码设计

@GetMapping("/test/{id}")
public ResponseEntity<String> test1(@PathVariable Integer id){
    return new ResponseEntity<>("ok", HttpStatus.OK);
}

2.配置设置

image-20220427145952767

在10秒内,每秒允许的请求数会逐渐增加,也就是每秒的阈值逐渐提高

3.测试

image-20220427150337329

  • 排队等待:也叫流量整形,它让请求以均匀的速度通过,单机阈值为每秒通过数量,其余的在队列排队等待一段时间,(即我们设置的时间,单位是毫秒),没有超过这个时间都能被及时处理,如果超过了这个等待时间针对请求的接口没有线程来处理,则抛出异常

image-20220427152215517

测试:每秒50个请求

image-20220427152404688

Sentinel 和 SpringMVC 整合原理

Sentinel 和 Spring MVC 的整合利用了 Spring MVC 的拦截器机制,Sentinel 实现了一个名为 SentinelWebInterceptor 的拦截器,其逻辑伪代码如下

public SentinelWebInterceptor implements HandlerInterceptor {

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler){
        try {
            1. 初始化上下文;
            2. 熔断、流控逻辑的判断,判断当前请求是否能继续执行;
            return true; // 此时 Controller 方法会被调用。Controller 方法就是 3 。
        } catch (BlockException e) {
            4. 上述第 2 步未能通过,会抛出 BlockException ,表示请求被拒绝
            return false;
        }
    }

    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {

    } 
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
      if (发生了异常) {
          5. 业务异常。记录、统计异常信息
      }
      6. 收尾工作:曾经创建的资源该回收的回收,该清除的清除
    }

自定义限流异常信息返回

Sentinel 返回的默认信息是 Blocked by Sentinel (flow limiting),如果你对默认响应信息不满意,你可以自定义限流返回信息。

Sentinel 提供了 BlockExceptionHandler 接口。不管什么原因触发了 Sentinel 阻断用户的正常请求,Sentinel 都将『进入』到用户自定义的 BlockExceptionHandler 接口的实现类中,执行 handle 方法,并传入当前的请求、响应对象以及异常对象,并以 handle 方法的执行结果作为返回,回传给用户。

@Component
public class MyBlockExceptionHandler implements BlockExceptionHandler {
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, BlockException ex) throws Exception {
        String msg = null;
        if (ex instanceof FlowException) {
            msg = "该请求限流了,请稍后重试";
        } else if (ex instanceof DegradeException) {
            msg = "被熔断了";
        } else {
            msg = "其它原因";
            // ParamFlowException   "热点参数限流";
            // SystemBlockException "系统规则(负载/...不满足要求)";
            // AuthorityException   "授权规则不通过";
        }
        // http 状态码
        response.setStatus(500);
        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-Type", "application/json;charset=utf-8");
        response.setContentType("application/json;charset=utf-8");
        new ObjectMapper().writeValue(response.getWriter(), msg);
    }
}

需要说明的是:不仅仅是因为限流和熔断这一个原因会导致 BlockExceptionhandlerhandle 方法的执行,还有其它的原因也会调用这个handler方法,因此,需要对 handle 方法的 BlockException 参数对象进行 instanceof 判断

sentinel服务熔断降级

我们在服务的 “请求发起方” 使用 Sentinel 整合 OpenFeign 进行熔断降级

sentinel整合feign

1.添加依赖

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

2.添加配置(连接到 sentinel-dashboard)

spring:
  cloud:
    sentinel:
      transport:
        dashboard: 127.0.0.1:8840
feign:
  sentinel:
    enabled: true   ##启用 Sentinel 与 OpenFeign 整合适配器

3.代码实现spring-service-a-feign微服务,调用spring-service-b微服务

@FeignClient(value = "spring-service-b",qualifier = "feignclient",
        fallback = PermFeignClientImpl.class )
public interface PermFeignClient {
	@GetMapping("/perms/{id}")
    public Perms getPermsById(@PathVariable("id") Integer id);
}
=========降级代码==============
@Component
public class PermFeignClientImpl implements PermFeignClient {
    @Override
    public Perms getPermsById(Integer id) {
        Perms perms = new Perms();
        perms.setName("服务器忙,请稍后再试");
        return perms;
    }
}
===========controller=======================
@RestController
public class PermController {
    @Autowired @Qualifier("feignclient")
    private PermFeignClient permFeignClient;
    @GetMapping("/perm")
    public Perms getPermsById(Integer id) {
        Perms perms = permFeignClient.getPermsById(id);
        return perms;
    }
}

spring-service-b微服务

@GetMapping("/perms/{id}")
public Perms getPermsById(@PathVariable("id") Integer id) {
    if(id==1){
        try {
            Thread.sleep(800);   //当id为1时,800毫秒才有相应
        }catch (Exception ex){ }
    }
    if(id==2){
        throw new RuntimeException();
    }
    return permService.getPermsById(id);
}

4.熔断规则

在 sentinel-dashboard 上你可以看到有 降级规则,它指的就是『设置当满足什么条件时,对服务进行降级

image-20220427175029755

慢调用比例

如下配置:在一秒内,发5次请求,如果每次请求的响应时间超过500毫秒,这种比例达到0.5(50%),就进行熔断,熔断时长就是10秒。如:1秒内有5次请求,其中有3次请求响应时间超过了500毫秒,那么这个比例就是60%,大于50%,此时就熔断,然后降级。

image-20220427175159277

用jmeter测试,程序中当id=1时,每次响应都是800毫秒。所以每次的请求都大于500毫秒,失败率100%,这个时候去请求id=4的资源也是无法请求的,因为熔断了,所以也是直接降级。10s后再次请求id=4的就正常了。

异常数

如下配置:一秒内发送5次请求,如果有3次失败(异常),则直接熔断,然后降级

image-20220427175948916

测试:localhost:9527/perm?id=2,结果5次都失败了,此时熔断时长是9秒,在这9秒内,如果去请求id=4的依然是降级,9s之后试着去发送id=4的请求,如果通过则进入闭合正常状态。

异常比例

如下配置:1秒钟发送5次请求,如果调用接口最终失败的比例超过了20%,则熔断9s。

image-20220427180730668

blockhandler fallback,blockhandler 优先级高

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/564210.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

XML和JSON格式转换成txt

XML如下这种&#xff1a; 转换代码 import os import xml.etree.ElementTree as ET# xml文件存放目录(修改成自己的文件名) input_dir rC:\121\Annotations# 输出txt文件目录&#xff08;自己创建的文件夹&#xff09; out_dir rC:\121\txtclass_list []# 获取目录所有xml文…

pix2pixHD代码---数据集处理

在train文件中&#xff1a;其中dataset是dataloader的方法&#xff0c;而dataloader等于CreateDataLoader。 所以我们跳到CreateDataLoader&#xff1a; 在CreateDataLoader中返回的是dataset_loader&#xff0c;是来自于CustomDatasetDataLoader。切调用了initialize。因为C…

零次学习(Zero-Shot Learning)

零次学习&#xff08;Zero-Shot Learning&#xff09; 零样本学习zero-shot learning&#xff0c;是最具挑战的机器识别方法之一。2009年&#xff0c;Lampert 等人提出了Animals with Attributes数据集和经典的基于属性学习的算法&#xff0c;开始让这一算法引起广泛关注。 零…

qt quick(qml)通过arcgis导入自定义格式地图(Windows 版本)

参考ArcGIS Maps SDK for Qt 参考Display a map 安装 预先安装的软件 安装ArcGIS SDK 点击ArcGIS Maps SDK for Qt 注册账号 要注册成developer版本用户的&#xff0c;不然之后可能没办法生成API 下载 下载之后安装&#xff0c;一路next就可以了 在QT中创建ArcGIS项目…

CMOS图像传感器——TDI CIS(2)

在之前的文章 CMOS图像传感器——TDI CIS_tdi相机的工作原理_沧海一升的博客-CSDN博客时间延迟积分(Time-Delay Integration, TDI)技术是一种特殊的成像模式https://blog.csdn.net/qq_21842097/article/details/119873386 对CMOS TDI图像传感器做了基本介绍,这里我们…

django项目结合vue执行

开发环境下直接把vue打包后的文件放在django项目&#xff0c;启动前端项目直接打包即可 注意事项&#xff1a; settings.py文件 TEMPLATES [ { ‘BACKEND’: ‘django.template.backends.django.DjangoTemplates’, # ‘DIRS’: [], ‘DIRS’: [os.path.join(BASE_DIR,‘front…

Java基础面试题突击系列5

&#x1f469;&#x1f3fb; 作者&#xff1a;一只IT攻城狮 &#xff0c;关注我不迷路 ❤️《java面试核心知识》突击系列&#xff0c;持续更新… &#x1f490; 面试必知必会学习路线&#xff1a;Java技术栈面试系列SpringCloud项目实战学习路线 &#x1f4dd;再小的收获x365天…

mac 切换java jdk版本 java8 java11

1. 终端执行命令 查看本地各版本jdk&#xff1a;mac通常默认安装了jdk1.8 安装目录是 /Library/Java/JavaVirtualMachines/ cd /Library/Java/JavaVirtualMachines/ ls 2. 上述命令列出的各版本目录名 后&#xff0c;在全局配置文件.bash_profile中新增上面命令列出的各…

四月,收割12家offer,面试也太容易了吧....

前言 下面是我根据工作这几年来的面试经验&#xff0c;加上之前收集的资料&#xff0c;整理出来350道软件测试工程师 常考的面试题。字节跳动、阿里、腾讯、百度、快手、美团等大厂常考的面试题&#xff0c;在文章里面都有 提到。 虽然这篇文章很长&#xff0c;但是绝对值得你…

005 - STM32学习笔记 - 启动代码

005 - STM32学习笔记 - 启动代码 常用汇编指令 指令名称作用EQU给数字常量取一个符号名&#xff0c;相当于C语言中的#define&#xff1b;AREA汇编一个新的代码段或者数据段&#xff1b;SPACE分配内存空间&#xff1b;PRESERVE8当前文件栈需要按照8字节对齐&#xff1b;EXPORT…

【ChatGPT】ChatGPT自动生成思维导图

参考视频&#xff1a;https://edu.csdn.net/learn/38346/613917 应用场景&#xff1a;自学&#xff0c;“研一学生如何学习机器学习”的思维导图 问&#xff1a;写一个“研一学生如何学习机器学习”的思维导图内容&#xff0c;以markdown代码块格式输出 # 研一学生如何学习…

探索人工智能和机器学习的前沿趋势

&#x1f31f; 深度学习的突破&#x1f31f; 强化学习的进展&#x1f31f; 可解释性和公平性的挑战&#xff08;1000字&#xff09;&#x1f31f; 自动化和智能化的未来&#xff08;1000字&#xff09; 在当今科技飞速发展的时代&#xff0c;人工智能&#xff08;Artificial In…

全网最牛最前面的浦发银行软件测试面试题精讲分析

面试永远都是软件测试人重点关注的问题&#xff0c;最近也总有很多想去银行面试的小伙伴来问我&#xff0c;有没有什么方法技巧传授一下。 那今天就给大家总结一些浦发银行的面试题&#xff0c;小伙伴们可以看看如果是自己能不能流畅地回答上来这些面试题。 1、说说你们公司测…

c++积累12-const

1、文件作用域-const修饰变量默认为文件局部变量 注意&#xff1a;非const变量默认为extern。要使const变量能够在其他文件中访问&#xff0c;必须在文件中显式地指定它为extern。 1) 未被const修饰的变量在不同文件的访问 可以看到是能够默认不加const是可以正常访问的 2) …

某大型啤酒企业:构建网络安全软实力,首选Coremail反钓鱼演练

客户背景 某大型啤酒厂商的公司规模和市场份额多年来始终都处于行业领先地位&#xff0c;积极赞助多项体育赛事&#xff0c;持续丰富和提升品牌形象。作为一家具有全球影响力的企业&#xff0c;自然也成为了全球黑客等攻击团伙的重点目标&#xff0c;而系统攻击的开端便是钓鱼…

什么是产品路线图?如何做产品路线图规划

产品路线图规划 •产品路线图是一个高层次的战略计划&#xff0c;它描述了产品在未来一段时间可能会如何发展和壮大&#xff0c;产品路线图确保整个产品团队持续关注产品的目标&#xff0c;帮助产品负责人把握产品的战略方向&#xff0c;调整产品的优先级和产品规划。 里程碑…

轻松打造智能化性能测试监控平台:【JMeter+Grafana+Influxdb】的优化整合方案

目录 【引言】 【背景说明】 【实现原理】 【平台搭建】 方法一&#xff1a;Windows或macOS环境下搭建 1.InfluxDB安装 2.grafana安装 3.jmeter配置 方法二&#xff1a;Linux环境下搭建 1.influxdb安装 2.grafana安装 3.jdkjmeter安装 方法三&#xff1a;docker容…

L1-093 猜帽子游戏

宝宝们在一起玩一个猜帽子游戏。每人头上被扣了一顶帽子&#xff0c;有的是黑色的&#xff0c;有的是黄色的。每个人可以看到别人头上的帽子&#xff0c;但是看不到自己的。游戏开始后&#xff0c;每个人可以猜自己头上的帽子是什么颜色&#xff0c;或者可以弃权不猜。如果没有…

python接口自动化测试之unittest自动化测试框架基本使用

目录 unittest简单介绍 unittest基础使用 unittest.Testcase setUp tearDown setUpClass tearDownClass 测试用例 unittest.main() unitteest提供的各种断言方式 unittest测试用例跳过执行 跳过执行测试用例共有四种写法 self.skipTest(reason) 跳过执行测试用例注…