Sentinel 初级使用

           根据 alibaba 官网说明,Sentinel 在 1.8.0 版本有较大的改进,以下使用的 Sentinel 版本为 1.7.0

sentinel 资源链接 提取码:kui6

1. Sentinel 的组成

  • 核心库(Java 客户端)不依赖任何框架/库,能够运行于所有 Java 运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持。

  • 控制台(Dashboard)基于 Spring Boot 开发,打包后可以直接运行,不需要额外的 Tomcat 等应用容器。

1.控制台启动

  1. https://github.com/alibaba/Sentinel/releases 下载 sentinel-dashboard-1.7.0.jar 到本地

  2. 运行:java -jar sentinel-dashboard-1.7.0.jar

  3. 访问:http://localhost:8080

  4. 初始账号密码:sentinel

  5. 启动 nacos (负责 Sentinel 规则持久化)

2. 创建新项目测试

  1. 创建 Module:cloudalibaba-sentinel-service8401

  2. POM

<dependencies>
	<dependency>
		<groupId>com.atguigu</groupId>
		<artifactId>cloud-api-commons</artifactId>
		<version>${project.version}</version>
	</dependency>
	<!-- Nacos -->
	<dependency>
		<groupId>com.alibaba.cloud</groupId>
		<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
	</dependency>
	<!-- 负责 sentinel 持久化 -->
	<dependency>
		<groupId>com.alibaba.csp</groupId>
		<artifactId>sentinel-datasource-nacos</artifactId>
	</dependency>
	
	<!-- sentinel -->
	<dependency>
		<groupId>com.alibaba.cloud</groupId>
		<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
	</dependency>
	<!-- OpenFeign -->
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-openfeign</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-web</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-actuator</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-devtools</artifactId>
		<scope>runtime</scope>
		<optional>true</optional>
	</dependency>
	<dependency>
		<groupId>cn.hutool</groupId>
		<artifactId>hutool-all</artifactId>
		<version>4.6.3</version>
	</dependency>
	<dependency>
		<groupId>org.projectlombok</groupId>
		<artifactId>lombok</artifactId>
		<optional>true</optional>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-test</artifactId>
		<scope>test</scope>
	</dependency>
</dependencies>
  1. YML
server:
  port: 8401

spring:
  application:
    name: cloudalibaba-sentinel-service
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
    sentinel:
      transport:
        dashboard: localhost:8080 # 控制台地址
        port: 8719  #默认8719,应用与Sentinel控制台交互的端口,应用本地会起一个该端口占用HttpServer

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

注:这里的 spring.cloud.sentinel.transport.port 端口配置会在应用对应的机器上启动一个 Http Server ,该 Server 会与 Sentinel 控制台做交互。比如 Sentinel 控制台添加了一个限流规则,会把规则数据 push 给这个 Http Server 接收,Http Server 再将规则注册到 Sentinel 中。

  1. 主启动
@EnableDiscoveryClient
@SpringBootApplication
public class MainApp8401{
    public static void main(String[] args) {
        SpringApplication.run(MainApp8401.class, args);
    }
}
  1. 业务类
@RestController
@Slf4j
public class FlowLimitController{
    @GetMapping("/testA")
    public String testA() {
        return "------testA";
    }

    @GetMapping("/testB")
    public String testB() {
        return "------testB";
    }
}
  1. 启动
  • 启动 sentinel 8080:java -jar sentinel-dashboard-1.7.0.jar

  • 启动微服务 8401

注:Sentinel 采用的懒加载模式,我们需要访问一次,sentinel 才会加载监控的业务

2. 流控规则

博客:
sentinel流控模式:链路模式失效问题
Spring Cloud Alibaba:Sentinel 流控规则

1. 直接:达到条件直接失败

注:上述配置表示,QPS,即每秒访问次数超过 1 次,就直接快速失败,报默认错误;
注:上述配置表示,每秒线程数超过 1,就直接快速失败,报默认错误;

2. 关联:关联的微服务达到条件时,指定资源失败;

3. 链路

链路流控模式指的是,当从某个接口过来的资源达到限流条件时,开启限流。它的功能有点类似于针对来源配置项,区别在于:针对来源是针对上级微服务,而链路流控是针对上级接口,也就是说它的粒度更细。

下面建议将 spring-cloud-alibaba 的版本改为 2.1.1.RELEASE

  • 编写一个 service
@Service
public class FlowControlServiceImpl implements FlowControlService {

    @Override
    @SentinelResource(value = "testC")      // Sentinel 默认会将 controller 映射为资源名,我们也可以用此注解表明资源名
    public void testC() {
        System.out.println("------testC");
    }
    public void testC_Handler(){
        System.out.println("------testC_Handler");
    }
}
  • 在 controller 的两个接口中,调用这个方法
@RestController
@Slf4j
public class FlowLimitController{

    @Resource
    private FlowControlService flowControlService;

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

