Sentinel实战应用

Sentinel实战应用

  • Sentinel实战应用
    • 1 Sentinel核心库
      • 1.1 Sentinel介绍
      • 1.2 Sentinel核心功能
        • 1.2.1 流量控制
        • 1.2.2 熔断降级
      • 1.3 Sentinel熔断限流
        • 1.3.1 SpringBoot集成
          • 1.3.1.1 @SentinelResource注解
          • 1.3.1.2 blockHandler
          • 1.3.1.3 fallback
          • 1.3.1.4 defaultFallback
        • 1.3.2 限流降级规则
          • 1.3.2.1 流量控制
          • 1.3.2.2 熔断降级
          • 1.3.2.3 系统自我保护
          • 1.3.2.4 热点数据
        • 1.3.3 OpenFeign支持
          • 1.3.3.1 fallback
          • 1.3.3.2 fallbackFactory
    • 2 Sentinel集成Gateway
      • 2.1 Sentinel对网关支持
      • 2.2 集成Sentinel
      • 2.3 配置/API定义
    • 3 Sentinel控制台
      • 3.1 Sentinel控制台安装
      • 3.2 接入控制台
      • 3.3 可视化管理
        • 3.31 实时监控
        • 3.3.2 流控规则
        • 3.3.3 降级规则
        • 3.3.4 热点数据

Sentinel实战应用

1 Sentinel核心库

Sentinel主页 https://github.com/alibaba/Sentinel/wiki/%E4%B8%BB%E9%A1%B5

1.1 Sentinel介绍

Sentinel实战应用_第1张图片
随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 是面向分布式服务架构的流量控制组件,主要以流量为切入点,从限流、流量整形、熔断降级、系统负载保护、热点防护等多个维度来帮助开发者保障微服务的稳定性。

1)Sentinel核心组件

1:核心库(Java 客户端):不依赖任何框架/库,能够运行于 Java 7 及以上的版本的运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持。 
2:控制台(Dashboard):控制台主要负责管理推送规则、监控、集群限流分配管理、机器发现等。 

2)Sentinel vs Hystrix
Sentinel实战应用_第2张图片
3)Sentinel基本概念

  • 资源
资源是 Sentinel 的关键概念。它可以是 Java 应用程序中的任何内容,例如,由应用程序提供的服务,或由应用程序调用的其它应用提供的服务,甚至可以是一段代码。 
只要通过 Sentinel API 定义的代码,就是资源,能够被 Sentinel 保护起来。大部分情况下,可以使用方法签名,URL,甚至服务名称作为资源名来标示资源。 
  • 规则
围绕资源的实时状态设定的规则,可以包括流量控制规则、熔断降级规则以及系统保护规则。所有规则可以 动态实时调整。

1.2 Sentinel核心功能

1.2.1 流量控制

流量控制在网络传输中是一个常用的概念,它用于调整网络包的发送数据。然而,从系统稳定性角度考虑,在处理请求的速度上,也有非常多的讲究。任意时间到来的请求往往是随机不可控的,而系统的处理能力是有限的。我们需要根据系统的处理能力对流量进行控制。Sentinel 作为一个调配器,可以根据需要把随机的请求调整成合适的形状,如下图所示:
Sentinel实战应用_第3张图片
流量控制有以下几个角度:

  • 资源的调用关系,例如资源的调用链路,资源和资源之间的关系;
  • 运行指标,例如 QPS、线程池、系统负载等;
  • 控制的效果,例如直接限流、冷启动、排队等。

Sentinel 的设计理念是让您自由选择控制的角度,并进行灵活组合,从而达到想要的效果。

1.2.2 熔断降级

1)什么是熔断降级
除了流量控制以外,及时对调用链路中的不稳定因素进行熔断也是 Sentinel 的使命之一。由于调用关系的复杂性,如果调用链路中的某个资源出现了不稳定,可能会导致请求发生堆积,进而导致级联错误。
Sentinel实战应用_第4张图片
Sentinel 和 Hystrix 的原则是一致的: 当检测到调用链路中某个资源出现不稳定的表现,例如请求响应时间长或异常比例升高的时候,则对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联故障。

2)Sentinel熔断降级设计
Hystrix 通过 线程池隔离 的方式,来对依赖(在 Sentinel 的概念中对应 资源)进行了隔离。这样做的好处是资源和资源之间做到了最彻底的隔离。缺点是除了增加了线程切换的成本(过多的线程池导致线
程数目过多),还需要预先给各个资源做线程池大小的分配。
Sentinel熔断降级设计:

