SpringCloud Alibaba-Sentinel

SpringCloud Alibaba-Sentinel

  • 1. Sentinel核心库
    • 1.1 Sentinel介绍
    • 1.2 Sentinel核心功能
      • 1.2.1 流量控制
      • 1.2.2 熔断降级
  • 2 Sentinel 限流熔断降级
    • 2.1 @SentinelResource定义资源
      • 2.1.1 blockHandler/blockHandlerClass
      • 2.1.2 fallback/fallbackClass
      • 2.1.3 defaultFallback
    • 2.2 Sentinel的规则
      • 2.2.1 流量控制规则 (FlowRule)
        • 2.2.1.1 QPS流量控制
        • 2.2.1.2 线程数流量控制
      • 2.2.2 熔断降级规则 (DegradeRule)
      • 2.2.3 系统保护规则 (SystemRule)
      • 2.2.4 访问控制规则 (AuthorityRule)
      • 2.2.5 热点规则 (ParamFlowRule)
    • 2.3 OpenFeign支持
      • 2.3.1 fallback
      • 2.3.2 fallbackFactory
  • 3 Sentinel集成Gateway
    • 3.1 Sentinel对网关支持
    • 3.2 GateWay集成Sentinel
  • 4 Sentinel控制台
    • 4.1 Sentinel控制台安装
    • 4.2 接入控制台
    • 4.3 可视化管理
      • 4.3.1 实时监控
      • 4.3.2 流控规则
      • 4.3.3 降级规则
      • 4.3.4 热点数据

1. Sentinel核心库

Sentinel 主页

1.1 Sentinel介绍

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

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

参看 官方网站

对比内容SentinelHystrix
隔离策略信号量隔离线程池隔离/信号量隔离
熔断降级策略基于响应时间或失败比率基于失败比率
实时指标实现滑动窗口滑动窗口(基于 RxJava)
规则配置支持多种数据源支持多种数据源
扩展性多个扩展点插件的形式
基于注解的支持支持支持
限流信号量隔离基于 QPS,支持基于调用关系的限流不支持
流量整形支持慢启动、匀速器模式不支持
系统负载保护支持不支持
控制台开箱即用,可配置规则、查看秒级监控、机器发现等不完善
常见框架的适配Servlet、Spring Cloud、Dubbo、gRPC 等Servlet、Spring Cloud Netflix
多语言支持Java/Go/C++Java
  1. Sentinel基本概念
  • 资源
    资源是 Sentinel 的关键概念。资源,可以是一个方法、一段代码、由应用提供的接口,或者由应用调用其它应用的接口
  • 规则
    围绕资源的实时状态设定的规则,包括流量控制规则、熔断降级规则以及系统保护规则、自定义规则
  • 降级
    在流量剧增的情况下,为保证系统能够正常运行,根据资源的实时状态、访问流量以及系统负载有策略的拒绝掉一部分流量
  • 熔断
    一个轻轻过来, 可能服务调用的链路长, 在某个服务发生问题时可能会造成服务雪崩 如果触发熔断机制,则可以保证后续的请求不会继续发送到目标服务上
    降级和熔断的区别是, 降级为可用, 熔断为不可用

1.2 Sentinel核心功能

1.2.1 流量控制

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

流量控制有以下几个角度:

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

1.2.2 熔断降级

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

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

Sentinel熔断降级设计:

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

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

针对这个情况,Sentinel 提供了对应的保护机制,让系统的入口流量和系统的负载达到一个平衡,保证系统在能力范围之内处理最多的请求。

2 Sentinel 限流熔断降级

Sentinel 可以简单的分为 Sentinel 核心库和 Dashboard。核心库不依赖 Dashboard,但是结合 Dashboard 可以取得最好的效果
在这里插入图片描述
以下内容根据上面服务架构进行熔断限流操作

使用Spring Cloud Alibaba Sentinel 使用手册
首先需要引入spring-cloud-starter-alibaba-sentinel依赖,并使用@SentinelResource标识资源
在hailtaxi-driver工程中引入spring-cloud-starter-alibaba-sentinel依赖,依赖如下:

<!--sentinel-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    <version>2.2.7.RELEASE</version>
</dependency>

2.1 @SentinelResource定义资源

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

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

2.1.1 blockHandler/blockHandlerClass

制造SystemBlockException异常

