# 流控

本文介绍如何使用流控插件 (opens new window)。

# 功能介绍

流控插件基于resilience4j (opens new window) 框架,以"流量"切入点,实现"非侵入式"流量控制;当前支持限流、熔断、隔离仓、错误注入与重试、熔断指标采集、系统规则、系统自适应流控能力,并且支持配置中心动态配置规则,实时生效。

  • 限流:对指定接口限制1S秒内通过的QPS,当1S内流量超过指定阈值,将触发流控,限制请求流量,在客户端和服务端都可生效。
  • 熔断:对指定接口配置熔断策略,可从单位统计时间窗口内的错误率或者慢请求率进行统计,当请求错误率或者慢请求率达到指定比例阈值,即触发熔断,在时间窗口重置前,隔离所有请求,在客户端和服务端都可生效。
  • 隔离仓:对指定接口设置允许的最大并发量,当超过最大并发量时,对并发流量进行排队等待控制,等待超过最大等待时间则拒绝调用,避免瞬时并发流量过大导致服务崩溃,在客户端和服务端都可生效。
  • 重试:当服务遇到非致命的错误时,可以通过重试的方式避免服务的最终失败。
  • 错误注入:指在服务运行时,给指定服务配置错误注入策略,在客户端访问目标服务前,以指定策略模式返回。该策略多用于减少目标服务的访问负载,可作为降级的一种措施。
  • 熔断指标采集:当服务配置了熔断策略后,插件会异步采集熔断的相关信息,并通过监控插件进行指标上报。
  • 系统规则:在服务运行时,若系统负载,CPU使用率,并发线程数,请求平均响应时间,请求qps任意指标超出阈值,将触发流控,限制请求流量。
  • 系统自适应:在服务运行时,根据系统当前负载状态,以及过去一段时间内系统数据,对请求进行自适应流控。

# 参数配置

# Sermant-agent配置

流控插件依赖动态配置中心,需要在Sermant-agent中配置动态配置中心的地址(dynamic.config.serverAddress),动态配置中心的类型(dynamic.config.dynamicConfigType),具体参考Sermant-agent使用手册。

# 插件配置

流控插件需打开是否开启ServiceComb适配(flow.control.plugin.useCseRule),是否开启指标监控(flow.control.plugin.enable-start-monitor)等开关,可在${path}/sermant-agent-x.x.x/agent/pluginPackage/flowcontrol/config/config.yaml找到插件的配置文件,配置如下所示:

flow.control.plugin:
  useCseRule: false # 是否开启ServiceComb适配
  enable-start-monitor: false # 是否启动指标监控
  enable-system-adaptive: false # 是否开启系统自适应流控,开启此开关需enable-system-rule配置项也开启
  enable-system-rule: false # 是否开启系统规则流控
参数键 说明 默认值 是否必须
useCseRule 是否开启ServiceComb适配;
true:插件根据应用配置,服务配置,自定义标签订阅配置
false:插件根据实例服务名进行配置订阅
true 是
enable-start-monitor 是否开启指标监控; true:熔断指标数据通过监控插件上传至Prometheus,详情查看监控插件 false 否
enable-system-adaptive 是否开启系统自适应流控;
true:根据系统负载对请求流量进行自适应流控
false 否
enable-system-rule 是否开启系统规则流控;
true:根据流控策略中的系统参数阈值进行流控
false 否

useCseRule说明: Sermant当前支持zookeeper和ServiceComb-kie配置中心,默认采用zookeeper配置中心,若用户使用ServiceComb-kie,则需要设置useCseRule配置为true

# 详细治理规则

流控配置主要基于group进行配置订阅,该group由多个键值对组成。下面详细说明group和键值对key和value的设置规则。

关于group key 的介绍以及配置中心的设置参考动态配置中心使用手册。

