流量控制插件

更新时间:
复制 MD 格式

本文介绍了流量控制插件的配置及常见场景示例。

1. 概述

  • 流量控制插件用于对API进行限流,流量控制插件可以对APIApp(访问的AK)用户(访问方的App归属用户),以及自定义参数进行多种维度的限流。

  • 流量控制插件目前支持两种配置模板:

    • 参数流控配置,支持自定义参数的流控配置。

    • 基础流控配置,与控制台上的流量控制功能保持兼容。

  • 流量控制现在合并进了插件体系。现存的流量控制界面与接口仍然可以使用,流量控制策略流量控制插件属于同一种插件类型,如果你绑定了流量控制插件,则流量控制策略会失效

  • 使用原有的流量控制接口或控制台创建或更改流量控制,会同步数据至插件系统,但不会反向同步。

2. 基础流控配置

2.1. 流控能力

2.1.1 基础流控支持以下的流控维度:

  • API 流量限制:该策略绑定的API在单位时间内被调用的次数不能超过设定值,单位时间可选秒、分钟、小时、天,如5000次/分钟。

  • APP 流量限制:每个App对该策略绑定的任何一个API在单位时间内的调用次数不能超过设定值。如50000次/小时。

  • 用户流量限制:每个阿里云账号对该策略绑定的任何一个 API 在单位时间内的调用次数不能超过设定值。一个阿里云账号可能有多个 APP,所以对阿里云账号的流量限制就是对该账号下所有 APP 的流量总和的限制。如 50 万次/天。

说明

在一个流控策略插件里面,这三个值可以同时设置。请注意,用户流量限制应不大于 API 流量限制,APP 流量限制应不大于用户流量限制。即 APP 流量限制 <= 用户流量限制 <= API 流量限制。

此外,您可以在流控策略下添加特殊应用(APP)和特殊用户。对于特例,流控策略基础的API 流量限制依然有效,您需要额外设定一个阈值作为该 APP 或者该用户的流量限制值,该值不能超过策略的API流量限制值,同时流控策略基础的APP流量限制用户流量限制对该 APP 或用户失效。

2.1.2 流控插件支持的时间维度及其算法

API网关流控插件支持的时间维度分别是秒(SECOND)、分钟(MINUTE)、小时(HOUR)、天(DAY)。其中分钟、小时、天维度使用的是固定时间窗口算法。秒级别默认使用的是令牌桶流控算法,若不满足需求,可以配置固定时间窗口流控算法。两种算法分别如下:

  • 令牌桶流控算法:秒级别的流控默认用的是令牌桶算法。令牌桶算法有两个概念,令牌桶和一个Waiting Queue。API网关的引擎会定期向令牌桶发放令牌,客户端发送的请求进到API网关后会先去令牌桶里取令牌,取到令牌就通过了。如果没有取到令牌,请求会进入一个Queue中排队,下一波发令牌的时候优先分配给Queue中请求。Queue满了之后,请求再进来就会报429;如果不想进入Queue排队,可以直接配置blockingMode: QUICK_RETURN,这样就不会进入Queue排队,如果没有取到令牌,直接报错429。

  • 固定时间窗口流控算法:限制单位时间的流量,例如限制每分钟1000次请求,超过部分报429,下一分钟重置请求计数。

2.2. 基础流控插件配置

可以选择JSON或者YAML格式的来配置您的插件,两种格式的schema相同,可以搜索yaml to json转换工具来进行配置格式的转换,YAML格式的模板见下表。