@SentinelResource(value = "info",blockHandler = "blockExHandler")
@RequestMapping(value = "/info/{id}")
public Driver info(@PathVariable(value = "id")String id) throws BlockException {
    log.info("当前服务占用的端口为:{}",port);
    Driver driver = driverService.findById(id);
    if (driver==null) {
        //throw new RuntimeException("司机id="+id+"不存在");
        throw new SystemBlockException("info", "司机id="+id+"不存在",null); // 抛出BlockException
    }
    return driver;
}

/**
 * info资源出现BlockException后的降级处理
 */
public Driver blockExHandler(String id,BlockException e) {
    Driver driver = new Driver();
    driver.setId(id);
    driver.setName("系统繁忙,稍后再试");
    return driver;
}

指定blockHandlerClass
指定的class必须要是静态方法

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

注意:这种方式只能拦截BlockException异常, 局限性比较高

2.1.2 fallback/fallbackClass

如果希望抛出任何异常都能处理,都能调用默认处理方法,而并非只是BlockException异常才调用,此时可以使用@SentinelResource的fallback属性,代码如下:

@SentinelResource(value = "info"/*,blockHandler = "blockExHandler"*/,fallback = "exHandler")
@RequestMapping(value = "/info/{id}")
public Driver info(@PathVariable(value = "id")String id) throws BlockException {
    log.info("当前服务占用的端口为:{}",port);
    Driver driver = driverService.findById(id);
    if (driver==null) {
        throw new RuntimeException("司机id="+id+"不存在");
        // throw new SystemBlockException("info", "司机id="+id+"不存在",null); // 抛出BlockException
    }
    return driver;
}
/**
 * info资源出现任何类型异常后的降级处理
 * 方法参数可以添加一个Throwable 类型的参数,也可不添加
 */
public Driver exHandler(String id,Throwable e) {
    Driver driver = new Driver();
    driver.setId(id);
    driver.setName("系统繁忙,稍后再试");
    return driver;
}

指定fallbackClass
指定的class必须要是静态方法

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

2.1.3 defaultFallback

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

@RestController
@RequestMapping(value = "/driver")
@Slf4j
@RefreshScope
@SentinelResource(defaultFallback = "defaultExHandler")
public class DriverController {
    @Autowired
    private DriverService driverService;

    public Driver defaultExHandler(Throwable e) {
        Driver driver = new Driver();
        driver.setName("系统繁忙,稍后再试");
        return driver;
    }

    /****
     * 司机信息
     */
    //@SentinelResource(value = "info"/*,blockHandler = "blockExHandler"*/,fallback = "exHandler")
    @SentinelResource("info")
    @RequestMapping(value = "/info/{id}")
    public Driver info(@PathVariable(value = "id")String id) throws BlockException {
        log.info("当前服务占用的端口为:{}",port);
        Driver driver = driverService.findById(id);
        if (driver==null) {
            throw new RuntimeException("司机id="+id+"不存在");
            // throw new SystemBlockException("info", "司机id="+id+"不存在",null); // 抛出BlockException
        }
        return driver;
    }

两个字: 也很麻烦
不过一般都不会这么写, 通常会和OpenFeign的FallbackFactory结合使用

2.2 Sentinel的规则

参考官网
Sentinel 的所有规则都可以在内存态中动态地查询及修改,修改之后立即生效。同时 Sentinel 也提供相关 API,供用户来定制自己的规则策略
Sentinel 支持以下几种规则:流量控制规则、熔断降级规则、系统保护规则、来源访问控制规则热点参数规则

2.2.1 流量控制规则 (FlowRule)

参看 链接1、链接2
流量规则的定义,重要属性如下:

Field说明默认值
resource资源名,资源名是限流规则的作用对象
count限流阈值
grade限流阈值类型,QPS 模式(1)或并发线程数模式(0)QPS 模式
limitApp流控针对的调用来源default,代表不区分调用来源
strategy调用关系限流策略:直接、链路、关联根据资源本身(直接)
controlBehavior流控效果(直接拒绝/WarmUp/匀速+排队等待),不支持按调用关系限流直接拒绝
clusterMode是否集群限流

同一个资源可以同时有多个限流规则,检查规则时会依次检查

strategy限流策略说明:

  1. 直接: 资源达到限流条件时,直接限流
  2. 关联: A资源关联B资源,当关联的B资源达到阈值限流时,A资源也会被限流
  3. 链路: 对于某资源C,有两个入口,从资源A->C,从资源B->C, 通过指定入口资源可以达到只记录从该入口进来的流量(指定资源从入口资源进来的流量,如果达到阈值,就可以对其限流)

controlBehavior流控说明:

