流量控制规则,简称流控规则,会对资源的流量进行限制。同一个资源可以对应多条限流规则。Sentinel会对该资源的所有限流规则依次遍历,直到有规则触发限流或者所有规则遍历完毕。

限流的直接表现是抛出FlowException异常。FlowException是BlockException的子类,您可以捕捉BlockException来自定义被限流之后的处理逻辑。

一条限流规则FlowRule主要由下面几个属性组成,我们可以组合这些属性来实现不同的限流效果:

Field Label 说明 默认值
resource 资源名 资源名是限流规则的作用对象
limitApp 针对来源
count 单机阈值 限流阈值
grade 阈值类型 限流阈值类型,QPS或线程数模式 QPS模式
strategy 流控模式 调用关系限流策略:直接、链路、关联 直接
controlBehavior 流控效果 流控效果:直接拒绝、排队等待、慢启动模式 直接拒绝

阈值类型

流量控制主要有两种统计类型,一种是统计线程数,另外一种则是统计QPS。

类型由FlowRule.grade字段来定义。其中,0代表根据并发数量来限流,1代表根据QPS来进行流量控制。其中线程数、QPS值,都是由StatisticSlot实时统计获取的。

可以通过下面的命令查看实时统计信息:

curl http://localhost:8719/cnode?id=resourceName

例如,注意端口不一定是8719,具体是多少可以通过sentinel控制台->机器列表查看:

curl http://localhost:8720/cnode?id=sentinel-annotationidx id                  thread    pass      blocked   success    total    aRt   1m-pass   1m-block   1m-all   exception
2   sentinel-annotation 0         1.0       672.0     1.0        673.0    0.0   8         5117       5125     0.0

其中:

  • thread:代表当前处理该资源的线程数;
  • pass:代表一秒内到来到的请求;
  • blocked:代表一秒内被流量控制的请求数量;
  • success:代表一秒内成功处理完的请求;
  • total:代表到一秒内到来的请求以及被阻止的请求总和;
  • RT:代表一秒内该资源的平均响应时间;
  • 1m-pass:则是一分钟内到来的请求;
  • 1m-block:则是一分钟内被阻止的请求;
  • 1m-all:则是一分钟内到来的请求和被阻止的请求的总和;
  • exception:则是一秒内业务本身异常的总和。

QPS

当QPS超过某个阈值的时候,则采取措施进行流量控制。

线程数

线程数限流用于保护业务线程数不被耗尽。例如,当应用所依赖的下游应用由于某种原因导致服务不稳定、响应延迟增加,对于调用者来说,意味着吞吐量下降和更多的线程数占用,极端情况下甚至导致线程池耗尽。为应对高线程占用的情况,业内有使用隔离的方案,比如通过不同业务逻辑使用不同线程池来隔离业务自身之间的资源争抢(线程池隔离),或者使用信号量来控制同时请求的个数(信号量隔离)。这种隔离方案虽然能够控制线程数量,但无法控制请求排队时间。当请求过多时排队也是无益的,直接拒绝能够迅速降低系统压力。Sentinel线程数限流不负责创建和管理线程池,而是简单统计当前请求上下文的线程个数,如果超出阈值,新的请求会被立即拒绝。

根据调用关系限流策略

调用关系包括调用方、被调用方;方法又可能会调用其它方法,形成一个调用链路的层次关系。Sentinel通过NodeSelectorSlot建立不同资源间的调用的关系,并且通过ClusterNodeBuilderSlot记录每个资源的实时统计信息。

有了调用链路的统计信息,我们可以衍生出多种流量控制手段。

根据调用方限流

ContextUtil.enter(resourceName, origin)方法中的origin参数标明了调用方身份。这些信息会在ClusterBuilderSlot中被统计。

可通过以下命令来展示不同的调用方对同一个资源的调用数据:

curl http://localhost:8719/origin?id=nodeA

例如,调用数据示例:

curl http://localhost:8720/origin?id=sentinel-annotationid: sentinel-annotationidx originthreadNum passQps   blockQps   totalQps aRt   1m-pass   1m-block   1m-total
1   nodeA 0         0.0       0.0        0.0      0.0   0         0          0
2   nodeB 0         0.0       0.0        0.0      0.0   100       0          100

上面这个命令展示了资源名为sentinel-annotation的资源被两个不同的调用方调用的统计。

可以实现接口RequestOriginParser来获取请求中的某个参数来标明调用方身份,例如可以从请求的Header中获取source字段来标明调用方身份,然后可以将source字段配置在流控规则中,可以根据source的值进行限流:

