天天看点

SpringCloud Alibaba Sentinel实现熔断与限流(上)

什么是sentinel?

Sentinel: 分布式系统的流量防卫兵

Sentinel 具有以下特征:

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

    完善的 SPI 扩展点:Sentinel 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。

Sentinel 的主要特性:

SpringCloud Alibaba Sentinel实现熔断与限流(上)

Sentinel 分为两个部分:

  • 核心库(Java 客户端)不依赖任何框架/库,能够运行于所有 Java 运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持。
  • 控制台(Dashboard)基于 Spring Boot 开发,打包后可以直接运行,不需要额外的 Tomcat 等应用容器。

github地址

中文介绍

安装Sentinel

  • 首先去下载,地址
    SpringCloud Alibaba Sentinel实现熔断与限流(上)
  • 然后运行,运行命令
java -jar sentinel-dashboard-1.8.2.jar
           

前提是有jdk环境,并且8080端口不能被占用

SpringCloud Alibaba Sentinel实现熔断与限流(上)

然后去访问

http://localhost:8080

SpringCloud Alibaba Sentinel实现熔断与限流(上)

用户名密码都是sentinel

项目整合sentinel

  • 新建模块

    cloudalibaba-sentinel-service8401

    SpringCloud Alibaba Sentinel实现熔断与限流(上)
  • 修改pom文件,添加以下的依赖
<dependencies>
        <dependency><!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
            <groupId>com.zhubayi.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        <!--SpringCloud ailibaba nacos -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!--SpringCloud ailibaba sentinel-datasource-nacos 后续做持久化用到-->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
        </dependency>
        <!--SpringCloud ailibaba 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>
        <!-- SpringBoot整合Web组件+actuator -->
        <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>
        <!--日常通用jar包配置-->
        <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>
           
SpringCloud Alibaba Sentinel实现熔断与限流(上)
  • 修改配置文件
server:
  port: 8401

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

management:
  endpoints:
    web:
      exposure:
        include: '*'
           
SpringCloud Alibaba Sentinel实现熔断与限流(上)
  • 新建

    MainApp8401

    主启动类
package com.zhubayi.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.zhubayi.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";
    }
}
           
SpringCloud Alibaba Sentinel实现熔断与限流(上)

然后启动Sentinel8080

java -jar sentinel-dashboard-1.8.2.jar
           

登录进去发现啥都没有

SpringCloud Alibaba Sentinel实现熔断与限流(上)

因为Sentinel采用的懒加载,当有访问时才会加载,所以执行一次访问即可

http://localhost:8401/testA

http://localhost:8401/testB

SpringCloud Alibaba Sentinel实现熔断与限流(上)

说明sentinel8080正在监控微服务8401。

流控规则

1.基本介绍

SpringCloud Alibaba Sentinel实现熔断与限流(上)

解释说明:

SpringCloud Alibaba Sentinel实现熔断与限流(上)

2. 流控模式

(1) 直接(默认)

  • 就是快速失败,直接不让访问了,这是

    系统默认

  • 配置说明
    SpringCloud Alibaba Sentinel实现熔断与限流(上)

表示1秒钟内查询1次就是OK,若超过次数1,就直接-快速失败,报默认错误

测试:快速点击访问

http://localhost:8401/testA

SpringCloud Alibaba Sentinel实现熔断与限流(上)

直接调用默认报错信息

(2) 关联

关联是啥意思?

  • 当关联的资源达到阈值时,就限流自己。例如:当与A关联的资源B达到阀值后,就限流A自己。B惹事,A挂了
  • 配置A
    SpringCloud Alibaba Sentinel实现熔断与限流(上)

说明:当关联资源/testB的qps阀值超过1时,就限流/testA的Rest访问地址,当关联资源到阈值后限制配置好的资源名

postman模拟并发密集访问testB

SpringCloud Alibaba Sentinel实现熔断与限流(上)
SpringCloud Alibaba Sentinel实现熔断与限流(上)

开始运行然后去访问

testA

SpringCloud Alibaba Sentinel实现熔断与限流(上)

可以看出,大批量线程高并发访问B,导致A失效了

(3) 链路

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

这是重点讲的内容 毕竟在这里踩过坑

我用的版本是springCloud-alibab 是2.2.5.RELEASE sentinel1.8.0 所以会造成流控链路失效

给出解决办法

Sentinel 链路流控模式失效

禁止收敛URL的入口context

从1.6.3 版本开始,Sentinel Web filter默认收敛所有URL的入口context,因此链路限流不生效。

1.7.0 版本开始(对应SCA的2.1.1.RELEASE),官方在CommonFilter 引入了

WEB_CONTEXT_UNIFY 参数,用于控制是否收敛context。将其配置为 false 即可根据不同的URL 进行链路限流。

SCA 2.1.1.RELEASE之后的版本,可以通过配置spring.cloud.sentinel.web-context-unify=false即可关闭收敛