  1. 直接拒绝: 请求直接失败
  2. WarmUp: 当系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过"冷启动",让通过流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮
  3. 排队等待: 排队处理请求

2.2.1.1 QPS流量控制

Application初始化完成之后加载规则

/***
 * 初始化规则
 */
@PostConstruct
private void initFlowRule() {
    //规则集合
    List<FlowRule> rules = new ArrayList<FlowRule>();
    //定义一个规则
    FlowRule rule = new FlowRule("info");
    // 设置阈值
    rule.setCount(2);
    //设置限流阈值类型
    rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
    //default,代表不区分调用来源
    rule.setLimitApp("default");
    //设置流控效果 当QPS超过任意规则的阈值后,新的请求就会被立即拒绝
    rule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT);
    //将定义的规则添加到集合中
    rules.add(rule);
    //加载规则
    FlowRuleManager.loadRules(rules);
}

2.2.1.2 线程数流量控制

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

@PostConstruct
public void initFlowRule() {
    //规则集合
    List<FlowRule> rules = new ArrayList<>();
    // 定义一个规则
    FlowRule rule = new FlowRule("info");
    // 设置基流量控制 的类型
    rule.setGrade(RuleConstant.FLOW_GRADE_THREAD);//默认是qps
    //设置流量阈值
    rule.setCount(2);
    // 将 规则添加到 集合中
    rules.add(rule);
    // 加载规则
    FlowRuleManager.loadRules(rules);
}

此时再来访问http://localhost:18081/driver/info/1 无论怎么访问都不会出现降级现象,但是如果用Jmeter模拟多个线程,会执行降级方法,效果如下:
在这里插入图片描述

2.2.2 熔断降级规则 (DegradeRule)

参看 链接1、链接2
熔断降级规则包含下面几个重要的属性:

Field说明默认值
resource资源名,即规则的作用对象
grade熔断策略,支持慢调用比例/异常比例/异常数策略慢调用比例
count慢调用比例模式下为慢调用临界 RT(超出该值计为慢调用);异常比例/异常数模式下为对应的阈值
timeWindow熔断时长,单位为 s
minRequestAmount熔断触发的最小请求数,请求数小于该值时即使异常比率超出阈值也不会熔断(1.7.0 引入)5
statIntervalMs统计时长(单位为 ms),如 60*1000 代表分钟级(1.8.0 引入)1000 ms
slowRatioThreshold慢调用比例阈值,仅慢调用比例模式有效(1.8.0 引入)

同一个资源可以同时有多个降级规则
可以通过调用 DegradeRuleManager.loadRules() 方法来用硬编码的方式定义熔断规则

@PostConstruct
public void initDegradeRule() {
    List<DegradeRule> rules = new ArrayList<>();
    DegradeRule rule = new DegradeRule();
    // 设置资源名称
    rule.setResource("info");
    /**
         * 设置熔断策略
         * DEGRADE_GRADE_RT:平均响应时间
         * DEGRADE_GRADE_EXCEPTION_RATIO:异常比例数量
         * DEGRADE_GRADE_EXCEPTION_COUNT:异常数
         */
    rule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT);
    //设置阈值
    rule.setCount(2);
    //设置 熔断时长(单位秒)
    rule.setTimeWindow(30);
    // 统计时长(单位为 ms) 默认1000
    rule.setStatIntervalMs(60*1000);
    //将规则添加到集合中
    rules.add(rule);
    DegradeRuleManager.loadRules(rules);
}

上面设置的规则的意思是, 在1分钟内请求出现异常的数量超过2次,服务熔断降级, 30秒后回复正常

2.2.3 系统保护规则 (SystemRule)

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

Field说明默认值
highestSystemLoadload1 触发值,用于触发自适应控制阶段-1 (不生效)
avgRt所有入口流量的平均响应时间-1 (不生效)
maxThread入口流量的最大并发数-1 (不生效)
qps所有入口资源的 QPS-1 (不生效)
highestCpuUsage当前系统的 CPU 使用率(0.0-1.0)-1 (不生效)

可以通过调用 SystemRuleManager.loadRules() 方法来用硬编码的方式定义流量控制规则

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

可以测试CPU使用率自我保护,使用jmeter测试如下
在这里插入图片描述

2.2.4 访问控制规则 (AuthorityRule)

