九、Sentinel熔断与限流

Sentinel实现熔断与限流

Sentinel介绍

官网

https://github.com/alibaba/Sentinel

中文

https://github.com/alibaba/Sentinel/wiki/介绍

是什么

一句话解释,之前的Hystrix

能干嘛

去哪下

https://github.com/alibaba/Sentinel/releases

怎么玩

https://spring-cloud-alibaba-group.github.io/github-pages/hoxton/en-us/index.html#_spring_cloud_alibaba_sentinel

  • 服务使用中的各种问题
    • 服务雪崩
    • 服务降级
    • 服务熔断
    • 服务限流

安装Sentinel控制台

sentinel组件由2部分组成

Sentinel 分为两个部分:

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

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

  • 后台
  • 前台8080

安装步骤

下载

https://github.com/alibaba/Sentinel/releases

下载到本地sentinel-dashboard-1.8.2.jar

运行命令

前提

java8环境OK

8080端口不能被占用

命令

java -jar sentinel-dashboard-1.8.2.jar

访问sentinel管理界面

http://localhost:8080

登录账号密码均为sentinel

初始化演示工程

启动Nacos8848成功

http://localhost:8848/nacos/#/login

案例

创建Module:cloudalibaba-sentinel-service8401
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">
    <parent>
        <artifactId>cloud2021</artifactId>
        <groupId>com.aqrlmy.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>cloudalibaba-sentinel-service8401</artifactId>

    <dependencies>
        <dependency>
            <groupId>com.aqrlmy</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <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>
</project>
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: '*'

https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-features.html#production-ready-endpoints

主启动
package com.aqrlmy.springcloud.alibaba;

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

@EnableDiscoveryClient
@SpringBootApplication
public class MainApp8401{
    public static void main(String[] args) {
        SpringApplication.run(MainApp8401.class, args);
    }
}
业务类FlowLimitController
package com.aqrlmy.springcloud.alibaba.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class FlowLimitController{
    @GetMapping("/testA")
    public String testA() {
        return "------testA";
    }

    @GetMapping("/testB")
    public String testB() {
        return "------testB";
    }
}

启动Sentinel8080

java -jar sentinel-dashboard-1.8.2.jar

启动微服务8401

启动8401微服务后查看sentienl控制台

空空如也,啥都没有

Sentinel采用的懒加载说明

执行一次访问即可

http://localhost:8401/testA

http://localhost:8401/testB

效果

结论

sentinel8080正在监控微服务8401

流控规则

基本介绍

进一步解释说明

计算机生成了可选文字: . O 快速失败: 协厄肋Up 抛异常 O 根续乳叫eFador(冷加载因子,默认3)的值,从阂何cede「ador,经过预热时长,才达至恨 置的Qps阂值 。排队等待 匀速排队,让请求以匀速的速度通过,阂值类型必须设置为QpS,否则无效

流控模式

直接(默认)
  • 直接->快速失败
    • 系统默认
      • 测试QPS
        • 配置及说明
          • 表示1秒钟内查询1次就是OK,若超过次数1,就直接-快速失败,报默认错误

但是,在映射方法里添加sleep后,同样也会出现Blocked by Sentinel (flow limiting)默认提示信息。

  • 思考???
    • 直接调用默认报错信息,技术方面OK but,是否应该有我们自己的后续处理?
      • 类似有一个fallback的兜底方法?
关联
  • 是什么?
    • 当关联的资源达到阈值时,就限流自己
      • 当与A关联的资源B达到阈值后,就限流自己
      • B惹事,A挂了
配置A
  • 设置效果:
    • 当关联资源/testB的QPS阀值超过1时,就限流/testA的REST访问地址,当关联资源到阀值后闲置配置的的资源名。

JMeter模拟并发密集访问testB

  • 运行
    • 大批量线程高并发访问B,导致A失效了
  • 运行后发现testA挂了
    • 点击访问http://localhost:8401/testA
    • 结果
      • Blocked by Sentinel (flow limiting)
链路
  • 多个请求调用了同一个微服务

流控效果

直接->快速失败(默认的流控处理)
  • 直接失败,抛出异常:Blocked by Sentinel (flow limiting)
  • 源码:com.alibaba.csp.sentinel.slots.block.flow.controller.DefaultController
预热
  • 说明
    • 公式:阈值除以coldFactor(默认值为3),经过预热时长后才会达到阈值

  • Warmup配置

    默认 coldFactor 为 3,即请求 QPS 从 threshold / 3 开始,经预热时长逐渐升至设定的 QPS 阈值。

  • 案例:阈值为10 + 预热时长设置5秒。

  • 系统初始化的阈值为10/3约等于3,即阈值刚开始为3;然后过了5秒后阈值才慢慢升高,恢复到10

  • 多次点击http://localhost:8401/testB
  • 刚开始不行,后续慢慢OK
  • 应用场景
    • 如:秒杀系统在开启的瞬间,会有很多流量上来,很有可能把系统打死,预热方式就是为了保护系统,可慢慢的把流量放进来,慢慢的把阈值增长到设置的阈值。