# 根据采用配置中心的不同,group的值将会有所区别,以下介绍group的设置规则:

  • 采用zookeeper

    此时插件将根据宿主应用的服务名进行订阅, 即应用配置的spring.applicaton.name, 插件订阅配置的group为service=${spring.applicaton.name}。

  • 采用KIE

    此时插件将根据应用配置,服务配置以及自定义配置三项数据配置同时订阅, 而这三类配置可参考${path}/sermant-agent-x.x.x/agent/config/config.properties, 相关配置如下:

    # 服务app名称
    service.meta.application=default
    # 服务版本
    service.meta.version=1.0.0
    # serviceComb 命名空间
    service.meta.project=default
    # 环境
    service.meta.environment=development
    # 自定义标签,按需配置,用于后续的配置订阅
    service.meta.customLabel=public
    service.meta.customLabelValue=default
    

    应用配置,服务配置,自定义配置说明参考CSE配置中心概述 (opens new window)。

    • 应用配置:由service.meta.application与service.meta.environment组成, 对应的group为app=default&environment=development。
    • 服务配置:由service.meta.application、service.meta.environment以及服务名组成,此处服务即spring.application.name, 对应的group为app=default&environment=development&service=DynamicConfigDemo。
    • 自定义配置:由service.meta.customLabel与service.meta.customLabelValue组成, 对应的group为public=default。

# 流控插件根据配置键key的前缀进行规则匹配,以下介绍配置键key的规则:

流量治理采用流量标记+流控规则的方式对指定的流量进行流控,所谓流量标记,通俗讲为请求信息,例如接口路径、接口方法类型、请求头以及下游服务名。

流控规则是否生效取决于流量标记,当流量标记与请求相匹配,流控规则才会生效。而如何将流量标记对应上具体规则,则取决于业务场景名,通常流量标记与流控规则配置均要配置指定前缀。

例如流量标记的键key需以servicecomb.MatchGroup为前缀, 而限流规则的键key需以servicecomb.rateLimiting为前缀,以一个具体的例子:

流量标记配置键key为:servicecomb.MatchGroup.flow。

限流规则配置键key为:servicecomb.rateLimiting.flow。

如上,flow即为业务场景名,仅当两者业务场景名称一致,当请求匹配上流量标记时,限流规则才会生效。