参看:链接1、链接2
很多时候,我们需要根据调用方来限制资源是否通过,这时候可以使用 Sentinel 的访问控制(黑白名单)的功能。黑白名单根据资源的请求来源(origin)限制资源是否通过,若配置白名单则只有请求来源位于白名单内时才可通过;若配置黑名单则请求来源位于黑名单时不通过,其余的请求通过。

授权规则,即黑白名单规则(AuthorityRule)非常简单,主要有以下配置项:

  • resource:资源名,即规则的作用对象
  • limitApp:对应的黑名单/白名单,不同 origin 用 , 分隔,如 appA,appB
  • strategy:限制模式,AUTHORITY_WHITE 为白名单模式,AUTHORITY_BLACK 为黑名单模式,默认为白名单模式

可以通过AuthorityRuleManager.loadRules来加载规则

@PostConstruct
public void initAuthorityRule() {
    AuthorityRule rule = new AuthorityRule();
    rule.setResource("info");
    rule.setStrategy(RuleConstant.AUTHORITY_WHITE);
    rule.setLimitApp("127.0.0.1,demo.com");
    AuthorityRuleManager.loadRules(Collections.singletonList(rule));
}

/**
 * Sentinel提供了 RequestOriginParser 接口来处理访问来源,Sentinel保护的资源如果被访问,
 * 就会调用 RequestOriginParser解析访问来源
 */
@Component
public class IpLimiter implements RequestOriginParser{

    @Override
    public String parseOrigin(HttpServletRequest httpServletRequest) {
        return httpServletRequest.getRemoteAddr();
    }
}

2.2.5 热点规则 (ParamFlowRule)

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

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

热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。
在这里插入图片描述
Sentinel 利用 LRU 策略统计最近最常访问的热点参数,结合令牌桶算法来进行参数级别的流控。热点参数限流支持集群模式。
要使用热点参数限流功能,需要引入以下依赖

<!--热点参数限流-->
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-parameter-flow-control</artifactId>
    <version>1.8.1</version>
</dependency>

然后为对应的资源配置热点参数限流规则,并在 entry 的时候传入相应的参数,即可使热点参数限流生效

热点参数规则(ParamFlowRule)类似于流量控制规则(FlowRule)

属性说明默认值
resource资源名,必填
count限流阈值,必填
grade限流模式QPS 模式
durationInSec统计窗口时间长度(单位为秒),1.6.0 版本开始支持1s
controlBehavior流控效果(支持快速失败和匀速排队模式),1.6.0 版本开始支持快速失败
maxQueueingTimeMs最大排队等待时长(仅在匀速排队模式生效),1.6.0 版本开始支持0ms
paramIdx热点参数的索引,必填,对应 SphU.entry(xxx, args) 中的参数索引位置
paramFlowItemList参数例外项,可以针对指定的参数值单独设置限流阈值,不受前面 count 阈值的限制。仅支持基本类型和字符串类型
clusterMode是否是集群参数流控规则false
clusterConfig集群流控相关配置

可以通过 ParamFlowRuleManager 的 loadRules 方法更新热点参数规则

@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("A");
    driver.setId("1");
    return driver;
}
/***
 * 热点参数初始化
 */
@PostConstruct
private static void initParamFlowRules() {
    ParamFlowRule rule = new ParamFlowRule("search")
            //参数下标为0
            .setParamIdx(0)
            //限流模式为QPS
            .setGrade(RuleConstant.FLOW_GRADE_QPS)
            //统计窗口时间长度(单位为秒)默认1秒
            .setDurationInSec(10)
            //流控效果(支持快速失败和匀速排队模式)
            //CONTROL_BEHAVIOR_DEFAULT:限流行为,直接拒绝
            //CONTROL_BEHAVIOR_WARM_UP:限流行为,匀速排队
            //CONTROL_BEHAVIOR_RATE_LIMITER:限流行为,匀速排队
            .setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT)
            //最大排队等待时长(仅在匀速排队模式生效  CONTROL_BEHAVIOR_RATE_LIMITER)
            //.setMaxQueueingTimeMs(600)
            //最大阈值为5
            .setCount(5);

    // 为特定参数单独设置规则
    //如下配置:当参数值为恩施的时候,阈值到达2的时候则执行限流
    ParamFlowItem item = new ParamFlowItem()
            //参数类型为String类型
            .setClassType(String.class.getName())
            //设置阈值为2
            .setCount(2)
            //需要统计的值
            .setObject(String.valueOf("恩施"));
    rule.setParamFlowItemList(Collections.singletonList(item)); //返回的是不可变的集合,但是这个长度的集合只有1,可以减少内存空间
    //加载热点数据
    ParamFlowRuleManager.loadRules(Collections.singletonList(rule));
}