并发线程数限制:和资源池隔离的方法不同,Sentinel 通过限制资源并发线程的数量,来减少不稳定资源 对其它资源的影响。这样不但没有线程切换的损耗,也不需要您预先分配线程池的大小。当某个资源出现不 稳定的情况下,例如响应时间变长,对资源的直接影响就是会造成线程数的逐步堆积。当线程数在特定资源 
上堆积到一定的数量之后,对该资源的新请求就会被拒绝。堆积的线程完成任务后才开始继续接收请求。 
响应时间降级:除了对并发线程数进行控制以外,Sentinel 还可以通过响应时间来快速降级不稳定的资 源。当依赖的资源出现响应时间过长后,所有对该资源的访问都会被直接拒绝,直到过了指定的时间窗口之 后才重新恢复。

3)系统自适应保护
Sentinel 同时提供系统维度的自适应保护能力。防止雪崩,是系统防护中重要的一环。当系统负载较高的时候,如果还持续让请求进入,可能会导致系统崩溃,无法响应。在集群环境下,网络负载均衡会把本应这台机器承载的流量转发到其它的机器上去。如果这个时候其它的机器也处在一个边缘状态的时候,这个增加的流量就会导致这台机器也崩溃,最后导致整个集群不可用。
针对这个情况,Sentinel 提供了对应的保护机制,让系统的入口流量和系统的负载达到一个平衡,保证系统在能力范围之内处理最多的请求。

1.3 Sentinel熔断限流

Sentinel 可以简单的分为 Sentinel 核心库和 Dashboard。核心库不依赖 Dashboard,但是结合Dashboard 可以取得最好的效果。我们先来学习Sentinel 核心库的使用,后面再学习Dashboard使用。
Sentinel实战应用_第5张图片
在我们项目中,用户请求通过 hailtaxi-gateway 路由到 hailtaxi-driver 或者 hailtaxi-order ,还有可能在 hailtaxi-order 中使用feign调用 hailtaxi-driver ,所以我们有可能在单个服务中实现熔断限流,也有可能要集成feign调用实现熔断限流,还有可能在微服务网关中实现熔断限流。我们接下来一步一步实现每一种熔断限流操作。

1.3.1 SpringBoot集成

如果在SpringBoot项目中使用Sentinel,首先需要引入 spring-cloud-starter-alibaba-sentinel 依赖,并使用 @SentinelResource 标识资源。

1.3.1.1 @SentinelResource注解

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

Sentinel实战应用_第6张图片

1.3.1.2 blockHandler

用户在打车的时候,会查询司机信息,如果司机不存在,此时会报错,代码如下:
Sentinel实战应用_第7张图片
如果此时访问 http://localhost:18081/driver/info/3 查询司机信息,如果没有ID为3的司机信息,会报如下错误,这种体验非常查,我们可以集成Sentinel使用 @SentinelResource 的 blockHandler 返回默认错误信息。
Sentinel实战应用_第8张图片
在 hailtaxi-driver 工程中引入 spring-cloud-starter-alibaba-sentinel 依赖,依赖如下:

  <dependency>
            <groupId>com.alibaba.cloudgroupId>
            <artifactId>spring-cloud-starter-alibaba-sentinelartifactId>
            <version>2.2.5.RELEASEversion>
        dependency>

我们先添加一个方法 blockExHandler ()用来处理程序发生BlockException 异常的时候,执行默认操作,代码如下:

 /***
     * BlockException异常处理
     */
    public Driver blockExHandler(String id,BlockException ex){
        Driver driver = new Driver();
        driver.setId(id);
        driver.setName("bbb");
        return driver;
    }

我们为 info() 方法添加一个 @SentinelResource 注解,用来标注资源,表示当前方法需要执行限流、降级,在注解中添加value属性,用来标注资源,说白了就是给当前资源起个名字,blockHandler用来表示当前方法发生 BlockException 异常的时候,将处理流程交给指定的方法 blockExHandler()处理,此时 blockExHandler() 方法必须和抛出异常的方法在同一个类中,这是一种降级操作,代码如下:
Sentinel实战应用_第9张图片
如果此时不在同一个类中,我们可以在 @SentinelResource 中添加 blockHandlerClass 属性,指定降级处理类的方法所在的类,代码如下:

@SentinelResource(value = "info",blockHandler = "blockExHandler",blockHandlerClass = "xxx.xxx.Xxxx")

访问 http://localhost:18081/driver/info/3 测试出错效果如下:
Sentinel实战应用_第10张图片

1.3.1.3 fallback

如果我们希望抛出任何异常都能处理,都能调用默认处理方法,而并非只是 BlockException 异常才调用,此时可以使用 @SentinelResource 的 fallback 属性,代码如下
Sentinel实战应用_第11张图片
访问 http://localhost:18081/driver/info/3 测试出错效果如下:
Sentinel实战应用_第12张图片
如果发生异常执行的方法和当前发生异常的方法不在同一个类中,可以使用 @SentinelResource 注解的 fallbackClass 实现,代码如下:

@SentinelResource(value = "info",fallback ="exHandler" ,fallbackClass = "xx.xxx.xxx.xx.Xxx")
1.3.1.4 defaultFallback

上面无论是 blockHandler 还是 fallback ,每个方法发生异常,都要为方法独立创建一个处理异常的方法,效率非常低,我们可以使用 @SentinelResource 注解的 defaultFallback 属性,为一个类指定
一个全局的处理错误的方法,代码如下

@RestController
@RequestMapping(value = "/driver")
@RefreshScope
@SentinelResource(defaultFallback ="defaultExFallback")
public class DriverController {

    /***
     * 异常处理
     */
    public Driver defaultExFallback() {
        Driver driver = new Driver();
        driver.setName("系统繁忙,请稍后再试!");
        return driver;
    }

    /***
     * 搜素指定城市的司机
     */
    //@SentinelResource(value = "search")
    @GetMapping(value = "/search/{city}")
    public Driver search(@PathVariable(value = "city")String city){
        System.out.println("查询的司机所在城市:"+city);
        //假设查询到了一个司机信息
        Driver driver = new Driver();
        driver.setName("张三");
        driver.setId("No.1");
        return driver;
    }

    /****
     * 司机信息
     */
    //@SentinelResource(value = "info",blockHandler = "blockExHandler")
    //@SentinelResource(value = "info",fallback ="exHandler")
    //@SentinelResource(value = "info")
    @GetMapping(value = "/info/{id}")
    public Driver info(@PathVariable(value = "id")String id) throws InterruptedException{
        Driver driver = driverService.findById(id);
        //if(id.equals("1")){
        //    TimeUnit.SECONDS.sleep(10);
        //}
        if(driver==null){
            throw new RuntimeException("司机不存在");
            //throw new SystemBlockException("info","hailtaxi-driver");//必须抛出BlockException才会生效
        }
        driver.setName(driver.getName()+",IP="+ip);
        return driver;
    }

此时需要注意, defaultFallback 属性指定的方法入参必须为空,最多可以增加一个异常对象。
我们访问 http://localhost:18081/driver/info/3 效果如下:
Sentinel实战应用_第13张图片

1.3.2 限流降级规则

Sentinel支持多种限流规则,规则我们可以在代码中直接定义,规则属性如下:
Sentinel实战应用_第14张图片

1.3.2.1 流量控制

理解上面规则的定义之后,我们可以通过调用FlowRuleManager.loadRules() 方法来用硬编码的方式定义流量控制规则。
1)QPS流量控制
我们先实现流量基于QPS控制,在 hailtaxi-driver 的 DriverApplication 启动类上添加如下方法加载限流规则,当 DriverApplication 初始化完成之后加载规则,代码如下:

 /***
     * 初始化规则
     */
    @PostConstruct
    private void initFlowQpsRule() {
        //规则集合
        List<FlowRule> rules = new ArrayList<FlowRule>();
        //定义一个规则
        FlowRule rule = new FlowRule("info");
        // 设置阈值
        rule.setCount(2);
        //设置限流阈值类型
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);//QPS控制
        //default,代表不区分调用来源
        rule.setLimitApp("default");
        //将定义的规则添加到集合中
        rules.add(rule);
        //加载规则
        FlowRuleManager.loadRules(rules);
    }

我们访问 http://localhost:18081/driver/info/1 此时不会抛出异常,但是频繁刷新,则会调用降级方法,效果如下:
Sentinel实战应用_第15张图片
2)线程数流量控制

我们修改限流阈值类型,代码如下:

@PostConstruct
    private void initFlowQpsRule() {
        //规则集合
        List<FlowRule> rules = new ArrayList<FlowRule>();
        //定义一个规则
        FlowRule rule = new FlowRule("info");
        // 设置阈值
        rule.setCount(2);
        //设置限流阈值类型
        //rule.setGrade(RuleConstant.FLOW_GRADE_QPS);//QPS控制
        rule.setGrade(RuleConstant.FLOW_GRADE_THREAD);//线程数控制
        //default,代表不区分调用来源
        rule.setLimitApp("default");
        //将定义的规则添加到集合中
        rules.add(rule);
        //加载规则
        FlowRuleManager.loadRules(rules);
    }

此时再来访问 http://localhost:18081/driver/info/1 我们发现用浏览器无论怎么访问都不会出现降级现象,但是如果用Jmeter模拟多个线程,效果就不一样了,效果如下:

1.3.2.2 熔断降级

熔断降级规则包含下面几个重要的属性:
Sentinel实战应用_第16张图片
同一个资源可以同时有多个降级规则。理解上面规则的定义之后,我们可以通过调用DegradeRuleManager.loadRules() 方法来用硬编码的方式定义流量控制规则,在DriverApplication 规则定义如下:

@PostConstruct
    private void initDegradeRule() {
        //降级规则集合
        List<DegradeRule> rules = new ArrayList<DegradeRule>();
        //降级规则对象
        DegradeRule rule = new DegradeRule();
        //设置资源
        rule.setResource("info");
        //设置触发降级阈值
        rule.setCount(2);
        //熔断降级策略,支持慢调用比例/异常比例/异常数策略
        //DEGRADE_GRADE_RT:平均响应时间
        //DEGRADE_GRADE_EXCEPTION_RATIO:异常比例数量
        //DEGRADE_GRADE_EXCEPTION_COUNT:异常数
        rule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT);
        //熔断窗口时长,单位为 s
        rule.setTimeWindow(10);
        //将规则添加到集合中
        rules.add(rule);
        //加载规则
        DegradeRuleManager.loadRules(rules);
    }

我们来测试一下平均响应时间,在程序中休眠10秒中,再执行访问,代码如下:
Sentinel实战应用_第17张图片
测试效果如下:
Sentinel实战应用_第18张图片
我们可以发现只有2个访问是成功的,并且熔断降级10秒钟之后才可接着访问该方法。
Sentinel实战应用_第19张图片

1.3.2.3 系统自我保护

Sentinel 系统自适应限流从整体维度对应用入口流量进行控制,结合应用的 Load、CPU 使用率、总体平均 RT、入口 QPS 和并发线程数等几个维度的监控指标,通过自适应的流控策略,让系统的入口流量和系统的负载达到一个平衡,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。
系统规则包含下面几个重要的属性:
Sentinel实战应用_第20张图片
理解上面规则的定义之后,我们可以通过调用SystemRuleManager.loadRules() 方法来用硬编码的方式定义流量控制规则。
在 hailtaxi-driver 的 DriverApplication 中创建如下方法,代码如下:

 /***
     * 系统自我保护
     */
    @PostConstruct
    private void initSystemRule() {
        //系统自我保护集合
        List<SystemRule> rules = new ArrayList<>();
        //创建系统自我保护规则
        SystemRule rule = new SystemRule();
        //CPU使用率 值为0-1,-1 (不生效)
        rule.setHighestCpuUsage(0.2);
        //所有入口资源的 QPS,-1 (不生效)
        rule.setQps(10);
        //入口流量的最大并发数,-1 (不生效)
        rule.setMaxThread(5);
        //所有入口流量的平均响应时间,单位:秒,-1 (不生效)
        rule.setAvgRt(5);
        //load1 触发值,用于触发自适应控制阶段,系统最高负载,建议取值 CPU cores * 2.5
        rule.setHighestSystemLoad(20);
        //将规则加入到集合
        rules.add(rule);
        SystemRuleManager.loadRules(rules);
    }

我们可以测试CPU使用率自我保护,如下效果
在这里插入图片描述
https://www.jianshu.com/p/3668cc1bf24a

1.3.2.4 热点数据

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

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

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

Sentinel实战应用_第21张图片
Sentinel 利用 LRU 策略统计最近最常访问的热点参数,结合令牌桶算法来进行参数级别的流控。热点参数限流支持集群模式。
要使用热点参数限流功能,需要引入以下依赖:


        <dependency>
            <groupId>com.alibaba.cspgroupId>
            <artifactId>sentinel-parameter-flow-controlartifactId>
            <version>1.8.1version>
        dependency>

然后为对应的资源配置热点参数限流规则,并在 entry 的时候传入相应的参数,即可使热点参数限流生效。
热点参数规则( ParamFlowRule )类似于流量控制规则( FlowRule ):
Sentinel实战应用_第22张图片
clusterMode 是否是集群参数流控规则 false
clusterConfig 集群流控相关配置

我们可以创建一个司机筛选方法,比如根据城市来筛选,在 DriverController 中创建一个方法

/***
     * 搜素指定城市的司机
     */
    @SentinelResource(value = "search")
    @GetMapping(value = "/search/{city}")
    public Driver search(@PathVariable(value = "city")String city){
        System.out.println("查询的司机所在城市:"+city);
        //假设查询到了一个司机信息
        Driver driver = new Driver();
        driver.setName("张三");
        driver.setId("No.1");
        return driver;
    }