# 下面介绍流控规则配置键key对应值value的相关信息:

  • 流量标记

    流量标记配置键前缀: servicecomb.MatchGroup

    以zookeeper为例,当使用zookeeper配置中心设置流量标记规则时,结合上述group和key的说明,需要在zookeeper中创建节点/service=${spring.applicaton.name}/servicecomb.MatchGroup.${sceneName},节点内容为流量标记规则,如下述yaml内容。

    matches:            # 匹配器集合,可配置多个
    - apiPath:          # 匹配的api路径, 支持各种比较方式,相等(exact)、包含(contains)等
        exact: /degrade # 具体匹配路径
      headers:          # 请求头
        key: 
          exact: value  # 请求头值,此处为key=value, 比较方式同apiPath
      method:           # 支持方法类型
      - GET
      name: degrade     # 可选,配置名
    

    流量标记解释:

    流量标记请求路径(apiPath)配置说明

    流量标记的请求路径会因不同的请求协议配置而存在差异,当前主要为Http(Spring)与Rpc(Dubbo)协议,下面分别说明两种请求协议的配置方式:

    • Http协议

      该协议依据请求路径进行匹配,例如请求路径为localhost:8080/test/flow, 则实际拿到的路径为/test/flow,因此若需设置匹配规则,需依据该路径进行配置。

      值得注意的是,如果用户配置了contextPath, 则需要加上contextPath前缀才可生效,即流量标记中请求路径为${contextPath}/test/flow。

    • Rpc协议(Dubbo)

      该协议调用需要基于接口+方法,例如请求的接口为com.demo.test, 其方法为flow, 则对应的请求路径为com.demo.test.flow, 特别的,如果用户有配置接口的版本,例如指定的version为1.0.0, 则请求路径为com.demo.test:1.0.0.flow。同时需要配置请求方法为POST, RPC协议仅支持POST类型。

  • 限流

    限流规则配置键前缀: servicecomb.rateLimiting

    限流规则:

    配置项 说明 默认值 是否必须
    limitRefreshPeriod 单位统计时间,单位毫秒, 若需配置秒则可增加单位S, 例如10S 1000ms 否
    rate 单位统计时间所能通过的请求个数 1000 否

    以zookeeper为例,当使用zookeeper配置中心设置限流规则时,结合上述group和key的说明,需要在zookeeper中创建节点/service=${spring.applicaton.name}/servicecomb.rateLimiting.${sceneName},节点内容为限流规则,如下述yaml内容:

    imitRefreshPeriod: 1000
    rate: 2
    

    上述限流规则解释: 若1秒内超过2个请求,即触发流控效果。

  • 熔断

    熔断规则配置键前缀: servicecomb.circuitBreaker

    熔断规则:

    配置项 说明 默认值 是否必须
    failureRateThreshold 熔断所需达到的错误率 50 否
    minimumNumberOfCalls 滑动窗口内的最小请求数, 超过最小请求数才开始判断熔断条件 100 否
    name 配置项名称,可选参数 null 否
    slidingWindowSize 滑动统计窗口大小,支持毫秒与秒,例如1000为1000毫秒, 10S代表10秒 100ms 否
    slidingWindowType 滑动窗口类型,目前支持time与count两种类型,前者基于时间窗口统计,后者基于请求次数 time 否
    slowCallDurationThreshold 慢请求阈值,单位同滑动窗口配置 60s 否
    slowCallRateThreshold 慢请求占比,当慢调用请求数达到该比例触发通断 100 否
    waitDurationInOpenState 熔断后恢复时间 60s 否

    以zookeeper为例,当使用zookeeper配置中心设置熔断规则时,结合上述group和key的说明,需要在zookeeper中创建节点/service=${spring.applicaton.name}/servicecomb.circuitBreaker.${sceneName},节点内容为熔断规则,如下述yaml内容:

    failureRateThreshold: 90
    minimumNumberOfCalls: 3
    name: degrade
    slidingWindowSize: 10S
    slidingWindowType: time
    slowCallDurationThreshold: "1"
    slowCallRateThreshold: 80
    waitDurationInOpenState: 10s
    

    上述熔断规则解释: 10秒内,若流量标记的接口请求次数超过3次,且错误率超过90%或者慢请求占比超过80%则触发熔断。

  • 隔离

    隔离规则配置键前缀: servicecomb.bulkhead

    隔离规则:

    配置项 说明 默认值 是否必须
    maxConcurrentCalls 最大并发数 1000 否
    maxWaitDuration 最大等待时间,若线程超过maxConcurrentCalls,会尝试等待,若超出等待时间还未获取资源,则抛出隔离仓异常 0 否
    name 可选,配置名称 null 否

    以zookeeper为例,当使用zookeeper配置中心设置隔离规则时,结合上述group和key的说明,需要在zookeeper中创建节点/service=${spring.applicaton.name}/servicecomb.circuitBreaker.${sceneName},节点内容为隔离规则,如下述yaml内容:

    maxConcurrentCalls: "5"
    maxWaitDuration: "10S"
    name: "隔离仓"
    

    上述隔离规则解释: 针对流量标记的接口, 若最大并发数超过5,且新的请求等待10S,还未获取资源,则触发隔离仓异常。

  • 重试

    重试规则配置键前缀: servicecomb.retry

    重试规则:

    配置项 说明 默认值 是否必须
    waitDuration 重试等待时间,默认毫秒;支持秒单位,例如2S 10ms 否
    retryStrategy 重试策略,当前支持两种重试策略:固定时间间隔(FixedInterval), 指数增长间隔(RandomBackoff) FixedInterval 否
    maxAttempts 最大重试次数 3 否
    retryOnResponseStatus HTTP状态码,当前仅支持HTTP请求;针对dubbo请求,可通过配置异常类型确定是否需要重试,默认为RpcException null 否

    以zookeeper为例,当使用zookeeper配置中心设置重试规则时,结合上述group和key的说明,需要在zookeeper中创建节点/service=${spring.applicaton.name}/servicecomb.retry.${sceneName},节点内容为重试规则,如下述yaml内容:

    waitDuration: "2000"
    retryStrategy: FixedInterval
    maxAttempts: 2
    retryOnResponseStatus:
      - 500
    

    上述重试规则解释: 针对流量标记的接口, 当请求抛出500异常时进行重试,直到重试成功或者达到最大重试次数。

  • 错误注入

    错误注入规则配置键前缀: servicecomb.faultInjection

    错误注入规则:

    配置项 说明 默认值 是否必须
    type 错误注入类型, 目前支持abort(请求直接返回)与delay(请求延时) delay 否
    percentage 错误注入触发概率 -1 是
    fallbackType 请求调用返回类型,仅type=abort生效。当前支持两种ReturnNull:直接返回空内容,状态码200;ThrowException: 按照指定错误码返回,关联配置errorCode ThrowException 否
    errorCode 指定错误码返回, 默认500, 仅在type=abort且fallbackType=ThrowException生效 500 否
    forceClosed 是否强制关闭错误注入能力, 当为true时,错误注入将不会生效。默认false false 否

    以zookeeper为例,当使用zookeeper配置中心设置错误注入规则时,结合上述group和key的说明,需要在zookeeper中创建节点/service=${spring.applicaton.name}/servicecomb.retry.${sceneName},节点内容为错误注入规则,如下述yaml内容:

    type: abort
    percentage: 100
    fallbackType: ReturnNull
    forceClosed: false
    errorCode: 503
    

    上述错误注入规则解释: 当请求流量标记的接口时,100%将返回空。

  • 系统规则

    系统规则配置键前缀: servicecomb.system

    配置项 说明 默认值 是否必须
    systemLoad 系统负载阈值,仅支持linux Double.MAX_VALUE 否
    cpuUsage 系统cpu使用率阈值 1.0 否
    qps 入口流量的qps阈值 Double.MAX_VALUE 否
    aveRt 入口流量的平均响应时间阈值,单位ms Long.MAX_VALUE 否
    threadNum 入口流量的并发线程数阈值 Long.MAX_VALUE 否

    以zookeeper为例,当使用zookeeper配置中心设置系统规则时,结合上述group和key的说明,需要在zookeeper中创建节点/service=${spring.applicaton.name}/servicecomb.system.${sceneName},节点内容为系统规则,如下述yaml内容:

    systemLoad: 5
    cpuUsage: 0.6
    qps: 1000
    aveRt: 100
    threadNum: 200
    

    上述系统规则解释:

    • 针对使用流控插件的应用示例来说,当系统负载超过5,或者cpu使用率超过0.6,或者qps超过1000,或者请求响应时间小鱼100ms,或者并发线程数大于200时,即触发限流,返回对应异常信息。
    • 若开启系统自适应开关,则当系统负载大于5时,若当前并发线程数大于系统容量(系统容量由qps * minRt计算得出),则触发限流。