非热点参数5次限流, 热点参数2次限流

以上是被调用放的熔断降级, 下面聊聊调用方的

2.3 OpenFeign支持

参看:链接
Sentinel 适配了 Feign 组件。如果想使用,除了外还需要 2 个步骤:

1:引入 spring-cloud-starter-alibaba-sentinel 的依赖
3:配置文件打开 Sentinel 对 Feign 的支持:feign.sentinel.enabled=true

  1. 引入sentinel和OpenFeign依赖,配置如下:
<!--sentinel-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    <version>2.2.7.RELEASE</version>
</dependency>
  1. 配置文件中开启Feign支持sentinel,配置如下:
feign:
  #开启SentinelFeign的支持
  sentinel:
    enabled: true

不打开默认使用hytrix, 而且hytrix默认是打开的

2.3.1 fallback

  1. 为Feign接口创建一个实现类:DriverFeignFallback,在实现类中处理程序异常降级处理方法,代码如下:
@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;
    }
}
  1. 在DriverFeign接口上添加fallback属性指定降级处理的类,代码如下:
@FeignClient(value = "hailtaxi-driver",fallback = DriverFeignFallback.class)

2.3.2 fallbackFactory

可以为DriverFeign接口创建一个降级处理的工厂对象,在工厂对象中处理程序异常降级处理方法,用工厂对象处理可以拿到异常信息,代码如下:

  1. 创建DriverFeignFallbackFactory
@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;
            }
        };
    }
}

2、在DriverFeign接口上添加fallbackFactory属性指定讲解处理的类,代码如下:

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

3 Sentinel集成Gateway

参看:再飞一个
我们的项目流量入口是SpringCloud Gateway,因此重点看Sentinel集成Gateway

3.1 Sentinel对网关支持

Sentinel 支持对 Spring Cloud Gateway、Zuul 等主流的 API Gateway 进行限流
在这里插入图片描述
Sentinel 1.6.0 引入了 Sentinel API Gateway Adapter Common 模块,此模块中包含网关限流的规则和自定义 API 的实体和管理逻辑
从 1.6.0 版本开始,Sentinel 提供了 Spring Cloud Gateway 的适配模块,可以提供两种资源维度的限流:

  1. route 维度:即在 Spring 配置文件中配置的路由条目,资源名为对应的 routeId
  2. 自定义 API 维度:用户可以利用 Sentinel 提供的 API 来自定义一些 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) 注册动态规则源动态推送(推荐方式)

3.2 GateWay集成Sentinel

参考:Sentinel · alibaba/spring-cloud-alibaba Wiki · GitHub

  1. 引入如下依赖:
<!--Sentinel-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    <version>2.2.7.RELEASE</version>
</dependency>

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
    <version>2.2.7.RELEASE</version>
</dependency>

  1. 创建配置类GatewayConfiguration
    自版本2.2.0起,不再需要手动注入SentinelGatewayBlockExceptionHandler和SentinelGatewayFilter