我们可以对热门参数比如下标为0的参数流量进行控制,对热点数据执行特殊限流,比如参数值为 tj 的时候执行限流,在 DriverApplication 中创建限流配置,代码如下:

 /***
     * 系统自我保护
     */
    @PostConstruct
    private void initSystemRule() {
        //系统自我保护集合
        List<SystemRule> rules = new ArrayList<>();
        //创建系统自我保护规则
        SystemRule rule = new SystemRule();
        //CPU使用率 值为0-1,-1 (不生效)
        rule.setHighestCpuUsage(0.2);
        //所有入口资源的 QPS,-1 (不生效)
        rule.setQps(10);
        //入口流量的最大并发数,-1 (不生效)
        rule.setMaxThread(5);
        //所有入口流量的平均响应时间,单位:秒,-1 (不生效)
        rule.setAvgRt(5);
        //load1 触发值,用于触发自适应控制阶段,系统最高负载,建议取值 CPU cores * 2.5
        rule.setHighestSystemLoad(20);
        //将规则加入到集合
        rules.add(rule);
        SystemRuleManager.loadRules(rules);
    }

我们访问 http://localhost:18081/driver/search/shenzhen 的时候,连续执行5次,才会限流,效果如下:
Sentinel实战应用_第23张图片
我们访问 http://localhost:18081/driver/search/tj 的时候,连续执行2次,就会限流,效果如下:
Sentinel实战应用_第24张图片

1.3.3 OpenFeign支持

Sentinel 适配了 Feign 组件。如果想使用,除了引入 spring-cloud-starter-alibaba-sentinel 的依赖外还需要 2 个步骤:

1:配置文件打开 Sentinel 对 Feign 的支持:feign.sentinel.enabled=true 
2:加入 spring-cloud-starter-openfeign 依赖使 Sentinel starter 中的自动化配置类生效

Sentinel实战应用_第25张图片
在上面案例中,我们可以实现用户打车成功调用 hailtaxi-order 执行下单,并且通过feign调用hailtaxi-driver 修改司机状态,此时我们可以使用Sentinel实现Feign调用降级、限流。
我们把之前的案例中 @SentinelResource 相关注解全部注释掉,再实现Feign集成。

在 hailtaxi-driver 中引入 OpenFeign 依赖,配置如下:

   
        <dependency>
            <groupId>com.alibaba.cloudgroupId>
            <artifactId>spring-cloud-starter-alibaba-sentinelartifactId>
            <version>2.2.5.RELEASEversion>
        dependency>

        
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-openfeignartifactId>
        dependency>

还需要在Feign调用客户端(也就是 hailtaxi-order )中开启Feign的支持,配置如下:

feign:
  compression:
    request:
      enabled: true # 开启请求压缩
      mime-types: text/html,application/xml,application/json # 设置压缩的数据类型
      min-request-size: 2048 # 设置触发压缩的大小下限
      #以上数据类型,压缩大小下限均为默认值
    response:
      enabled: true # 开启响应压缩
  #开启Sentinel对Feign的支持
  sentinel:
    enabled: true

为了测试程序异常能实现降级操作,我们在 hailtaxi-order 中将 OrderInfoController.add() 方法的司机ID改成一个不存在的司机ID,让程序报错,测试降级处理,代码如下:
Sentinel实战应用_第26张图片

1.3.3.1 fallback

我们可以为Feign接口创建一个实现类,在实现类中处理程序异常降级处理方法,代码如下:

@Component
public class DriverFeignFallback implements DriverFeign {

    /**
     * status()降级处理方法
     */
    @Override
    public Driver status(String id, Integer status) {
        Driver driver = new Driver();
        driver.setId(id);
        driver.setStatus(status);
        driver.setName("系统比较繁忙,请您稍后再试!");
        return driver;
    }
}

我们还需要在Feign接口上添加 fallback 属性指定讲解处理的类,代码如下:

@FeignClient(value = "hailtaxi-driver",fallback = DriverFeignFallback.class)

此时运行,会发生如下问题:

parseAndValidatateMetadata(Ljava/lang/Class;)Ljava/util/List;

出现上面问题的主要原因是当前SpringCloud版本存在问题。Hoxton.SR1 中, fegin.context 接口方法的定义为parseAndValidatateMetadata Hoxton.SR3中, fegin.context 接口方法的定义为 parseAndValidateMetadata
我们现在需要把 Hoxton.SR1 换成 Hoxton.SR3 ,因此需要在 hailtaxi-parent 修改SpringCloud版本:

将 SpringCloud 版本升级至 Hoxton.SR3 同时将 SpringBoot 版本升级至 2.2.10 ,如上图:
此时我们测试,效果如下:

1.3.3.2 fallbackFactory