package com.morris.user.config;import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.RequestOriginParser;
import org.springframework.stereotype.Component;import javax.servlet.http.HttpServletRequest;@Component
public class HeaderOriginParser implements RequestOriginParser {@Overridepublic String parseOrigin(HttpServletRequest request) {/*** 根据header中的source字段来区分请求来源*/return request.getHeader("source");}
}

在sentinel自带的适配器模块sentinel-spring-webmvc-adapter中默认实现了一个请求来源解析器RequestOriginParser,我们可以将InterceptorConfig注入到项目中来使用:

com.alibaba.csp.sentinel.demo.spring.webmvc.config.InterceptorConfig#addSpringMvcInterceptor

private void addSpringMvcInterceptor(InterceptorRegistry registry) {SentinelWebMvcConfig config = new SentinelWebMvcConfig();config.setBlockExceptionHandler(new DefaultBlockExceptionHandler());config.setHttpMethodSpecify(true);config.setWebContextUnify(true);// 请求来源解析器config.setOriginParser(request -> request.getHeader("S-user"));registry.addInterceptor(new SentinelWebInterceptor(config)).addPathPatterns("/**");
}

可以看到默认取的是请求头中的S-user参数来标记请求的调用方来源,所以当请求头部中没有带S-user参数时sentinel上下文中就无法获取来源,所以就会影响授权规则的限流效果。

限流规则中的limitApp字段用于根据调用方进行流量控制。该字段的值有以下三种选项,分别对应不同的场景:

  • default:表示不区分调用者,来自任何调用者的请求都将进行限流统计。如果这个资源名的调用总和超过了这条规则定义的阈值,则触发限流。
  • {some_origin_name}:表示针对特定的调用者,只有来自这个调用者的请求才会进行流量控制。例如NodeA配置了一条针对调用者caller1的规则,那么当且仅当来自caller1对NodeA的请求才会触发流量控制。
  • other:表示针对除{some_origin_name}以外的其余调用方的流量进行流量控制。例如,资源NodeA配置了一条针对调用者caller1的限流规则,同时又配置了一条调用者为other的规则,那么任意来自非caller1对NodeA的调用,都不能超过other这条规则定义的阈值。

同一个资源名可以配置多条规则,规则的生效顺序为:{some_origin_name} > other > default

由于需要为每个调用来源origin的资源建立统计信息StatisticNode,大量使用会造成内存占用过多。这点官方faq中也给出了警示,注意origin数量不能太多,否则会导致内存暴涨,并且目前不支持模式匹配。

例如下面的规则,针对调用方为NodeB的请求进行限流,也就是对请求头中带有source=NodeB的请求进行限流,而不带source请求头或者请求头中source的值不为NodeB的请求不会触发限流。

根据调用链路入口限流:链路限流

NodeSelectorSlot中记录了资源之间的调用链路,这些资源通过调用关系,相互之间构成一棵调用树。这棵树的根节点是一个名字为machine-root的虚拟节点,调用链的入口都是这个虚节点的子节点。

一棵典型的调用树如下图所示:

                   machine-root/       \/         \chainA     chainB/              \/                \chain              chain

上图中来自入口chainAchainB的请求都调用到了资源chain,Sentinel允许只根据某个入口的统计信息对资源限流。比如我们可以设置 FlowRule.strategy为RuleConstant.CHAIN,同时设置FlowRule.ref_identity为chainA来表示只有从入口chainA的调用才会记录到chain的限流统计当中,而对来自chainB的调用漠不关心。

举个例子:chainA、chainB两个接口都调用某一资源chain,chainA->chain、chainB->chain可以看成两个简单的链路,此时可以针对chain配置链路限流,比如限制chainA调用chain,而chainB调用chain则不受影响,它的功能有点类似于针对来源配置项,而链路流控是针对上级接口,它的粒度更细。

示例代码如下:

@RequestMapping("sentinel")
@RestController
public class FlowChainController {@Resourceprivate FlowChainService flowChainService;@RequestMapping("/chainA")public String chainA(Integer num) {return flowChainService.chain(num);}@RequestMapping("/chainB")public String chainB(Integer num) {return flowChainService.chain(num);}
}@Service
public class FlowChainService {@SentinelResource(value = "chain",fallback = "fallback", fallbackClass = ExceptionUtil.class,blockHandler = "blockHandler", blockHandlerClass = ExceptionUtil.class)public String chain(Integer num) {return String.valueOf(10 / num);}
}

规则的配置如下:

这样当/sentinel/chainA的QPS大于1时,/sentinel/chainA就会触发限流,而/sentinel/chainB不会影响。

注意默认调用链路是收敛的,需要打开才可以进行链路流控:

      web-context-unify: false # 默认将调用链路收敛,需要打开才可以进行链路流控

调用链的入口是通过API方法ContextUtil.enter(name)定义的。

具有关系的资源流量控制:关联流量控制

当两个资源之间具有资源争抢或者依赖关系的时候,这两个资源便具有了关联。比如对数据库同一个字段的读操作和写操作存在争抢,读的速度过高会影响写得速度,写的速度过高会影响读的速度。如果放任读写操作争抢资源,则争抢本身带来的开销会降低整体的吞吐量。可使用关联限流来避免具有关联关系的资源之间过度的争抢。

举例来说,read和write这两个资源分别代表数据库读写,我们可以给read设置限流规则来达到写优先的目的:设置FlowRule.strategy为RuleConstant.RELATE同时设置FlowRule.ref_identity为write。这样当写库操作过于频繁时,读数据的请求会被限流。

@RequestMapping("sentinel")
@RestController
public class FlowRelateController {@RequestMapping("/read")public String read(Integer num) {return String.valueOf(10 / num);}@RequestMapping("/write")public String write(Integer num) {return String.valueOf(10 / num);}
}

规则配置如下:

这样当/sentinel/write的QPS大于1时,/sentinel/read就会触发限流。

流控效果

流控效果只用于根据QPS限流。

流量控制的手段包括下面3种,对应FlowRule中的controlBehavior字段:

  • 直接拒绝(快速失败)(RuleConstant.CONTROL_BEHAVIOR_DEFAULT)方式
  • WARM_UP(冷启动)(RuleConstant.CONTROL_BEHAVIOR_WARM_UP)方式
  • 排队等待(匀速器)(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER)方式

快速失败

该方式是默认的流量控制方式,当QPS超过任意规则的阈值后,新的请求就会被立即拒绝,拒绝方式为抛出FlowException,不做任何额外的处理,是最简单的效果。这种方式适用于对系统处理能力确切已知的情况下,比如通过压测确定了系统的准确水位时。

Warm Up

该方式主要用于系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过"冷启动",让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮的情况,对应的是令牌桶算法。

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

这个场景主要用于启动需要额外开销的场景,例如建立数据库连接等。

流控的原理是在流量入口处控制流量,让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,以便系统可以预热。最适合突发流量的场景。

冷启动,参考了Guava的算法,通过随时调整斜率,把流量在指定的时间之类缓慢调整到特定的阈值。

举个例子:对/sentinel/annotation资源设置直接限流,阈值为10,预热时长为10s,则刚访问此接口时,实际限流阈值为10/3,即为3,也就是刚开始的时候阈值只有3,当经过10s后,阈值才慢慢提高到10。

具体配置如下:

可以看到流量的增长趋势如下图所示:

排队等待

这种方式严格控制了请求通过的间隔时间,也即是让请求以均匀的速度通过,对应的是漏桶算法。

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

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

请求流量具有波峰波谷的特点,流控的原理是将前面的峰值流量延迟(排队时长)到后面再处理,既能最大化满足所有请求,又能保证用户体验。

让请求以均匀的速度通过,单机阈值为每秒通过数量,其余的排队等待;它还会让设置一个超时时间,当请求超过超时间时间还未处理,则会被丢弃。

测试案例:对/sentinel/annotation资源进行直接限流,设置阈值为10,设置流控效果为排队等候,等待超时时间设置为1000ms。当每秒10次请求时,再有请求就排队等候,等待超时时间为1000ms, 超时过后,请求将被踢出排队队列,返回限流异常。

可以看到流量的增长趋势如下图所示:

【sentinel】流控规则详解相关推荐

  1. Alibaba Sentinel | 流控规则设置

    文章目录 一.Sentinel概述 强大的优势: 组成部分: 二.微服务集成Sentinel 版本说明 安装Sentinel控制台: 1.docke安装 2.jar安装 启动控制台 微服务集成Sent ...

  2. Sentinel流控规则

    Sentinel流控规则 流控规则基本介绍 名词解释 资源名:唯一名称,默认请求路径 针对来源:Sentinel可以针对调用者进行限流,填写微服务名,默认default(不区分来源) 阈值类型/单机阈 ...

  3. 什么?Sentinel流控规则可以这样玩?

    点赞再看,养成习惯,微信搜索[牧小农]关注我获取更多资讯,风里雨里,小农等你,很高兴能够成为你的朋友. 项目源码地址:公众号回复 sentinel,即可免费获取源码 前言 上一篇文章中,我们讲解了关于 ...

  4. Spring Cloud Alibaba:Sentinel 流控规则

    文章目录 1. 前言 2. 阈值类型 2.1 QPS 2.2 线程数 3. 流控模式 3.1 直接 3.2 关联 3.3 链路 4. 流控效果 4.1 快速失败 4.2 Warm Up 4.3 排队等 ...

  5. 性能百万/s:腾讯轻量级全局流控方案详解

    作者:莫家文,腾讯事务型开发工程师 商业转载请联系腾讯WeTest获得授权,非商业转载请注明出处. 原文链接:http://wetest.qq.com/lab/view/320.html WeTest ...

  6. 性能百万/s:腾讯轻量级全局流控方案详解【转自Wetest】

    阿里用的方案是在nginx中配置限流(限流功能模块是自己开发的),流量统计线上是有监控打通的,具体的限流值是通过线上流量表现+线下性能测试(模拟线上场景)测试得出的. 全新的全局流控实现方案,既解决了 ...

  7. Sentinel流控规则_流控等待_分布式系统集群限流_线程数隔离_削峰填谷_流量控制_速率控制_服务熔断_服务降级---微服务升级_SpringCloud Alibaba工作笔记0037

    技术交流QQ群[JAVA,C++,Python,.NET,BigData,AI]:170933152 然后再看一下流控等待这个流控的规则 其实就是,如果流量来了很多,然后,请求,会进行排队,如果超时了 ...

  8. Sentinel流控规则_QPS直接失败_分布式系统集群限流_线程数隔离_削峰填谷_流量控制_速率控制_服务熔断_服务降级---微服务升级_SpringCloud Alibaba工作笔记0033

    技术交流QQ群[JAVA,C++,Python,.NET,BigData,AI]:170933152 好上节课,咱们说了一下流量控制的的介绍,下面咱们开始配置, 流控的规则,首先先看第一点,就是流控, ...

  9. Sentinel流控规则简介_分布式系统集群限流_线程数隔离_削峰填谷_流量控制_速率控制_服务熔断_服务降级---微服务升级_SpringCloud Alibaba工作笔记0032

    技术交流QQ群[JAVA,C++,Python,.NET,BigData,AI]:170933152 上节,我们配置好了sentinel的监控,启动了一个微服务,看了效果 然后接下来我们去点击这个簇点 ...

最新文章

  1. 虚拟化技术KVM的搭建
  2. 比特币的矿工为什么讨厌开发组Core?
  3. LeetCode Path Sum II(dfs或者bfs)
  4. 【嵌入式开发】 ARM 汇编 (指令分类 | 伪指令 | 协处理器访问指令)
  5. nginx+awstats多域名日志分析2
  6. textview点击后selector的pressed无效果
  7. linux指定查看文件目录,【Linux】查看指定目录下的每个文件或目录的大小
  8. ds哈希查找—二次探测再散列_大白话之哈希表和哈希算法
  9. mllib调参 spark_《Spark 官方文档》机器学习库(MLlib)指南
  10. Python进行数值计算
  11. Hadoop和Spark三大核心组件介绍与对比
  12. Atitit dsl exer v3 qb3 新特性
  13. NeatUpload
  14. jfinal 和bjui 常用前后交互方式
  15. 径向基神经网络与多层感知器的比较
  16. java数组的结构_详解Java数组结构
  17. 李开复致中国家长的信:培养快乐感性的孩子
  18. 计算机网络 信道复用技术
  19. MyBatis:万能Map和模糊查询(狂神)
  20. ReactNative常用插件使用

热门文章

  1. 高亲和力丨艾美捷DetergentOUT GB-S10去垢剂研究
  2. python计算整数各位数字之和_Python入门篇之数字 python分享整数各位数字之和
  3. oracle将奖金和工资相加,2019年工资薪金和年终奖合并入综合性所得测算个税实例讲解...
  4. [奇思异想]使用RabbitMQ实现定时任务
  5. sqlserver 没有备份误删数据_超实用的Word备份和恢复技巧,职场必备,为你的文件保驾护航!...
  6. 区块链推文@2019.1.24
  7. 开发一个二方包,优雅地为系统接入ELK(elasticsearch+logstash+kibana)
  8. endnote无法导入文献
  9. python画曲线图
  10. SysTick_系统定时器实现流水灯