@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;
    }

    /**
     * 限流的异常处理器
     * @return
     */
    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
        return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
    }

    /***
     * Sentinel路由处理核心过滤器
     * @return
     */
    @Bean
    @Order(-1)
    public GlobalFilter sentinelGatewayFilter() {
        return new SentinelGatewayFilter();
    }



    @PostConstruct
    public void doInit() {
        // 自定义 api 分组
        initCustomizedApis();
        // 初始化网关流控规则
        initGatewayRules();
    }

    private void initCustomizedApis() {
        Set<ApiDefinition> definitions = new HashSet<>();
        ApiDefinition api1 = new ApiDefinition("customer_api")
                .setPredicateItems(new HashSet<ApiPredicateItem>() {{
                    add(new ApiPathPredicateItem().setPattern("/order/**")
                            /**
                             * 匹配策略:
                             * URL_MATCH_STRATEGY_EXACT:url精确匹配
                             * URL_MATCH_STRATEGY_PREFIX:url前缀匹配
                             * URL_MATCH_STRATEGY_REGEX:url正则匹配
                             */
                            .setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));
                }});
        definitions.add(api1);
        GatewayApiDefinitionManager.loadApiDefinitions(definitions);
    }

    private void initGatewayRules() {
        Set<GatewayFlowRule> rules = new HashSet<>();

        rules.add(new GatewayFlowRule("hailtaxi-driver") // 资源名称,可以是网关中的 routeid或者用户自定义的 API分组名称
                .setCount(2) // 限流阈值
                .setIntervalSec(10) // 统计时间窗口默认1s
                .setGrade(RuleConstant.FLOW_GRADE_QPS) // 限流模式
                /**
                 * 限流行为:
                 * CONTROL_BEHAVIOR_RATE_LIMITER 匀速排队
                 * CONTROL_BEHAVIOR_DEFAULT 快速失败(默认)
                 * CONTROL_BEHAVIOR_WARM_UP:
                 * CONTROL_BEHAVIOR_WARM_UP_RATE_LIMITER:
                 */
                .setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER)
                //匀速排队模式下的最长排队时间,单位是毫秒,仅在匀速排队模式下生效
                .setMaxQueueingTimeoutMs(1000)
                /**
                 * 热点参数限流配置
                 * 若不设置,该网关规则将会被转换成普通流控规则;否则会转换成热点规则
                 */
                .setParamItem(new GatewayParamFlowItem()
                        /**
                         * 从请求中提取参数的策略:
                         * PARAM_PARSE_STRATEGY_CLIENT_IP
                         * PARAM_PARSE_STRATEGY_HOST
                         * PARAM_PARSE_STRATEGY_HEADER
                         * PARAM_PARSE_STRATEGY_URL_PARAM
                         */
                                    .setParseStrategy(SentinelGatewayConstants.PARAM_PARSE_STRATEGY_URL_PARAM)
                        /**
                         * 若提取策略选择 Header 模式或 URL 参数模式,
                         * 则需要指定对应的 header 名称或 URL 参数名称。
                         */
                        .setFieldName("token")
                        /**
                         * 参数的匹配策略:
                         * PARAM_MATCH_STRATEGY_EXACT
                         * PARAM_MATCH_STRATEGY_PREFIX
                         * PARAM_MATCH_STRATEGY_REGEX
                         * PARAM_MATCH_STRATEGY_CONTAINS
                         */
                        .setMatchStrategy(SentinelGatewayConstants.PARAM_MATCH_STRATEGY_EXACT)
                        //参数值的匹配模式,只有匹配该模式的请求属性值会纳入统计和流控
                        .setPattern("123456") // token=123456 10s内qps达到2次会被限流
                )
        );

        rules.add(new GatewayFlowRule("customer_api")
                /**
                 * 规则是针对 API Gateway 的 route(RESOURCE_MODE_ROUTE_ID)
                 * 还是用户在 Sentinel 中定义的 API 分组(RESOURCE_MODE_CUSTOM_API_NAME),默认是 route。
                 */
                .setResourceMode(SentinelGatewayConstants.RESOURCE_MODE_CUSTOM_API_NAME)
                .setCount(2)
                .setIntervalSec(1)
                .setGrade(RuleConstant.FLOW_GRADE_QPS)
        );
        GatewayRuleManager.loadRules(rules);
    }
}

4 Sentinel控制台

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

4.1 Sentinel控制台安装

Sentinel 控制台包含如下功能:

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

Sentinel控制台安装可以基于jar包启动的方式安装,也可以基于docker安装

docker run --name=sentinel-dashboard -d -p 8858:8858 -d --restart=on-failure bladex/sentinel-dashboard:1.8.0

登录后,效果如下:在这里插入图片描述

4.2 接入控制台

  1. 引入依赖包:
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    <version>2.2.7.RELEASE</version>
</dependency>
spring:
  cloud:
    sentinel:
      transport:
        port: 8719
        dashboard: 192.168.200.200:8858

4.3 可视化管理

4.3.1 实时监控

同一个服务下的所有机器的簇点信息会被汇总,并且秒级地展示在"实时监控"下。

注意: 实时监控仅存储 5 分钟以内的数据,如果需要持久化,需要通过调用实时监控接口来定制。
在这里插入图片描述

4.3.2 流控规则

可以在【流控规则】页面中新增,点击【流控规则】进入页面新增页面,如下图:
在这里插入图片描述

4.3.3 降级规则

降级规则的熔断策略有3种,分别是慢调用比例、异常比例、异常数
在这里插入图片描述

4.3.4 热点数据

热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K 数据,并对其访问进行限制
在这里插入图片描述
拓展知识点:
注意:如果流控模式是链路模式,需要引入如下依赖:

<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-web-servlet</artifactId>
    <version>1.8.0</version>