---
unit: SECOND         # 控制区间, 取值: SECOND, MINUTE, HOUR, DAY
apiDefault: 1000     # 允许的总流量值
controlMode: FIX_WINDOW  # 当时间维度为秒时,指定流控算法为固定时间窗口算法
blockingMode: QUICK_RETURN     #令牌桶流控算法时,不会进入Queue排队,如果没有取到令牌,直接报429
userDefault: 30      # (可选)每个用户的默认流量最大值, 0表示不进行限制, 不能大于总流量值
appDefault: 30       # (可选)每个APP允许的流量最大值, 0表示不进行限制, 不能大于总流量值
specials:            # (可选)特殊流控, 支持"APP"和"USER"两种特殊维度
  - type: "APP"      # 针对不同应用(AK)进行的流控
    policies:
    - key: 10123123  # AppId, AppId的取值请在API网关控制台->应用管理->应用详情处查看
      value: 10      # 特殊流控值, 不能大于总流量值
    - key: 10123123  # AppId控
      value: 10      # 特殊流控值, 不能大于总流量值
  - type: "USER"     # 针对不同的阿里云账户进行的流控
    policies:
    - key: 123455    # 阿里云账号ID, 可点击阿里云控制台左上角查看账号ID
      value: 100     # 特殊流控值, 不能大于总流量值

2.3 基础流控插件支持插件数据集

2.3.1 创建流控插件数据集

  1. 登录API网关控制台,在左侧导航栏单击API管理 > 插件管理,进入插件数据集页签。

  2. 单击右上角的创建数据集,在弹出框中自定义数据集的名称类型选择TRAFFIC_CONTROL_POLICY,单击确定即可生成数据集。

  3. 进入刚生成的数据集,单击右上角的创建数据集条目,即可在页面中配置流控插件支持的keyvalue,其中,keyAppId或阿里云账号ID。value则是对应的流控值。

2.3.2 流控插件配置插件数据集示例

基础流控插件支持使用插件数据集,特殊流控specials策略可使用插件数据集配置APP和流控值、用户阿里云账号ID和流控值。示例如下:

---
unit: SECOND         # 控制区间, 取值: SECOND, MINUTE, HOUR, DAY
apiDefault: 1000     # 允许的总流量值
userDefault: 30      # (可选)每个用户的默认流量最大值, 0表示不进行限制, 不能大于总流量值
appDefault: 30       # (可选)每个APP允许的流量最大值, 0表示不进行限制, 不能大于总流量值
specials:            # (可选)特殊流控, 支持"APP"和"USER"两种特殊维度
  - type: "APP"      # 针对不同应用(AK)进行的流控
    policyDatasetId: 87b65008e92541938XXXXXXXX6eda5		# 插件数据集ID
    policies:
    - key: 10123123  # AppId, AppId的取值请在API网关控制台->应用管理->应用详情处查看
      value: 10      # 特殊流控值, 不能大于总流量值
    - key: 10123123  # AppId控
      value: 10      # 特殊流控值, 不能大于总流量值
  - type: "USER"     # 针对不同的阿里云账户进行的流控
    policyDatasetId: 87b65008eXXXXXXXXXXXXa236eda5		# 插件数据集ID
    policies:
    - key: 123455    # 阿里云账号ID, 可点击阿里云控制台左上角查看账号ID
      value: 100     # 特殊流控值, 不能大于总流量值
重要

本次开发只针对基础配置模式的插件格式进行插件数据集的支持,对参数流控配置模式的插件配置暂不进行插件数据集的支持。

3. 参数流控配置

参数流控可以针对用户的请求参数以及条件执行进行流控,参数流控配置支持如下特性:

  • 支持秒、分钟、小时、天的流控维度。

  • 可以根据请求参数、系统参数设置条件,来执行不同的流控维度。

  • 可以使用单个参数、或多个参数的组合来设置流控。

  • 可以设置流控的范围为API或插件。

3.1. 快速开始

有这样一个场景,我们希望执行如下的规则执行流控,针对每个访问的客户端IP地址,当用户使用了AppId:10001Key做了签名认证时,设置流控为100请求/秒,对其他的场合设置为10请求/秒

针对这个场景我们的插件配置如下,这里我们使用yaml来配置插件。

---
scope: "PLUGIN"
#
# 这个流控依赖两个系统参数
# 1. 用户签名的AppId,通过系统参数CaAppId获取
# 2. 用户来源的ClientIP,通过系统参数CaClientIp获取
parameters:
  AppId: "System: CaAppId"
  ClientIP: "System: CaClientIp"