# 基于配置文件设置规则

若应用未采用配置中心的方式配置流控规则,也可采用配置文件的方式使用流控能力。

流控插件在应用启动时,会尝试的从SpringBoot加载的配置源读取流控规则以及对应的流量标记,用户需要在启动之前进行配置。如下为配置示例, 示例配置直接基于application.yml进行配置

servicecomb:                            # 流量标记前缀
  matchGroup:                           # 流量标记前缀
    demo-fault-null:                    # 错误注入场景
      matches:                          # 匹配器集合
        - apiPath:                      # 匹配的api路径
            exact: "/flow"              # 具体匹配路径
    demo-retry:                         # 重试场景
      matches:                          
        - apiPath:                      
            prefix: "/retry"            
          serviceName: rest-provider    
          method:                       # 支持方法类型
          - GET                         
    demo-rateLimiting:                  # 限流场景
      matches:
        - apiPath:
            exact: "/flow"
    demo-circuitBreaker-exception:      # 熔断场景
      matches:
        - apiPath:
            exact: "/exceptionBreaker"
    demo-bulkhead:                      # 隔离舱场景
      matches:
        - apiPath:
            exact: "/flowcontrol/bulkhead"
    demo-system:                        # 系统规则场景
      matched:
        - apiPath:
            prefix: /
  rateLimiting:                         # 限流规则
    demo-rateLimiting:
      rate: 1
  retry:                                # 重试规则
    demo-retry: |
      maxAttempts: 3
      retryOnResponseStatus:
      - 500
  circuitBreaker:                       # 熔断规则
    demo-circuitBreaker-exception: |
      failureRateThreshold: 44
      minimumNumberOfCalls: 2
      name: 熔断
      slidingWindowSize: 10000
      slidingWindowType: time
      waitDurationInOpenState: 5s
  bulkhead:                             # 隔离规则
    demo-bulkhead: |
      maxConcurrentCalls: 1
      maxWaitDuration: 10
  faultInjection:                       # 错误注入规则
    demo-fault-null: |
      type: abort
      percentage: 100
      fallbackType: ReturnNull
      forceClosed: false
  system:                               # 系统流控规则
    demo-system: |
      systemLoad: 0.6
      cpuUsage: 0.6
      qps: 100
      aveRt: 20
      threadNum: 100

# 基于Sermant动态配置中心发布规则

基于Sermant动态配置中心发布规则,可以参考动态配置中心使用手册。

# 支持版本与限制