</dependency>

创建过滤器:

/***
 * CommonFilter过滤器
 * @return
 */
@Bean
public FilterRegistrationBean sentinelFilterRegistration() {
    FilterRegistrationBean registration = new FilterRegistrationBean();
    registration.setFilter(new CommonFilter());
    registration.addUrlPatterns("/*");  //过滤所有请求
    // 入口资源关闭聚合
    registration.addInitParameter(CommonFilter.WEB_CONTEXT_UNIFY, "false");
    registration.setName("sentinelFilter");
    registration.setOrder(1);
    return registration;
}

bootstrap.yml配置:web-context-unify: false

  cloud:
    sentinel:
      transport:
        port: 8719
        dashboard: localhost:8858
      web-context-unify: false  #可根据不同的URL 进行链路限流

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/29884.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java中不支持多重继承原因

在 Java 中回答这种棘手问题的关键是准备好相关主题, 以应对后续的各种可能的问题。 这是非常经典的问题&#xff0c;与为什么 String 在 Java 中是不可变的很类似; 这两个问题之间的相似之处在于它们主要是由 Java 创作者的设计决策使然。 为什么Java不支持类多重继承, 可以考…

ChatGPT将改变教育,而不是摧毁它

01 学校和大学的反应迅速而果断 就在 OpenAI 于 2022 年 11月下旬发布ChatGPT 的几天后&#xff0c;该聊天机器人被广泛谴责为一种免费的论文写作、应试工具&#xff0c;它很容易在作业中作弊。 美国第二大学区洛杉矶联合大学立即阻止了OpenAI网站从其学校网络访问。其他人很…

k8s的service资源类型有ClusterIP、Nodeport、ExternalName、LoadBalancer、Headless(None)

1. ClusterIP 是什么 ClusterIP 是在所有节点内生成一个虚拟IP&#xff0c;为一组pod提供统一的接入点&#xff0c;当service存在时&#xff0c;它的IP地址和端口不会发生改变&#xff0c;客户端通过service的ip和端口建立连接&#xff0c;由service将连接路由到该服务的任意一…

数据结构——广义表

文章目录 前言二、特殊矩阵的压缩存储数组的存储结构和实现按行优先存储按列优先存储 矩阵的压缩存储稀疏矩阵 广义表 总结 前言 数组&#xff0c;数组的压缩存储&#xff0c;广义表 二、特殊矩阵的压缩存储 数组的存储结构和实现 对于多维数组&#xff0c;可以分为按行优先…

spring 反射,BigDecimal,自定义注解的使用(aop)

反射 利用反射调用它类中的属性和方法时&#xff0c;无视修饰符。 获取Class类的对象&#xff08;三种方式&#xff09; Class.forName(“全类名”) &#xff08;推荐使用&#xff09;类名.class对象.getClass() 反射获取构造方法Constructor<?>[] getConstructors()…

父亲节礼物:用Python编写一个小型游戏

名字&#xff1a;阿玥的小东东 学习&#xff1a;Python、C/C 主页链接&#xff1a;阿玥的小东东的博客_CSDN博客-python&&c高级知识,过年必备,C/C知识讲解领域博主 目录 安装必要的库 绘制游戏界面 添加游戏元素 为游戏添加交互性 结论 一、父亲节的来历简介 二…

UE4/5样条线学习(三):样条线与时间轴

目录 简单的小模板 物品跟随样条线移动 粒子特效类&#xff1a; 简单的小模板 通过之前的案例&#xff0c;我们可以直接创建一个actor蓝图&#xff0c;加上要用的样条组件&#xff1a; 然后我们就可以通过时间轴做出不同的一些效果 在蓝图中找到时间轴的这个节点 双击时间…

1745_Perl中的switch结构

全部学习汇总&#xff1a; GreyZhang/perl_basic: some perl basic learning notes. (github.com) 用了很久时间的Perl了&#xff0c;但是一直没有使用过switch结构。即使有的时候&#xff0c;基本上也通过其他的形式完成了相关工作。虽说有时候可能会效率低一些&#xff0c;但…

【备战秋招】每日一题:5月13日美团春招第三题:题面+题目思路 + C++/python/js/Go/java带注释

为了更好的阅读体检&#xff0c;为了更好的阅读体检&#xff0c;&#xff0c;可以查看我的算法学习博客第三题-火车调度 在线评测链接:P1288 题目描述 塔子哥是一位火车车厢调度员。 这一天&#xff0c;一列带有 n 个编号车厢的列车进站了&#xff0c;编号为 1\rightarrow …