    @GetMapping("/testB")
    public String testB() {
        flowControlService.testC();
        return "------testB";
    }
}
  • 配置文件中关闭sentinel官方的CommonFilter实例化
spring:
    cloud:
        sentinel:
            filter:
                enabled: false
  • 添加配置类,自己构建 CommonFilter 实例
@Configuration
public class FilterContextConfig {

    @Bean
    public FilterRegistrationBean sentinelFilterRegistration() {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
        registrationBean.setFilter(new CommonFilter());
        registrationBean.addUrlPatterns("/*");
        // 入口资源关闭聚合
        registrationBean.addInitParameter(CommonFilter.WEB_CONTEXT_UNIFY, "false");
        registrationBean.setName("sentinelFilter");
        registrationBean.setOrder(1);

        return registrationBean;
    }
}
  • 在添加完链路流控规则后,测试,发现资源 testC 被限制了

3.降级规则

现代微服务架构都是分布式的,由非常多的服务组成。不同服务之间相互调用,组成复杂的调用链路。以上的问题在链路调用中会产生放大的效果。复杂链路上的某一环不稳定,就可能会层层级联,最终导致整个链路都不可用。因此我们需要对不稳定的弱依赖服务调用进行熔断降级,暂时切断不稳定调用,避免局部不稳定因素导致整体的雪崩。熔断降级作为保护自身的手段,通常在客户端(调用端)进行配置。

1.熔断策略

  • 平均响应时间 (DEGRADE_GRADE_RT):当 1s 内持续进入 5 个请求,对应时刻的平均响应时间(秒级)均超过阈值(count,以 ms 为单位),那么在接下来的时间窗口(DegradeRule 中的 timeWindow,以 s 为单位)之内,对这个方法的调用都会自动熔断(抛出 DegradeException)。注意:窗口期过后关闭断路器RT 最大4900 ms,更大的需要通过启动配置项 -Dcsp.sentinel.statistic.max.rt=xxx 来配置。

  • 异常比例(DEGRADE_GRADE_EXCEPTION_RATIO):当资源的每秒请求量 >= 5,并且每秒异常总数占通过量的比值超过阈值(Degrade 中的 count)之后,资源进入降级状态,即在接下来的时间窗口(DegradeRule 中的 timeWindow,以 s 为单位)之内,对这个方法的调用都会自动降级。异常比例的范围是 [0.0, 1.0],代表 0% - 100%

  • 异常数(DEGRADE_GRADE_EXCEPTION_COUNT):当资源近 1 分钟的异常数超过阈值之后会进行熔断。注意由于统计时间窗口是分钟级别的,若 timeWindow 小于 60s,则结束熔断之后仍可能再进入熔断

说明:

  • Sentinel 熔断降级会在调用链路中某个资源出现不稳定状态时(例如:调用超时或异常比例升高),对这个资源的调用进行限制,让请求快速失败,避免影响到其他的资源而导致级联错误。当资源被降级后,在接下来的降级时间窗口之内,对该资源的调用都自动熔断(默认行为是抛出DegradeException)。

  • Sentinel的断路器是没有半开状态的(1.8.0 之后有较大改动,新增半开状态)。半开的状态系统自动去检测是否请求有异常,没有异常就关闭断路器恢复使用,有异常则继续打开断路器不可用。具体可以参考Hystrix

降级实测

  1. 新增 controller 接口
@GetMapping("/testD")
// 资源最好不要和 mapping 一样
@SentinelResource(value = "testD", fallback = "fallback")
public String testD(){
    try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
    log.info("testD 测试RT");
    return "------testD";
}

public String fallback(){
    System.out.println("fallback");
    return "fallback";
}
  1. 新增降级规则
  1. 测试效果
  1. 其他配置示例

4. 热点 Key 限流

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

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

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

Sentinel利用LRU策略统计最近最常访问的热点参数,结合令牌桶算法来进行参数级别的流控。热点参数限流支持集群模式。

实测

  1. 新增 controller 接口
@GetMapping("/testHotKey")
@SentinelResource(value = "testHotKey",fallback = "deal_testHotKey")
public String testHotKey(@RequestParam(value = "p1",required = false) String p1,
                         @RequestParam(value = "p2",required = false) String p2) {
    int age = 10/0;
    return "------testHotKey";
}

//兜底方法
public String deal_testHotKey (String p1, String p2){
    return "------deal_testHotKey,o(╥﹏╥)o";
}

@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 支持在类级别进行配置。

特别地,若 blockHandler 和 fallback 都进行了配置,则被限流降级而抛出 BlockException 时只会进入 blockHandler 处理逻辑。若未配置 blockHandler、fallback 和 defaultFallback,则被限流降级时会将 BlockException 直接抛出(若方法本身未定义 throws BlockException 则会被 JVM 包装一层 UndeclaredThrowableException)。

posted @ 2022-05-28 23:14  ayi8  阅读(127)  评论(0编辑  收藏  举报