我们可以为Feign接口创建一个降级处理的工厂对象,在工厂对象中处理程序异常降级处理方法,代码如下:

@Component
public class DriverFeignFallbackFactory implements FallbackFactory<DriverFeign> {

    @Override
    public DriverFeign create(Throwable throwable) {
        return new DriverFeign() {

            /**
             * status()降级处理方法
             */
            @Override
            public Driver status(String id, Integer status) {
                Driver driver = new Driver();
                driver.setId(id);
                driver.setStatus(status);
                driver.setName("系统比较繁忙,请您稍后再试!");
                return driver;
            }
        };
    }
}

我们还需要在Feign接口上添加 fallbackFactory 属性指定讲解处理的类,代码如下:

@FeignClient(value = "hailtaxi-driver",fallbackFactory = DriverFeignFallbackFactory.class)

此时我们测试,效果如下:
Sentinel实战应用_第27张图片

2 Sentinel集成Gateway

我们的项目流量入口是 SpringCloud Gateway ,因此我们重点讲解Sentinel集成 Gateway 。

2.1 Sentinel对网关支持

Sentinel 支持对 Spring Cloud Gateway、Zuul 等主流的 API Gateway 进行限流。

Sentinel 1.6.0 引入了 Sentinel API Gateway Adapter Common 模块,此模块中包含网关限流的规则和自定义 API 的实体和管理逻辑:

  • GatewayFlowRule :网关限流规则,针对 API Gateway 的场景定制的限流规则,可以针对不同 route 或自定义的API 分组进行限流,支持针对请求中的参数、Header、来源 IP 等进行定制化的 限流。
  • ApiDefinition :用户自定义的 API 定义分组,可以看做是一些 URL 匹配的组合。比如我们可以 定义一个 API 叫my_api ,请求 path 模式为 /foo/ 和 /baz/的都归到 my_api 这个 API分组下面。限流的时候可以针对这个自定义的 API 分组维度进行限流。

其中网关限流规则 GatewayFlowRule 的字段解释如下:

  • resource :资源名称,可以是网关中的 route 名称或者用户自定义的 API 分组名称。
  • resourceMode :规则是针对 API Gateway 的 route(RESOURCE_MODE_ROUTE_ID)还是用户在Sentinel 中定义的 API 分组( RESOURCE_MODE_CUSTOM_API_NAME ),默认是route。
  • grade :限流指标维度,同限流规则的 grade 字段。
  • count :限流阈值
  • intervalSec :统计时间窗口,单位是秒,默认是 1 秒。
  • controlBehavior :流量整形的控制效果,同限流规则controlBehavior 字段,目前支持快速失败和匀速排队两种模式,默认是快速失败。
  • burst :应对突发请求时额外允许的请求数目。
  • maxQueueingTimeoutMs :匀速排队模式下的最长排队时间,单位是毫秒,仅在匀速排队模式下生效。
  • paramItem
    :参数限流配置。若不提供,则代表不针对参数进行限流,该网关规则将会被转换成普通流控规则;否则会转换成热点规则。其中的字段:
    parseStrategy :从请求中提取参数的策略,目前支持提取来源
    IP( PARAM_PARSE_STRATEGY_CLIENT_IP )、Host( PARAM_PARSE_STRATEGY_HOST )、 任意 Header( PARAM_PARSE_STRATEGY_HEADER )和任意 URL 参数
    ( PARAM_PARSE_STRATEGY_URL_PARAM )四种模式。
    fieldName :若提取策略选择 Header 模式或 URL 参数模式,则需要指定对应的 header 名称或 URL 参数名称。
    pattern :参数值的匹配模式,只有匹配该模式的请求属性值会纳入统计和流控;若为空则 统计该请求属性的所有值。(1.6.2 版本开始支持)
    matchStrategy :参数值的匹配策略,目前支持精确匹配
    ( PARAM_MATCH_STRATEGY_EXACT )、子串匹配(PARAM_MATCH_STRATEGY_CONTAINS )和正则匹配(PARAM_MATCH_STRATEGY_REGEX )。(1.6.2 版本开始支持)
    用户可以通过 GatewayRuleManager.loadRules(rules) 手动加载网关规则,或通过 GatewayRuleManager.register2Property(property) 注册动态规则源动态推送(推荐方式)。

2.2 集成Sentinel

Sentinel实战应用_第28张图片
我们如果想要让微服务网关集成Sentinel,需要引入依赖包,使用时只需注入对应的SentinelGatewayFilter 实例以及 SentinelGatewayBlockExceptionHandler 实例即可。
首先在 hailtaxi-gateway 中引入如下依赖:


        <dependency>
            <groupId>com.alibaba.cspgroupId>
            <artifactId>sentinel-spring-cloud-gateway-adapterartifactId>
            <version>1.8.1version>
        dependency>