排队等待
  • 匀速排队,让请求以均匀的速度通过,阈值类型必须设置成QPS,否则无效。
    • 设置含义:/testB每秒1次请求,超过的话就排队等待,等待的超时时间为20000毫秒。

  • 官网

  • 源码:com.alibaba.csp.sentinel.slots.block.flow.controller.RateLimiterController

  • 测试

    • 增加打印语句
    @GetMapping("/testB")
    public String testB() {
    log.info(Thread.currentThread().getName()+"\t ...testB");
    return "------testB";
    }
    
  • 增加线程组:直接10个线程并发,排队被依次处理

熔断规则

官网

https://github.com/alibaba/Sentinel/wiki/熔断降级

基本介绍

  • 整体介绍

熔断策略实战

慢调用比例
  • 是什么

  • 测试
    • 代码
    @GetMapping("/testA")
    public String testA() {

        try {
            Thread.sleep(300);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "------testA";
    }
  • 配置

  • 访问测试: http://localhost:8401/testA
  • 5秒内打进10个请求,由于每次请求都大于RT,并且比例阈值100%,所以,熔断器打开。

异常比例
  • 是什么

  • 测试
    • 代码
@GetMapping("/testB")
public String testB() {
        int age = 10/0;
        return "------testB";
}
  • 配置

  • 访问测试: http://localhost:8401/testB
  • 5秒内打进10个请求,由于每次请求都抛异常,异常比例阈值100%超过50%,所以,熔断器打开,10s后半开。如果再次访问有异常,则继续熔断。

异常数
  • 是什么

  • 测试
    • 代码
@GetMapping("/testB")
public String testB(){
    int age = 10/0;
    return "------testB 测试异常数";
}
  • 配置

  • 访问测试: http://localhost:8401/testB
  • 5秒内打进10个请求,由于每次请求都抛异常,异常数超过5个,所以,熔断器打开,10s后半开。如果再次访问有异常,则继续熔断。

热点规则

基本介绍

  • 是什么

官网

https://github.com/alibaba/Sentinel/wiki/热点参数限流

承上启下复习

  • 兜底方法
    • 分为系统默认和客户自定义,两种
      • 之前的case,限流出问题后,都是用sentinel系统默认的提示: Blocked by Sentinel(flow limiting)
      • 我们能不能自定义?类似hystrix,某个方法出现问题了,就找对应的兜底降级方法?
      • 结论
        • 从@HystrixCommand到@SentinelResource

代码

@GetMapping("/testHotKey")
@SentinelResource(value = "testHotKey",blockHandler = "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, BlockException exception){
    return "------deal_testHotKey,o(╥﹏╥)o";  
}

com.alibaba.csp.sentinel.slots.block.BlockException

配置

  • 配置

计算机生成了可选文字: 热点参数限流规则 192月681,1.,8720 关键字 资潦名 t6St叫Ot众y 录折

  • 默认
    • @SentinelResource(value = “testHotKey”)
    • 异常打到了前台用户界面,不友好

参数例外项

  • 上述案例演示了第一个参数p1,当QPS超过1秒1次点击后马上被限流
    • 特殊情况
      • 普通
        • 超过1秒钟一个后,达到阈值1后马上被限流
      • 我们期望p1参数当它是某个特殊值时,它的限流值和平时不一样
      • 特例
        • 假如当p1的值等于5时,它的阈值可以达到200
    • 配置
      • 添加按钮不能忘

其他

  • 手动添加一个异常看看…
    • @SentinelResource
      • 处理的是Sentinel控制台配置的违规情况,有blockHandler方法配置的兜底处理
    • RuntimeException
      • Int age = 10/0;这个是java运行时报出的运行时异常RuntimeException,@SentinelResource不管
    • 总结:
      • @SentinelResource主管配置出错,运行出错该走异常走异常

系统规则

是什么

https://github.com/alibaba/Sentinel/wiki/系统自适应限流

各项配置参数说明

配置全局QPS

@SentinelResource

官网

https://github.com/alibaba/Sentinel/wiki/注解支持

流控规则+自定义处理

  • 方法
//注意: 此处的value不能是/testC,否则请求/testC时会直接调用自定义的兜底方法
@SentinelResource(value = "testC", blockHandler = "backup_testC")
@GetMapping("/testC")
public String testC() {
    return "请求执行成功......testC";
}

//自定义兜底方法
public String backup_testC(BlockException e) {
    e.printStackTrace();
    return "自定义兜底数据......testC";
}
  • 配置流控规则

上面兜底方法面临的问题

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

集中自定义处理

  • 创建CustomerBlockHandler类用于自定义限流处理逻辑
    • 自定义限流处理类
      • 方法必须是public static修饰的。
package com.aqrlmy.springcloud.alibaba.myhandler;

import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.aqrlmy.springcloud.entities.CommonResult;

public class CustomerBlockHandler {
    
public static String handleException1(BlockException exception){
        return "自定义限流处理信息.... CustomerBlockHandler --- 1";
    }

    public static String handleException2(BlockException exception){
        return "自定义限流处理信息.... CustomerBlockHandler --- 2";
    }
}
  • FlowLimitController
@SentinelResource(value = "testD", blockHandler = "handleException1",
        blockHandlerClass = CustomerBlockHandler.class)
@GetMapping("/testD")
public String testD() {
    return "请求执行成功......testD";
}
  • 启动微服务后先调用一次

    http://localhost:8401/testD

  • Sentinel控制台配置流控规则

  • 测试后我们自定义的出来了

更多注解属性说明

    /**
     * @SentinelResource  与 Hystrix 组件中的@HystrixCommand注解作用是类似的。
     *    value = "byResourceName"  用于设置资源名称,名称不能与方法的映射路径完全一致,否则正常的请求会直接调用降级方法
     *    blockHandler 用于引用降级方法。
     *    blockHandlerClass 用于引用降级方法的处理器类。注意:降级方法必须是static的。否则,无法解析
     *    blockHandler + blockHandlerClass 只处理配置违规,进行降级处理。代码出现异常,不执行的。
     *
     *    blockHandler + fallback 同时存在,配置违规,代码也有异常,这时,走blockHandler配置文件降级处理
     *
     *    exceptionsToIgnore 设置特定异常不需要降级处理,将异常原样抛出。
     */
    @RequestMapping("/fallback/{id}")
    @SentinelResource(value = "byFallbackName",
            blockHandler = "handleException2", blockHandlerClass = CustomerBlockHandler.class,
            fallback = "handleException3", fallbackClass = CustomerBlockHandler.class,
            exceptionsToIgnore = IllegalArgumentException.class
    )
    public String fallback(@PathVariable("id") Long id) {
        if (id == 4) {
            throw new IllegalArgumentException("IllegalArgumentException,非法参数异常....");
        }

        if (id == -1) {
            CommonResult<Payment> result = new CommonResult<>(444, "数据不存在", null);
            throw new NullPointerException("NullPointerException,该ID没有对应记录,空指针异常");
        }
        return "请求成功,获取到数据" + id;
    }

熔断框架比较

在生产环境中使用 Sentinel · alibaba/Sentinel Wiki (github.com)

规则持久化

是什么

一旦我们停止应用,该应用的Sentinel规则将消失,生产环境需要将配置规则进行持久化

怎么做

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

步骤

修改:cloudalibaba-sentinel-service8401
POM
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
YML
server:
  port: 8401

spring:
  application:
    name: cloudalibaba-sentinel-service
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 #Nacos服务注册中心地址
    sentinel:
      transport:
        dashboard: localhost:8080 #配置Sentinel dashboard地址
        port: 8719
      datasource:
        ds1:
          nacos:
            server-addr: localhost:8848
            dataId: cloudalibaba-sentinel-service
            groupId: DEFAULT_GROUP
            data-type: json
            rule-type: flow

management:
  endpoints:
    web:
      exposure:
        include: '*'
添加Nacos业务规则配置

  • 内容解析
[
    {
         "resource": "/testA",
         "limitApp": "default",
         "grade": 1,
         "count": 1,
         "strategy": 0,
         "controlBehavior": 0,
         "clusterMode": false 
    }
]

启动8401并访问接口

访问8401的任意接口,如:http://localhost:8401/testA

刷新sentinel发现业务规则有了

计算机生成了可选文字: 应用名 搜索 C10Uda11baba一sentine卜Se四iCe 巨 O首页 CIOUdsllbsbs一Sentlne!- SerVICe (111)" 涂控规则 关键字 匹实时监控 资源名 阅值类型 阅值团值模式 圈簇点链路 Ir分teLlmltlbyUn 来源应用流控模式 defautt直接 OPS 单机 流控效果 快速失败 共1条记录,每页 手降级规则

快速访问测试接口

http://localhost:8401/testA

流控规则生效,响应默认的兜底数据

停止8401再看sentinel

因为应用停止,所以监测不到数据

重新启动8401并访问接口

访问8401的接口:http://localhost:8401/testA

再看sentinel,配置出现了,持久化验证通过

了解

若需要配置其它规则,参照对应类的属性进行json的配置

流控规则:com.alibaba.csp.sentinel.slots.block.flow.FlowRule

熔断/降级规则:com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule

热点规则:com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule

系统规则:com.alibaba.csp.sentinel.slots.system.SystemRule

授权规则:com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule

之前的配置可以让我们启动项目就加载nacos配置好的规则,但是在Sentinel 控制台上修改后,nacos中的配置文件不会修改。
如果要做到同步到nacos中,需要对源码进行扩展。
参考文档:
Sentinel 基于Nacos规则持久化-推模式
[(企业案例)使用Nacos持久化规则,改造sentinel-dashboard](

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值