【linux网络配置】多个网卡一起使用,一个网卡连内网,一个网卡连外网

一、问题背景 因为有一个工作站在内网中&#xff0c;但是没有办法联网&#xff08;校园网账户有限&#xff09;。 虽然工作站没有联网&#xff0c;但是我仍然可以通过局域网远程控制工作站&#xff0c;使其访问校园网验证页面实现上网。 当给工作站安装软件或依赖项时&#…

grpc 实现grpc gateway(window环境)

官网&#xff1a;https://grpc-ecosystem.github.io/grpc-gateway/ github&#xff1a;https://github.com/grpc-ecosystem/grpc-gateway grpc gateway的原理官网有介绍。总结一下就是&#xff1a; gRPC-Gateway帮助你同时以gRPC和RESTful风格提供你的API。grpc-gateway旨在为您…

【Linux】linux下使用命令修改jar包内某一个文件中的内容并重新运行jar程序

linux下使用命令修改jar包内某一个文件中的内容并重新运行jar程序 一、背景描述二、vi命令编辑三、启动程序四、拓展--启动脚本 一、背景描述 需求&#xff1a;发现线上的 iotp-irsb-server-v1.0.0.2.jar 包中配置文件的日志级别配置错误&#xff0c;需要在线修改jar包中文件的…

MFC的定义和实际操作方法

我是荔园微风&#xff0c;作为一名在IT界整整25年的老兵&#xff0c;今天从另一个角度来看一下MFC。 完整的应用一般由四个类组成&#xff1a;CWinApp应用类&#xff0c;CFrameWnd窗口框架类&#xff0c;CDocument文档类&#xff0c;CView视类 过程&#xff1a;CWinApp创建CF…

ubuntu iptables开机自启动

一、配置ubuntu路由转发 用在一台电脑有多个网卡的情形下&#xff0c;一个网卡5网段、一个网卡8网段&#xff0c;8网段是网络出口&#xff0c;所以5网段的设备需要入网的话&#xff0c;要路由转发。 sudo iptables -t nat -A POSTROUTING -s 192.168.5.0/24 -j SNAT --to-sou…

STM32速成笔记—概述

文章目录 前言一、专栏简介二、前期准备三、编程规范以及程序架构简介1. 编程规范2. 程序架构 四、STM32F103ZET6简介五、程序模板六、ST-Link调试6.1 硬件连接6.2 Keil配置6.3 下载调试 前言 本人技术菜鸟一枚&#xff0c;2022年大学毕业&#xff0c;大学加入老师实验室&#…

chatgpt赋能python:如何在Python中创建模块:完整指南

如何在Python中创建模块&#xff1a;完整指南 如果你是一位Python开发者&#xff0c;你肯定需要用到模块。模块使得代码更容易组织和管理&#xff0c;并且可以复用许多代码片段&#xff0c; 提高代码的可重用性。在Python中&#xff0c;模块是一组相关函数&#xff0c;方法和变…

oracle expdp导致system表空间满

今天下午&#xff0c;项目经理反馈有套11204版本数据库无法使用了&#xff0c;立刻登录检查环境发现SYSTEM表空间使用率99.99%了 TABLESPACE_NAME MAXSIZE_MB ACTUALSIZE_MB USED_MB FREESPACE_MB SPACE USAGE ----------------- ---------- ------------- ---------- …

Trace32 SRST和TRST、system.attach 和 system.up的区别

目录 TRST-Resets the JTAG TAP controller and the CPU internal debug logic SRST- Resets the CPU core and peripherals SYStem.Mode Down SYStem.Mode Nodebug SYStem.Mode Prepare SYStem.Mode Go SYStem.Mode Attach SYStem.Mode StandBy SYStem.Mode Up 下图为…

ProGuard 进阶系列(二)配置解析

书接上文&#xff0c;从开源库中把代码下载到本地后&#xff0c;就可以在 IDE 中进行运行了。从 main 方法入手&#xff0c;可以看到 ProGuard 执行的第一步就是去解析参数。本文的内容主要分析源码中我们配置的规则解析的实现。 在上一篇文章末尾&#xff0c;在 IDE 中&#x…

大数据Doris(三十七):Spark Load导入HDFS数据

文章目录 Spark Load导入HDFS数据 一、准备HDFS数据 二、创建Doris表 三、创建Spark Load导入任务