# 支持版本

框架类型 版本支持
SpringBoot 1.2.x - 2.6.x
SpringWebMvc 4.1.3.RELEASE - 5.3.x
Dubbo 2.6.x-2.7.x

# 限制

# 操作和结果验证

下面将演示如何使用流控插件,验证springboot应用采用zookeeper配置中心,设置限流策略场景。

# 准备工作

# 步骤一:编译打包demo应用

在${path}/Sermant-examples/flowcontrol-demo/spring-cloud-demo/spring-provider目录执行以下命令:

# windows,Linux,mac
mvn clean package

打包成功后,在${path}/Sermant-examples/flowcontrol-demo/spring-cloud-demo/spring-provider/target得到spring-provider.jar。

说明: ${path}为demo应用下载所在路径。

# 步骤二:修改插件配置

参考插件配置 修改${path}/sermant-agent-x.x.x/agent/pluginPackage/flowcontrol/config/config.yaml文件为以下内容:

flow.control.plugin:
  useCseRule: false # 是否开启ServiceComb适配
  enable-start-monitor: false # 是否启动指标监控
  enable-system-adaptive: false # 是否开启系统自适应流控
  enable-system-rule: false # 是否开启系统规则流控

说明: ${path}为sermant所在路径。

# 步骤三:启动demo应用

参考如下命令启动demo应用

# windwos
java -javaagent:${path}\sermant-agent-x.x.x\agent\sermant-agent.jar -Dspring.application.name=spring-flow-provider -Dspring.cloud.zookeeper.connectString=127.0.0.1:2181 -jar spring-provider.jar

#linux mac
java -javaagent:${path}/sermant-agent-x.x.x/agent/sermant-agent.jar -Dspring.application.name=spring-flow-provider -Dspring.cloud.zookeeper.connectString=127.0.0.1:2181 -jar spring-provider.jar

说明: ${path}为sermant实际安装路径,x.x.x代表sermant某个版本号。

# 步骤四:发布流量标记

参考使用动态配置中心使用手册,发布如下配置:

{
  "value": "alias: scene\nmatches:\n- apiPath:\n    exact: /flow\n  headers: {}\n  method:\n  - GET\n  name: flow\n",
  "group": "service=spring-flow-provider",
  "key": "servicecomb.matchGroup.sceneFlow"
}

利用zookeeper提供的命令行工具来发布流量标记策略和流控策略:

  1. 在${path}/bin/目录执行以下命令创建节点/service=spring-flow-provider
# linux mac
./zkCli.sh -server localhost:2181 create /service=spring-flow-provider

# windows
zkCli.cmd -server localhost:2181 create /service=spring-flow-provider
  1. 在${path}/bin/目录执行以下命令创建节点/service=spring-flow-provider/servicecomb.matchGroup.sceneFlow和数据"alias: scene\nmatches:\n- apiPath:\n exact: /flow\n headers: {}\n method:\n - GET\n name: flow\n"
# linux mac
./zkCli.sh -server localhost:2181 create /service=spring-flow-provider/servicecomb.matchGroup.sceneFlow "alias: scene
matches:
- apiPath:
    exact: /flow
  headers: {}
  method:
  - GET
  name: flow"
  
# windwos
zkCli.cmd -server localhost:2181 create /service=spring-flow-provider/servicecomb.matchGroup.sceneFlow "alias: scene
matches:
- apiPath:
    exact: /flow
  headers: {}
  method:
  - GET
  name: flow"
  1. 在${path}/bin/目录执行以下命令创建节点/service=spring-flow-provider/servicecomb.rateLimiting.sceneFlow和数据"limitRefreshPeriod: \"2S\"\nname: flow\nrate: \"4\"\n"
# linux mac
./zkCli.sh -server localhost:2181 create /service=spring-flow-provider/servicecomb.rateLimiting.sceneFlow "limitRefreshPeriod: 2S
name: flow
rate: 4"

#windows
zkCli.cmd -server localhost:2181 create /service=spring-flow-provider/servicecomb.rateLimiting.sceneFlow "limitRefreshPeriod: 2S
name: flow
rate: 4"

说明:${path}为zookeeper的安装目录。

# 验证

通过curl工具多次请求localhost:8003/flow, 若在2秒内请求数超过4个时返回rate limited,则触发流控成功,效果如下:

上次更新: 2024/4/1 03:31:21