rules:
  # 第一条流控策略,当`AppId`为`10001`时生效,对每个ClientIP限流为`100/秒`
  - name: "Vip"
    condition: "$AppId = 10001"
    byParameters: "ClientIP"
    limit: 100
    period: SECOND
  # 第二条流控策略名为`PerClientIP`,对每个ClientIP限流为`10/秒`
  - name: "PerClientIP"
    byParameters: "ClientIP"
    bypassEmptyValue: true   #当rules中的规则没有添加condition,以byParameters参数为判断条件时,参数为空或传了空值此规则不生效,会走默认流控策略
    limit: 10
    period: SECOND

3.2. 参数流控插件配置

参数流控插件使用yaml或等价的json格式进行插件元数据配置。

---
scope: "PLUGIN"                # 流控插件的作用范围:目前可选为"PLUGIN", "API"
blockingMode: QUICK_RETURN     #不会进入Queue排队,如果没有取到令牌,直接报429,详情可查看下面的字段说明
controlMode: FIX_WINDOW  # 当时间维度为秒时,指定流控算法为固定时间窗口算法
defaultLimit: 100              # 默认流控值,如果设置了默认流控值
defaultPeriod: SECOND          # 默认流控周期
defaultRetryAfterBySecond: 60  #返回Retry-After标头,它提供建议在下一个请求之前需要等待多长时间
defaultErrorMessage: "Throttled by 100/SECOND"
parameters:                    # 参数列表, 可用于流控的参数
  clientIp: "System:CaClientIp"
  userId: "Token:userId"
rules:
  - name: "ByClientIp"
    byParameters: "clientIp"
    condition: "$clientIp !in_cidr '61.7.XX.XX/24'"
    limit: 10
    period: MINUTE
    retryAfterBySecond: 60    #返回Retry-After标头,它提供建议在下一个请求之前需要等待多长时间
    errorMessage: "Throttled by 10/MINUTE from ${clientIp}"
  - name: "每个用户限制10条/分钟,管理员除外"
    byParameters: "clientIp"
    condition: "$userId !like 'admin%'"
    limit: 10
    period: MINUTE
    retryAfterBySecond: 60    #返回Retry-After标头,它提供建议在下一个请求之前需要等待多长时间
  - name: "每个IP限制10条/分钟"
    byParameters: "clientIp"
    condition: "$clientIp in_cidr '67.0.XX.XX/8'"
    limit: 10
    period: MINUTE
  - name: "每个用户限制15条/分钟"
    condition: "$userId !like 'admin%'"
    limit: 15
    period: MINUTE
    byParameters: "clientIp"

插件配置的字段说明如下:

  • scope(必选):流控插件的作用范围,支持APIPLUGIN两种取值,如果多个API都绑定了同一个插件,则scope的取值会影响流控策略的作用范围,比如:某个策略取值为10次/秒

    • 当取值为API时:流控策略在每个API中分别生效,在本例中,每个API的限流均为10次/秒

    • 当取值为PLUGIN时:所有绑定了本插件的API共享这个限流,如果本例子中的插件绑定了一堆API,则这一堆API的总流控限制为10次/秒

  • parameters(必选):参与流控的参数表,参考参数与条件表达式的使用文档中的描述。

  • rules(可选):流控策略的列表,如果没有设置默认流控defaultLimitperiod,则不能为空,每个流控策略包含以下字段:

    • name(必选):流控策略的名称,合法值为[A-Za-z0-9_-]+,在同一个插件中保持唯一。

    • byParameters(必选):流控参数,如果使用多个参数组合流控,以“,”分割,比如:ClientIP表示,针对每个ClientIP的取值分别进行流控,UserId,Action表示对这两个参数的组合取值分别进行流控。

    • bypassEmptyValue(可选):值为true时,当rules中的规则没有添加condition,以byParameters参数为判断条件时,参数为空或传了空值此规则不生效,会走默认流控策略。

    • condition(可选):如果设置了条件,只有当条件符合时,才会执行此条流控策略。

    • limit(必选):流控值,正整数,当为-1时表示当命中此条件时不需要流控。

    • period(必选): 流控周期,取值:SECONDMINUTEHOURDAY

    • errorMessage(可选):定制错误信息,可以以模板的方式来定义,在parameters中定义的参数,可以以${Name}的方式来配置。

    • retryAfterBySecond(可选):返回Retry-After标头,它提供建议在下一个请求之前需要等待多长时间。

  • defaultLimit(可选):默认流控值,正整数。

  • defaultPeriod(可选):流控周期,取值: SECONDMINUTEHOURDAY

  • defaultErrorMessage(可选):定制错误信息,当配置了定制的错误信息后,返回的X-Ca-Error-Message头会使用定制的错误信息,这个信息无法使用参数。

  • defaultRetryAfterBySecond(可选):默认返回的Retry-After标头,它提供建议在下一个请求之前需要等待多长时间。

  • blockingMode(可选):API网关使用了标准的令牌桶算法来实现流控功能,关于字段值以及算法详情如下:

    • QUEUE(默认值):令牌桶算法有两个概念:令牌桶和一个Waiting Queue。API网关的引擎会定期向令牌桶发放令牌,客户端发送的请求进到API网关后会先去令牌桶里取令牌,取到令牌就通过了。如果没有取到令牌,请求会进入一个Queue中排队,下一波发令牌的时候优先分配给Queue中请求。Queue满了之后,请求再进来就会报429。

    • QUICK_RETURN:不会进入Queue排队,如果没有取到令牌,直接报429。

  • controlMode: 当时间维度为秒时,指定流控算法。默认取值TOKEN_BUCKET(令牌桶流控算法),可以配置为FIX_WINDOW(固定时间窗口流控算法 )。

