当前位置:   article > 正文

SpringCloud之Sentinel-熔断和限流_spring cloud sentinel限流?熔断?

spring cloud sentinel限流?熔断?


说明:关于SpringCloud系列的文章中的代码都在码云上面
地址: https://gitee.com/zh_0209_java/springcloud-alibaba.git

简介

随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。

Sentinel 具有以下特征:

  • 丰富的应用场景:Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。
  • 完备的实时监控:Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。
  • 广泛的开源生态:Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。
  • 完善的 SPI 扩展点:Sentinel 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等

Sentinel 的主要特性

在这里插入图片描述

下载Sentinel-dashboard

Sentinel-dashboard 是Sentinel 的web可视化界面
下载地址
在这里插入图片描述
现在的最新版本为1.8.2,那我们就下载1.8.2

下载到本地后,可以使用cmd进入黑窗口,启动sentinel-dashboard-1.8.2.jar

在这里插入图片描述
启动完成后浏览器访问 localhost:8080 ,这是sentinel-dashboard 的默认端口,注意不要产生端口冲突,
在这里插入图片描述
默认账号和密码都是 sentinel
在这里插入图片描述
自此sentinel-dashboard 安装成功

sentinel 初始化监控

新建项目 cloudalibaba–sentinel-service8401项目

  1. 修改pom文件
<dependencies>
		<!--SpringCloud alibaba Nacos-->
		<dependency>
			<groupId>com.alibaba.cloud</groupId>
			<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
		</dependency>

		<!--SpringCloud alibaba sentinel-datasource-nacos 后续做持久化用到的依赖-->
		<dependency>
			<groupId>com.alibaba.csp</groupId>
			<artifactId>sentinel-datasource-nacos</artifactId>
		</dependency>
		<!--SpringCloud alibaba sentinel-->
		<dependency>
			<groupId>com.alibaba.cloud</groupId>
			<artifactId>spring-cloud-starter-alibaba-sentinel</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-test</artifactId>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-actuator</artifactId>
		</dependency>
	</dependencies>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  1. 修改配置文件
server:
  port: 8401

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

# 暴露监控端点
management:
  endpoints:
    web:
      exposure:
        include: '*'
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  1. 新建启动类
@SpringBootApplication
@EnableDiscoveryClient
public class SentinelApplication {

