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

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 优先级高

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Cloud Nacos是一个服务注册中心,可以用于微服务架构中的服务注册与发现。要使用Spring Cloud Nacos作为注册中心,首先需要引入Nacos客户端依赖,并配置注册中心地址。在pom.xml文件中添加以下依赖: ```xml <!-- Nacos客户端依赖 --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> ``` 然后,在application.yml或application.properties中进行配置,指定Nacos注册中心地址: ```yaml spring: cloud: nacos: server-addr: 127.0.0.1:8848 ``` 这样就完成了Spring Cloud Nacos注册中心配置。使用Nacos作为注册中心与使用Eureka相比,并没有太大区别,因为Nacos也遵循了Spring Cloud定义的服务注册与发现规范。同时,Spring Cloud Nacos还提供了可视化界面,可以将微服务注册到Nacos,并支持CP和AP两种方式。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [SpringCloudNacos,服务注册中心](https://blog.csdn.net/qq_38668544/article/details/120066467)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [day2021-11-11(springcloud Nacos注册中心)](https://blog.csdn.net/TIM_Zhang1122/article/details/121268351)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [spring cloud nacos 注册中心](https://download.csdn.net/download/weixin_43326401/12545665)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值