实例引入:创建配置类 com.itheima.config.GatewayConfiguration :

@Configuration
public class GatewayConfiguration {

    private final List<ViewResolver> viewResolvers;
    private final ServerCodecConfigurer serverCodecConfigurer;

    public GatewayConfiguration(ObjectProvider<List<ViewResolver>> viewResolversProvider,
                                ServerCodecConfigurer serverCodecConfigurer) {
        this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
        this.serverCodecConfigurer = serverCodecConfigurer;
    }

    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
        // Register the block exception handler for Spring Cloud Gateway.
        return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
    }

    @Bean
    @Order(-1)
    public GlobalFilter sentinelGatewayFilter() {
        return new SentinelGatewayFilter();
    }

此时集成就完成了。

2.3 配置/API定义

1)API定义
正如前面所说, ApiDefinition 用户自定义的 API 定义分组,可以看做是一些 URL 匹配的组合。比如我们可以定义一个 API 叫 my_api ,请求 path 模式为 /foo/** 和 /baz/** 的都归到 my_api 这个API 分组下面。限流的时候可以针对这个自定义的 API 分组维度进行限流。
我们在配置类 com.itheima.config.GatewayConfiguration 创建Api

  /***
     * Api定义
     */
    private void initCustomizedApis() {
        //Api集合
        Set<ApiDefinition> definitions = new HashSet<ApiDefinition>();
        ApiDefinition cartApi = new ApiDefinition("hailtaxi_driver_api")
                .setPredicateItems(new HashSet<ApiPredicateItem>() {{
                    add(new ApiPathPredicateItem().setPattern("/driver/**"));
                    add(new ApiPathPredicateItem().setPattern("/car/model/**"));
                    add(new ApiPathPredicateItem().setPattern("/trip/message")
                            //参数值的匹配策略
                            // 精确匹配(PARAM_MATCH_STRATEGY_EXACT)
                            // 子串匹配(PARAM_MATCH_STRATEGY_CONTAINS)
                            // 正则匹配(PARAM_MATCH_STRATEGY_REGEX)
                            .setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));
                }});
        definitions.add(cartApi);
        //加载Api
        GatewayApiDefinitionManager.loadApiDefinitions(definitions);
    }

2)规则创建
GatewayFlowRule 网关限流规则,针对 API Gateway 的场景定制的限流规则,可以针对不同 route或自定义的 API 分组进行限流,支持针对请求中的参数、Header、来源 IP 等进行定制化的限流。
我们在配置类 com.itheima.config.GatewayConfiguration 创建配置:


    /***
     * 规则定义
     */
    private void initGatewayRules() {
        //网关限流规则
        Set<GatewayFlowRule> rules = new HashSet<GatewayFlowRule>();

        //商品微服务规则配置
        //资源名称,可以是网关中的 route 名称或者用户自定义的 API 分组名称
        rules.add(new GatewayFlowRule("hailtaxi-order")
                //限流阈值
                .setCount(2)
                //应对突发请求时额外允许的请求数目。
                .setBurst(2)
                //统计时间窗口,单位是秒,默认是 1 秒。
                .setIntervalSec(1)
                //限流行为
                //CONTROL_BEHAVIOR_RATE_LIMITER 匀速排队
                //CONTROL_BEHAVIOR_DEFAULT 快速失败(默认)
                .setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER)
                //匀速排队模式下的最长排队时间,单位是毫秒,仅在匀速排队模式下生效。
                .setMaxQueueingTimeoutMs(1000)
        );

        //API 【mall_cart_api】限流配置
        rules.add(new GatewayFlowRule("hailtaxi_driver_api")
                //限流阈值
                .setCount(3)
                //统计时间窗口,单位是秒,默认是 1 秒。
                .setIntervalSec(1)
        );
        //加载网关规则
        GatewayRuleManager.loadRules(rules);
    }

3)配置/Api加载
上面两个方法创建了API并且创建了配置,但并没有在程序启动加载,我们可以采用 @PostConstruct注解实现加载调用,在com.itheima.config.GatewayConfiguration 中创建方法:

/***
     * 初始化加载Api和规则
     */
    @PostConstruct
    public void doInit() {
        initCustomizedApis();
        initGatewayRules();
    }

3 Sentinel控制台

Sentinel 控制台是流量控制、熔断降级规则统一配置和管理的入口,它为用户提供了机器自发现、簇点链路自发现、监控、规则配置等功能。在 Sentinel 控制台上,我们可以配置规则并实时查看流量控制效果。

3.1 Sentinel控制台安装