3.3. 参数说明

流控插件支持以下位置的参数。

位置名称

适用范围

说明

Method

请求

HTTP请求方法 (大写),如:GETPOST……。

Path

请求

HTTP完整请求路径,如:/path/to/query

Header

请求

使用Header:{Name}获取名字为{Name}HTTP头的第一个值。

Query

请求

使用Query:{Name}获取QueryString中名字为{Name}的第一个值。

Form

请求

使用Form:{Name}获取请求Form中名字为{Name}的第一个值。

Host

请求

使用Host:{Name}获取匹配到的泛域名模板参数。

Parameter

请求

使用Parameter:{Name}获取用户API自定义参数中名字为Name的第一个值。

System

请求

使用System:{Name}获取名字为{Name}的系统参数值。

Token

请求

当处于jwtoauth2授权场景时,使用Token:{Name}获取token中名字为{Name}的值。

3.4. 执行规则

API网关按照如下的顺序执行参数流控:

  • 插件会使用parameters的配置,从请求上下文中获取参数表。

  • 所有condition执行结果为true或未配置condition的策略都会被执行。

  • 如果命中策略列表中有多条策略的byParameters配置相同,则选择配置顺序靠前的那一条执行,其余的策略不会生效。

4. 配置样例

4.1. 基础流控配置样例

基础流控可支持API流控、不同AppKey以及不同用户级别的流控。

---
unit: SECOND           # 默认的流控单位, 支持: SECOND,MINUTE,HOUR,DAY
apiDefault: 50         # API整体流控
defaultRetryAfterBySecond: 60  #默认返回Retry-After标头,它提供建议在下一个请求之前需要等待多长时间
appDefault: 20         # (可选)针对每个APP的流控值, 不大于API整体流控
userDefault: 30        # (可选)针对每个用户的流控值, 不大于API整体流控
specials:              # (可选)特殊流控, 支持"APP"和"USER"两种特殊维度
  - type: "APP"        # 针对不同应用(AppKey)进行的流控
    policies:
      - key: 10001     # AppId, AppId的取值请在API网关控制台->应用管理->应用详情处查看
        value: 3       # 特殊流控值, 不大于API整体流控
      - key: 10003
        value: 40
  - type: "USER"       # 针对不同的阿里云账户进行的流控
    policies:
      - key: 102       # 阿里云账号ID, 可点击阿里云控制台上角查看账号ID
        value: 10      # 特殊流控值, 不大于API整体流控
      - key: 233
        value: 35

4.2. 按照源IP进行参数限流