	public static void main(String[] args) {
		SpringApplication.run(SentinelApplication.class,args);
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  1. 新建业务类
@RestController
public class SentinelController {

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

	@GetMapping("/testB")
	public String testB(){
		return "=====testB";
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  1. 启动nacos 服务端 以及nacos-dashnoard 监控,在启动8401 客户端,
  2. 访问testA ,testB 接口,然后查看sentinel-dashnoard
    在这里插入图片描述
    注意:sentinel-dashboard 使用的是懒加载机制,必须访问过才能显示出来。

流控规则

在这里插入图片描述
说明:

  • 资源名: 唯一名称,默认请求路径
  • 针对来源: Sentinel 可以针对调用者进行限流,填写微服务名,默认default (不区分来源)
  • 阈值类型/单机阈值
    • QPS (每秒的请求数量): 当调用该api的QPS达到阈值的时候,进行限流
    • 线程数:当调用该API 的线程数达到阈值的时候,进行限流
  • 是否集群:不需要集群
  • 流控模式
    • 直接: API达到限流条件时,直接限流
    • 关联: 当关联的资源达到阈值时,就限流自己
    • 链路:只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到阈值,就进行限流)【API级别的针对】
  • 流控效果
    • 快速失败:直接失败,抛出异常
    • Warm Up: 根据codeFactor (冷加载因子,默认3)的值,从阈值/codeFactor, 经过预热时长,才达到设置的QPS阈值
    • 排队等待: 匀速排队,让请求以均匀的速度通过,阈值类型必须设置为QPS, 否则无效

测试QPS , 直接,快速失败

  • 对testA接口添加QPS流控
    在这里插入图片描述
    在访问testA 接口,当访问速度不超过 1次/秒的时候可以正常访问,当超过 1次/秒的时候就会报错
    在这里插入图片描述
  • 对testA接口添加线程数流控
    在这里插入图片描述
    修改业务类,使其休眠5秒
    在这里插入图片描述
    浏览器访问测试,当同时访问的线程数超过设置的阈值时就会抛出异常
    在这里插入图片描述
  • 关联
    当关联的资源达到阈值时,就限流自己
    在这里插入图片描述
    说明:就是当 /testB 的QPS超过设置的阈值1了,就管控 /testA
    使用postman模拟并发密集访问testB
    在这里插入图片描述
    在访问 /testA , 发现 /testA 报Blocked by Sentinel (flow limiting),当 /testB 访问结束,在访问 /testA 恢复正常

流控效果

  • 直接失败:默认,直接抛出异常,Blocked by Sentinel (flow limiting)
  • Warm Up(预热):
    说明:公式:阈值除以coldFactor(默认值为3),经过预热时长后才会达到阈值。
    Warm Up 方式,即预热/冷启动方式。当系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过“冷启动”,让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮
    在这里插入图片描述
    表示为 /testB 资源 最开启的QPS为 10(阈值)/3(冷加载因子,默认为3)=3,在5秒内慢慢增加QPS到设置的最大阈值10.

测试发现最开始快速访问 /testB,会抛出异常,慢慢的经过5秒后,当每秒访问不超过10QPS时,就不会抛出异常

  • 排队等待
    匀速排队,让请求以均匀的速度通过,阈值类型必须设成QPS,否则无效。
    设置含义:/testA 每秒一次请求,超过的话就排队,等待的超时时间为20000毫秒
    在这里插入图片描述

降级规则/熔断规则

简介

在这里插入图片描述
Sentinel 提供以下几种熔断策略:

  • 慢调用比例 (SLOW_REQUEST_RATIO):选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。
  • 异常比例 (ERROR_RATIO):当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。
  • 异常数 (ERROR_COUNT):当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。

热点key限流

简介

何为热点?热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K 数据,并对其访问进行限制。比如:

  • 商品 ID 为参数,统计一段时间内最常购买的商品 ID 并进行限制
  • 用户 ID 为参数,针对一段时间内频繁访问的用户 ID 进行限制

热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效
在这里插入图片描述

新建一个接口测试

	@GetMapping("/testHotKey")
	// /testHotKey 代表rest地址,testHotKey 代表资源名,要唯一
	@SentinelResource(value = "testHotKey",blockHandler = "deal_testHotKey")
	public String testHotKey(@RequestParam(value = "p1",required = false) String p1,@RequestParam(value = "p2",required = false) String p2){
		return " test 测试 -》 testHotKey"+ "p1 ->"+p1+",p2 ->" +p2;
	}

	public String deal_testHotKey(String p1, String p2, BlockException exception){
		// sentinel 系统的默认提示: Blocked by Sentintel (flow limiting)
		// 这里等于是指定了/testHotKey 接口的默认提示
		return " test 测试 -》 deal_testHotKey"+ "p1 ->"+p1+",p2 ->" +p2;
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

在这里插入图片描述
参数索引: 代表该资源的入参的第一个参数,是p1

单机阈值:携带该参数访问的阈值

统计时长:对设置规则的统计时长

如上图设置的热点规则就是在1秒内 访问 testHotKey 资源 携带参数索引为0(也就是第一个参数p1)的访问次数的阈值为1,超过阈值就会跳转到@SentinelResource注解中blockHandler 指定的方法中

参数例外项

在这里插入图片描述
访问测试,当参数p1的值不等于5的时候,阈值仍然是1,但当p1的值为5时,阈值到了199.
在这里插入图片描述
注意,参数类型只能是基本类型和String.

当代码发生运行时异常时,会直接抛出异常,而不会进入@SentinelResource注解中blockHandler 指定的方法中,因为@SentinelResource注解管的是sentinel控制台流控的错误。

@SentinelResource 主管配置出错,运行时出错该走异常走异常。

系统规则/系统自适应限流

简介

Sentinel 系统自适应限流从整体维度对应用入口流量进行控制,结合应用的 Load、CPU 使用率、总体平均 RT、入口 QPS 和并发线程数等几个维度的监控指标,通过自适应的流控策略,让系统的入口流量和系统的负载达到一个平衡,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。

系统保护规则是从应用级别的入口流量进行控制,从单台机器的 load、CPU 使用率、平均 RT、入口 QPS 和并发线程数等几个维度监控应用指标,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。

系统保护规则是应用整体维度的,而不是资源维度的,并且仅对入口流量生效。入口流量指的是进入应用的流量(EntryType.IN),比如 Web 服务或 Dubbo 服务端接收的请求,都属于入口流量。

系统规则

系统规则支持以下的模式:

  • Load 自适应(仅对 Linux/Unix-like 机器生效):系统的 load1 作为启发指标,进行自适应系统保护。当系统 load1 超过设定的启发值,且系统当前的并发线程数超过估算的系统容量时才会触发系统保护(BBR 阶段)。系统容量由系统的 maxQps * minRt 估算得出。设定参考值一般是 CPU cores * 2.5。
  • CPU usage(1.5.0+ 版本):当系统 CPU 使用率超过阈值即触发系统保护(取值范围 0.0-1.0),比较灵敏。
  • 平均 RT:当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。
  • 并发线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。
  • 入口 QPS:当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。

在这里插入图片描述
系统规则就相当于是整个系统入口的流控,比如这里设置的是入口QPS为1,那么访问该系统的所有请求的总QPS不能超过1

@SentinelResource 配置

他的作用根Hystrix 中的@HystrixCommand 差不多

现在的问题,使用@SentinelResource注解中的blockHandler 来做兜底方法,发现和代码耦合度太高,并且每一个方法都要写的话太多。

  • 系统默认的,没有体现我们自己的业务要求
  • 使用blockHandler 来做兜底方法,我们自定义的处理方法又和业务代码耦合在一起,不直观
  • 每个业务方法都添加一个兜底的方法,那代码膨胀加剧
  • 全局统一的处理方法没有体现

解决办法,新建自定义异常处理类

/**
 * @Description: 自定义全局异常处理
 * @ClassName MyBlockHandler
 * @date: 2021.07.29 16:21
 * @Author: zhanghang
 */
public class MyBlockHandler {

	/**
	 * description: 自定义兜底方法 ,必须是静态方法,返回值必须和业务方法一致
	 * date: 2021年-07月-29日 16:22
	 * author: zhanghang
	 *
	 * @param exception
	 * @return java.lang.String
	 */
	public static String blockMethod(BlockException exception){

		return "-----统一异常处理--blockMethod";
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

@SentinelResource使用

	@GetMapping("/globalBlockHandler")
	// /testHotKey 代表rest地址,testHotKey 代表资源名,要唯一
	@SentinelResource(value = "testHotKey",  // 指定资源名
			blockHandlerClass = MyBlockHandler.class,  // 指定兜底方法的类
			blockHandler = "blockMethod")  // 指定兜底方法
	public String globalBlockHandler(){
		return " test 测试 -》 globalBlockHandler";
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

经过测试发现,兜底方法可以调到自定义类里面的方法,兜底方法和业务方法彻底耦合。
注意:1, 兜底方法的返回值必须和业务方法的返回值一致,2,兜底方法必须是静态的

注意:注解方式埋点不支持 private 方法。

@SentinelResource 用于定义资源,并提供可选的异常处理和 fallback 配置项@SentinelResource 注解包含以下属性:

  • value:资源名称,必需项(不能为空)
  • entryType:entry 类型,可选项(默认为 EntryType.OUT)
  • blockHandler / blockHandlerClass: blockHandler 对应处理 BlockException 的函数名称,可选项。blockHandler 函数访问范围需要是 public,返回类型需要与原方法相匹配,参数类型需要和原方法相匹配并且最后加一个额外的参数,类型为 BlockException。blockHandler 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 blockHandlerClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。
  • fallback/fallbackClass:fallback 函数名称,可选项,用于在抛出异常的时候提供 fallback 处理逻辑。fallback 函数可以针对所有类型的异常(除了exceptionsToIgnore里面排除掉的异常类型)进行处理。fallback 函数签名和位置要求:
    • 返回值类型必须与原函数返回值类型一致;
    • 方法参数列表需要和原函数一致,或者可以额外多一个 Throwable 类型的参数用于接收对应的异常。
    • fallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 fallbackClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。
  • defaultFallback(since 1.6.0):默认的 fallback 函数名称,可选项,通常用于通用的 fallback 逻辑(即可以用于很多服务或方法)。默认 fallback 函数可以针对所有类型的异常(除了exceptionsToIgnore里面排除的异常类型)进行处理。若同时配置了 fallback 和 defaultFallback,则只有 fallback 会生效。defaultFallback 函数签名要求:
    • 返回值类型必须与原函数返回值类型一致;
    • 方法参数列表需要为空,或者可以额外多一个 Throwable 类型的参数用于接收对应的异常。
    • defaultFallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 fallbackClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。
  • exceptionsToIgnore(since 1.6.0):用于指定哪些异常被排除掉,不会计入异常统计中,也不会进入 fallback 逻辑中,而是会原样抛出。
    1.8.0 版本开始,defaultFallback 支持在类级别进行配置。

忽略异常

// exceptionsToIgnore 的意思就是忽略指定的异常,当报出IllEgalArgumentException异常不调用fallback兜底方法,没有降级效果了
@SentinelResource(exceptionsToIgnore = {IllEgalArgumentException.class})
  • 1
  • 2

规则持久化

问题:一旦重启服务应用,sentinel规则将消失,生产环境需要将配置规则进行持久化

效果
将限流配置规则持久化进Nacos保存,只要刷新8401某个rest地址,sentinel控制台的流控规则就能看到,只要Nacos里面的配置不删除,针对8401上sentinel上的流控规则持续有效

解决步骤

  1. 修改8402的pom,新增依赖
<!--SpringCloud alibaba sentinel-datasource-nacos 后续做持久化用到的依赖-->
		<dependency>
			<groupId>com.alibaba.csp</groupId>
			<artifactId>sentinel-datasource-nacos</artifactId>
		</dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  1. 修改8402的yml配置文件,添加Nacos数据源配置
server:
  port: 8402

spring:
  application:
    name: cloudalibaba-sentinel-service
  cloud:
    nacos:
      discovery:
        # Nacos 服务注册中心地址
        server-addr: localhost:8848
    sentinel:
      transport:
        # 配置sentinel dashboard 地址
        dashboard: localhost:8080
        # 默认9719端口,假如被占用会自动从8719开始依次+1扫描,直至找到违背占用的端口
        port: 8719
      datasource:
        ds1:
          nacos:
          	server-addr: localhost:8848  # nacos注册地址
            dataId: cloudalibaba-sentinel-service # dataId,也就是nacos配置规则的dataId
            groupId: DEFAULT_GROUP  # nacos配置规则的groupId
#            namespace: public     # nacos 的命名空间
            data-type: json        # nacos配置规则的数据类型
            rule-type: flow

# 暴露监控端点
management:
  endpoints:
    web:
      exposure:
        include: '*'    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  1. 在nacos中配置规则
   
   [
   	{
   		"resource":"/testA",
   		"limitApp":"default",
   		"grade":1,
   		"count":1,
   		"strategy":0,
   		"controlBehavior":0,
   		"clusterMode":false
   	}
   ]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

在这里插入图片描述

参数说明:

  • resource: 资源名称
  • limitApp : 来源应用
  • grade: 阈值类型,0-线程数,1-QPS
  • count: 单机阈值
  • strategy: 流控模式,0-直接,1-关联,2-链路
  • controlBehavior: 流控效果,0-快速失败,1-warm up, 2-排队等待
  • clusterMode: 是否集群,false:不是,true:是

重启服务,访问/testA ,发现sentinel规则已经持久化上去

可能出现的问题,我在配置的时候持久化不生效,原因为我的java版本有问题,当我使用idea新建一个项目,使用默认版本时就可以了。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/691363
推荐阅读
相关标签
  

闽ICP备14008679号