Sentinel 提供一个轻量级的开源控制台,它提供机器发现以及健康情况管理、监控(单机和集群),规则管理和推送的功能。
Sentinel 控制台包含如下功能:
查看机器列表以及健康情况:收集 Sentinel 客户端发送的心跳包,用于判断机器是否在线。
监控 (单机和集群聚合):通过 Sentinel 客户端暴露的监控 API,定期拉取并且聚合应用监控信息,最终可以实现秒级的实时监控。
规则管理和推送:统一管理推送规则。
鉴权:生产环境中鉴权非常重要。这里每个开发者需要根据自己的实际情况进行定制。

Sentinel控制台安装可以基于jar包启动的方式安装,也可以基于docker安装,为了方便操作,我们这里采用docker安装方式:

docker run --name=sentinel-dashboard -d -p 8858:8858 -d --restart=always bladex/sentinel-dashboard

安装好了后,我们可以直接访问 http://192.168.211.145:8858 访问控制台,默认用户名和密码都是sentinel :
Sentinel实战应用_第29张图片
登录后,效果如下:

客户端需要引入 Transport 模块来与 Sentinel 控制台进行通信,可以通过 pom.xml 引入 JAR 包:

<dependency>
    <groupId>com.alibaba.cspgroupId>
    <artifactId>sentinel-transport-simple-httpartifactId>
    <version>x.y.zversion>
dependency>

如果是SpringBoot工程接入Sentinel,可以直接引入如下依赖包:

 <dependency>
            <groupId>com.alibaba.cloudgroupId>
            <artifactId>spring-cloud-starter-alibaba-sentinelartifactId>
            <version>2.2.5.RELEASEversion>
        dependency>

3.2 接入控制台

我们将Gateway微服务网关接入Sentinel控制台,首先引入依赖包:

 <dependency>
            <groupId>com.alibaba.cloudgroupId>
            <artifactId>spring-cloud-starter-alibaba-sentinelartifactId>
            <version>2.2.5.RELEASEversion>
        dependency>

在核心配置文件中配置Sentinel服务地址

spring:
  cloud:
    sentinel:
      transport:
        port: 8719
        dashboard: 192.168.211.145:8858

这里的 spring.cloud.sentinel.transport.port 端口配置会在应用对应的机器上启动一个 HttpServer,该 Server 会与 Sentinel 控制台做交互,比如限流规则拉取。
此时我们出发一些请求操作,再看Sentinel控制台会多一个服务监控:
Sentinel实战应用_第30张图片

3.3 可视化管理

3.31 实时监控

同一个服务下的所有机器的簇点信息会被汇总,并且秒级地展示在"实时监控"下。
注意: 实时监控仅存储 5 分钟以内的数据,如果需要持久化,需要通过调用实时监控接口来定制
githup教程
Sentinel实战应用_第31张图片
如果要获取监控数据,直接调用 http://localhost:8719/clusterNode 即可获取,效果如下:

3.3.2 流控规则

我们可以在【流控规则】页面中新增,点击【流控规则】进入页面新增页面,如下图:

资源名:其实可以和请求路径保持一致,这里的流控模式为QPS,触发流控执行阈值为1,流控模式为让当前请求的资源快速直白。
我们测试效果如下:
在这里插入图片描述
这里的参数和我们程序中的参数其实是一样的,如下说明:

resource:资源名,即限流规则的作用对象 
count: 限流阈值 
grade: 限流阈值类型(QPS 或并发线程数) 
limitApp: 流控针对的调用来源,若为 default 则不区分调用来源 
strategy: 调用关系限流策略 
controlBehavior: 流量控制效果(直接拒绝、Warm Up、匀速排队) 

流控效果和程序中也是一样的:

快速失败: 
当QPS超过任何规则的阈值后,新的请求就会立即拒绝,拒绝方式为抛出FlowException . 这种方 式适用于对系统处理能力确切已知的情况下,比如通过压测确定了系统的准确水位时。 
Warm Up: 
当系统长期处理低水平的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压 垮。通过"冷启动",让通过的流量缓慢增加,在一定时间内逐渐增加到阈值的上限,给系统一个预热的时 间,避免冷系统被压垮。 
排队等待: 
匀速排队严格控制请求通过的时间间隔,也即是让请求以均匀的速度通过,对应的是漏桶算法。 
3.3.3 降级规则

我们可以选择 降级规则>新增降级规则 ,如下图:

降级规则的熔断策略有3种,分别是慢调用比例、异常比例、异常数,和程序中是一样的。

3.3.4 热点数据

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

你可能感兴趣的:(互联网微服务前沿技术栈进阶,sentinel,spring,java,sentinel集成,sentinel控制台)