在这个例子中,我们配置了的限流策略。

  • 每个源IP允许100次/分钟的调用。

  • 客户端IP处于58.66.XX.XX/24范围时,不限制访问。

  • 对客户端IP处于63.0.XX.XX73.0.XX.XX/24范围时,访问限制为5次/天

---
scope: API             # 限流的作用范围,可选API, PLUGIN
parameters:            # 设置限流的参数,我们仅针对客户端IP进行限流, 客户端IP从系统变量`CaClientIp`中获取
  ClientIp: "System:CaClientIp"
rules:
  - name: whitelist    # 白名单策略, 当客户端IP符合条件时,不执行限流
    condition: "$ClientIp in_cidr '58.66.XX.XX/24'"
    limit: -1          # `-1`表示不进行限流
  - name: banList      # 特殊限制策略, 当客户端IP符合条件时,按照`ClientIp`参数执行每天5次的限流
    condition: "$ClientIp in_cidr '63.0.XX.XX' or $ClientIp in_cidr '73.0.XX.XX/24'"  
    byParameters: "ClientIp"
    limit: 5
    period: DAY
  - name: 100perIp     # 默认策略,每个IP,100次/分钟访问
    byParameters: "ClientIp"
    limit: 100
    period: MINUTE     # 周期,支持:SECOND, MINUTE, HOUR, DAY

4.3 防CC攻击配置

在这个例子中,我们配置如何防CC攻击。

  • 每个源IP允许3次/秒钟的调用。

  • 当客户端源IP超出3次/秒钟范围时,访问将屏蔽10秒钟。

---
scope: API             # 限流的作用范围,可选API, PLUGIN
defaultLimit: 3000        # 默认流控值
defaultPeriod: SECOND     # 默认流控周期
defaultRetryAfterBySecond: 60  #默认返回Retry-After标头,它提供建议在下一个请求之前需要等待多长时间
parameters:        # 设置限流的参数,我们仅针对客户端IP进行限流, 客户端IP从系统变量`CaClientIp`中获取
  clientIp: "system:CaClientIp"
rules:
  - name: "每个源IP每秒只能访问3次,一旦触及阈值,屏蔽10秒钟"
    byParameters: "clientIp"
    limit: 3
    period: SECOND
    blockingPeriodBySecond: 10     #仅专享实例生效

5. 相关错误码

错误代码

Http状态码

报错信息

描述

T429ID

429

Throttled by INNER DOMAIN Flow Control, ${Domain} is a test domain, only 1000 requests per day

当使用默认二级域名访问时,限制1000次/天(海外Region及中国香港限制100次/天),请绑定正式域名以解除这个限制。

T429IN

429

Throttled by INSTANCE Flow Control

触发当前实例的流控限制。收到此错误时,请先排查是否已达到当前实例规格的并发上限:调用 DescribeInstances 接口查看返回结果中的 InstanceRpsLimit 字段,确认当前实例规格的 RPS 上限,并结合实际请求量判断是否已达到该上限。若已达到上限,需升级实例规格:前往实例与集群 > 专享实例,找到对应实例,单击升配,选择更高规格的实例。详细操作参见实例变配。升配是变更实例规格(例如从 api.s1.small 升级到 api.s1.medium),不是增加实例数量。

T429GR

429

Throttled by GROUP Flow Control

触发当前分组的流控限制。

T429PA

429

Throttled by API Flow Control

触发插件上的默认API流控。

T429PR

429

Throttled by PLUGIN Flow Control

触发插件的特殊流控。

6. 使用限制

  • 参数定义个数不超过16个。

  • 单个表达式的字符数不超过512个字符。

  • 插件元数据的大小限制为50KB

  • 每个插件中rules最大不超过16条。

  • 每个rule中的byParameters最大不超过3个。

  • 当限流参数的分散度太高时,可能释放掉实际使用数据不高的数据,比如:使用了天级别的源IP流控时,系统存储了过多的流控记录时,会释放掉一部分记录,在Serverless实例下的参数流控插件允许的不同参数个数为1000,在专享实例下的参数流控插件允许不同参数个数为100000