我们当前使用的版本是SpringCloud Alibaba 2.2.5.RELEASE,无法实现链路限流。

新增service接口

package com.zhubayi.springcloud.alibaba.serivce;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.springframework.stereotype.Service;

@Service
public class MySentinelService {

    /**
     * @SentinelResource: 可以理解就是一个资源名
     */
    @SentinelResource(value = "myresource",blockHandler = "testAFallback")
    public String sentinelChain() {
        return "调用该资源成功!!!!!";
    }
    public String testAFallback(BlockException ex) {
        return "ex testA";
    }
}

           
  • controller
package com.zhubayi.springcloud.alibaba.controller;

import com.zhubayi.springcloud.alibaba.serivce.MySentinelService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;



@RestController
public class FlowLimitController
{
    @Autowired
    private MySentinelService mySentinelService;

    @GetMapping("/testA")
    public String testA()
    {

        return "------testA"+mySentinelService.sentinelChain();
    }

    @GetMapping("/testB")
    public String testB()
    {
        return "------testB"+mySentinelService.sentinelChain();
    }

}
           

如果单单是这样的配置 是不起效果的 还需要新增配置

1.7.0 版本开始(对应Spring Cloud Alibaba的2.1.1.RELEASE) 需要新增依赖

<dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-web-servlet</artifactId>
        </dependency>
           
SpringCloud Alibaba Sentinel实现熔断与限流(上)

然后配置

spring.cloud.sentinel.web-context-unify=false

SpringCloud Alibaba Sentinel实现熔断与限流(上)

配置类

FilterContextConfig

package com.zhubayi.springcloud.alibaba.config;


import com.alibaba.csp.sentinel.adapter.servlet.CommonFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@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;

    }
}
           

接下来就有效果了

SpringCloud Alibaba Sentinel实现熔断与限流(上)
SpringCloud Alibaba Sentinel实现熔断与限流(上)

测试:频繁访问testA会报错,而访问testB则无影响。

SpringCloud Alibaba Sentinel实现熔断与限流(上)
SpringCloud Alibaba Sentinel实现熔断与限流(上)

3.流控效果

(1)直接->快速失败

  • 这时默认的处理方式,默认的流控处理
  • 直接失败,抛出异常->Blocked by Sentinel (flow limiting)
  • 源码:

    com.alibaba.csp.sentinel.slots.block.flow.controller.DefaultController

(2) Warm up 预热

当流量突然增大的时候,我们常常会希望系统从空闲状态到繁忙状态的切换的时间长一些。即如果系统在此之前长期处于空闲的状态,我们希望处理请求的数量是缓步的增多,经过预期的时间以后,到达系统处理请求个数的最大值。Warm Up(冷启动,预热)模式就是为了实现这个目的的。

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

公式:阈值除以coldFactor(默认值为3),经过预热时长后才会达到阈值

例如:

SpringCloud Alibaba Sentinel实现熔断与限流(上)

上面的是官方说法 说人话就是

10/3=3

,即刚开始的阈值为3

你一开始请求超过

每秒3次

则报错 等预热

5秒钟

,5秒之后,

超过每秒10次

系统报错,若不超过每秒10次,则正常运行

比如你要跑100米 得先热热身 让身体适应一下 不然抽筋猝死就gg了

应用场景: 秒杀系统在开启的瞬间,会有很多流量上来,很有可能把系统打死,预热方式就是把为了保护系统,可慢慢的把流量放进来,慢慢的把阀值增长到设置的阀值。

官方冷启动说明

Warm Up(RuleConstant.CONTROL_BEHAVIOR_WARM_UP)方式,即预热/冷启动方式。当系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过"冷启动",让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。详细文档可以参考 流量控制 - Warm Up 文档,具体的例子可以参见 WarmUpFlowDemo。

通常冷启动的过程系统允许通过的 QPS 曲线如下图所示:

SpringCloud Alibaba Sentinel实现熔断与限流(上)

(3)排队等待

官方文档

匀速排队(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER)方式会严格控制请求通过的间隔时间,也即是让请求以均匀的速度通过,对应的是漏桶算法。详细文档可以参考 流量控制 - 匀速器模式,具体的例子可以参见 PaceFlowDemo。

该方式的作用如下图所示:

SpringCloud Alibaba Sentinel实现熔断与限流(上)

这种方式主要用于处理间隔性突发的流量,例如消息队列。想象一下这样的场景,在某一秒有大量的请求到来,而接下来的几秒则处于空闲状态,我们希望系统能够在接下来的空闲期间逐渐处理这些请求,而不是在第一秒直接拒绝多余的请求。

注意:匀速排队模式暂时不支持 QPS > 1000 的场景。

例如:

SpringCloud Alibaba Sentinel实现熔断与限流(上)

说明:

匀速排队,让请求以均匀的速度通过,阀值类型必须设成QPS,否则无效。

设置含义:/testA每秒1次请求,超过的话就排队等待,等待的超时时间为20000毫秒,超过则报错。