使用集群限流插件(aliyun-qos)

更新时间:
复制为 MD 格式

aliyun-qos插件是阿里云Elasticsearch(ES)团队自研的集群级别读写限流插件,当上游业务无法进行流量控制时,可通过aliyun-qos插件按业务优先级对指定索引进行适当降级,将流量控制在合适范围内,保护ES服务的稳定性。

注意事项

  • aliyun-qos为预装插件,限流功能默认关闭,不支持卸载。该插件用于保护集群稳定性,不会精准计量读写流量。

  • 插件版本:使用前需确保aliyun-qos插件已升级至最新版本。登录Kibana控制台,执行GET /_cat/plugins?v查看插件版本。

    插件版本格式为<实例版本>_ali<内部版本号>,例如7.10.0_ali1.6.0.28.17.0_ali2.2.0.4.1。如果插件版本不是最新,请参考以下方式升级:

    • 7.10版本实例:在控制台将内核升级到1.6.0版本,具体操作请参见升级版本

    • 7.10版本实例:联系阿里云Elasticsearch技术工程师升级插件版本。升级后需手动重启Elasticsearch实例生效。

    • 插件版本低于rc4时,会出现unsupported_operation_exception报错。当前仅支持升级6.7.0及以上版本实例的aliyun-qos插件,低于6.7.0版本的实例需要先升级到6.7.0及以上。

评估阈值

为了不影响读写请求的执行效率,aliyun-qos插件在集群级别进行限流,但不会对所有节点的读写流量进行严格精准的计量,实际流量可能有所偏差。使用前可参考以下规则评估限流阈值:

  • 查询请求

    查询请求的限流阈值 = 客户端查询请求到达Elasticsearch的端到端QPS(Query Per Second)

    端到端QPS仅指查询请求到达协调节点的每秒请求数。

  • 写入请求

    写入请求的限流阈值计算规则与查询请求类似,但需要根据副本数进行调整。

    例如集群中有2个数据节点、1个索引,该索引有1shard、1个副本,每次写入10 MB大小的数据。因为存在副本,所以每个数据节点上都会被写入10 MB大小的数据。另外X-Pack自身的Monitor、Audit、Watcher等任务同样会占用写入流量,设置阈值时需要预留出该部分的大小。

开启限流功能

aliyun-qos插件的限流功能默认关闭,使用时需要先开启。不同版本的aliyun-qos插件,开启限流功能的命令不同。

7.10最新版本

其他版本

PUT _cluster/settings
{
  "persistent": {
    "apack.qos.limiter.enabled": true
  }
}
PUT _cluster/settings
{
  "persistent": {
    "apack.qos.ratelimit.enabled": "true"
  }
}

关闭限流功能

通过将限流参数设置为falsenull关闭限流功能。不同版本的命令如下。

关闭限流方式

7.10最新版本

其他版本

将限流参数设置为false

PUT _cluster/settings
{
  "persistent": {
    "apack.qos.limiter.enabled": false
  }
}
PUT _cluster/settings
{
  "persistent": {
    "apack.qos.ratelimit.enabled": "false"
  }
}

将限流参数设置为null

PUT _cluster/settings
{
  "persistent": {
    "apack.qos.limiter.enabled": null
  }
}
PUT _cluster/settings
{
  "persistent": {
    "apack.qos.ratelimit.enabled": null
  }
}

配置限流器(7.10最新版本)

以下配置限流器的内容仅适用于7.10版本实例的aliyun-qos插件。

限流器由两部分组成:limiters定义和tags定义。通过tags定义资源限制范围,通过limiters定义具体的限流类型和限流阈值。限流器分为普通限流器和默认限流器,将tags设置为可实现默认限流器。例如默认每个shard的流量,默认每个应用的QPS等。当请求超过限流值后,Elasticsearch会拒绝之后发送的请求。

PUT /_qos/limiter/<limiterName>
{
  "limiters": {
     ${action}.${limiter_type}:${threshold}
  },
  "tags": {
    ${tagName}:${tagValue}
  },
  "priority":0,
  "params":{
      "watchMode":true
  }
}

参数

说明

可选值

action

限流的action,用于限制不同类型的请求。

  • write:doc写入请求,包含indexcreate。

  • update:doc更新请求。

  • delete:doc删除请求。

  • search:查询请求。

  • search_shards:查询索引的shard总数请求。

limiter_type

限流类型。支持三大类:速率、并发度、单请求限制。

  • rate:速率,只支持整数。

  • qps:查询速率,只支持整数。

  • tps:写入速率,只支持整数。

  • throughput:吞吐量,只支持actionwrite、updatedelete。支持的单位包含GB、MB、KB等,最大支持2 GB。

  • thread_count:请求并发度,一个请求为一个并发。

  • concurrent_count:请求并发度,按照请求中的具体操作计算并发数。例如设置search_shards.concurrent_count:20,表示允许最大20shard并发查询。

  • max_per_request:单请求中包含的某类操作个数的上限。例如设置update.max_per_request:10,表示一个写入请求最多有10update。

  • max_size_per_request:单请求个数上限。只支持actionwrite、updatedelete。

threshold

限流阈值。

int范围内的整数,>=-1。

部分类型支持带单位的字符串,具体请参见limiter_type说明。

tagName

tag名称。

  • node:当前节点名。

  • is_master:当前节点是否为master,对应的tag值为truefalse。

  • index:索引名。如果有多个索引名,则为数组。如果传入的是别名,此处也是解析的实际索引名。仅IndicesRequest的子类请求才有此tag。

  • shard:shard名,即index[id],例如test[0]。仅ReplicationRequest的子类请求才有此tag。

  • index_in_url:URL中的index字符串,如果传入的是别名,则此处就是别名。仅IndicesRequest的子类请求才有此tag。

tagValue

tag的值。

字符串,可为数组。如果为数组,则对应tag匹配数组中任意一个value即可。支持精确匹配、模糊匹配和任意值,例如:

  • 精确匹配:"abc"

  • 模糊匹配:"ab*"

  • 任意值:"**"

    如果为任意值,则为默认限流器。即对这个tag的任意值都会生成一个精确的限流器,例如设置为index:"**",search.tps:1,表示默认情况下,限制每个索引的search速率为1,而不是总search速率为1。

priority

优先级。

int整数,默认为0。

优先级越大,排序越靠前。当有多个默认限流器同时命中时,只有优先级最大的默认限流器会生效。

params

高级参数。

watchMode:是否启用观察模式,支持truefalse(默认)。如果为true,Elasticsearch只会在metric中记录拒绝数,但不会实际限流。可通过API查看指标监控信息,用于提前验证限流效果,避免由于配置错误造成错误的限流。API的详细信息,请参见常见问题。

配置限流器示例

设置查询QPS限流

通过设置查询索引每秒请求次数,限制协调节点每秒接收的查询请求数。当每秒接收的查询请求数超过限流值后,Elasticsearch会拒绝接收请求。

indexindex_patterns的值支持完整索引名称和索引通配符。不同版本的命令如下。

操作

7.10最新版本

其他版本

设置单个索引的查询QPS限流

PUT /_qos/limiter/<limiterName>
{
  "limiters": {
    "search.qps": "1000"
  },
  "tags": {
    "index": "twitter"
  }
}
PUT /_qos/_ratelimit/<limiterName>
{
  "search.index_patterns": "twitter",
  "search.max_queries_per_sec": 1000
}

设置指定名称前缀的索引的查询QPS限流

PUT /_qos/limiter/<limiterName>
{
  "limiters": {
    "search.qps": "1000"
  },
  "tags": {
    "index": "nginx-log-*"
  }
}
PUT /_qos/_ratelimit/<limiterName>
{
  "search.index_patterns": "nginx-log-*",
  "search.max_queries_per_sec": 1000
}

设置任意索引的查询QPS限流

PUT /_qos/limiter/<limiterName>
{
  "limiters": {
    "search.qps": "1000"
  },
  "tags": {
    "index": "**"
  }
}

index:**表示任意索引。例如集群中有3个索引A、B、C,则这3个索引的限流值都为1000。

不支持。

设置所有索引的查询总QPS限流

PUT /_qos/limiter/<limiterName>
{
  "limiters": {
    "search.qps": "1000"
  },
  "tags": {
    "index": "*"
  }
}

index:*表示任意索引。例如集群中有3个索引A、B、C,则这3个索引的总限流值为1000。效果等同于不设置这个tags。

PUT /_qos/_ratelimit/<limiterName>
{
  "search.index_patterns": "*",
  "search.max_queries_per_sec": 1000
}

可以定义多条不同的规则,只要请求命中任意一条规则,就会触发限流。

当查询QPS超过限流值时,系统会返回如下报错信息。不同版本的报错信息不同:

  • 7.10最新版本

    {
      "error": {
        "root_cause": [
          {
            "type": "status_exception",
            "reason": "search blocked, limited by [<limiterName>][search.qps](<limiterId>) threshold:[x]"
          }
        ],
        "type": "status_exception",
        "reason": "search blocked, limited by [<limiterName>][search.qps](<limiterId>) threshold:[x]"
      },
      "status": 429
    }
  • 其他版本

    {
      "error": {
        "root_cause": [
          {
            "type": "rate_limited_exception",
            "reason": "request indices:data/read/search rejected, limited by [l1:t*:1.0]"
          }
        ],
        "type": "rate_limited_exception",
        "reason": "request indices:data/read/search rejected, limited by [l1:t*:1.0]"
      },
      "status": 429
    }

设置写入TPS限流

通过设置写入索引每秒请求次数,限制协调节点每秒接收的写入请求数。当每秒接收的写入请求数超过限流值后,Elasticsearch会拒绝接收请求。

indexindex_patterns的值支持完整索引名称和索引通配符。不同版本的命令如下。

7.10最新版本

其他版本

PUT /_qos/limiter/<limiterName>
{
  "limiters": {
    "write.tps": "100000"
  },
  "tags": {
    "index": "nginx-log-*"
  }
}

不支持

设置Bulk每秒写入大小限流

通过设置Bulk每秒写入的总字节数,限制协调节点每秒接收的写入字节数。当每秒接收的写入字节数超过限流值后,Elasticsearch会拒绝接收请求。

indexindex_patterns的值支持完整索引名称和索引通配符。不同版本的命令如下。

7.10最新版本

其他版本

PUT /_qos/limiter/<limiterName>
{
  "limiters": {
    "write.throughput": "100MB"
  },
  "tags": {
    "index": "nginx-log-*"
  }
}
PUT /_qos/_ratelimit/<limiterName>
{
  "bulk.index_patterns": "nginx-log-*",
  "bulk.max_throughput_in_bytes": 104857600
}

可以定义多条不同的规则,只要请求命中任意一条规则,就会触发限流。

设置Bulk单次请求大小限流

通过设置Bulk单次请求的最大值,限制协调节点接收单次请求的写入字节数。当单次请求的写入字节数超过限流值后,Elasticsearch会拒绝接收请求。

indexindex_patterns的值支持完整索引名称和索引通配符。不同版本的命令如下。

7.10最新版本

其他版本

PUT /_qos/limiter/<limiterName>
{
  "limiters": {
    "write.max_size_per_request": "1000"
  },
  "tags": {
    "index": "nginx-log-*"
  }
}
PUT /_qos/_ratelimit/<limiterName>
{
  "bulk.index_patterns": "nginx-log-*",
  "bulk.max_request_size_in_bytes": 1000
}

可以定义多条不同的规则,只要请求命中任意一条规则,就会触发限流。

当单次请求的写入字节数超过限流值时,系统会返回如下报错信息。不同版本的报错信息不同:

  • 7.10最新版本

    {
      "error" : {
        "root_cause" : [
          {
            "type" : "status_exception",
            "reason" : "write_size blocked, limited by [<limiterName>][write.max_size_per_request](<limiterId>) threshold:[x] try acquire [x]"
          }
        ],
        "type" : "status_exception",
        "reason" : "write_size blocked, limited by [<limiterName>][write.max_size_per_request](<limiterId>) threshold:[x] try acquire [x]"
      },
      "status" : 400
    }
  • 其他版本

    {
      "error": {
        "root_cause": [
          {
            "type": "rate_limited_exception",
            "reason": "request indices:data/write/bulk rejected, limited by [b2:ByteSizePreSeconds:992.0]"
          }
        ],
        "type": "rate_limited_exception",
        "reason": "request indices:data/write/bulk rejected, limited by [b2:ByteSizePreSeconds:992.0]"
      },
      "status": 413
    }

设置查询shard并发个数限流

通过设置并发查询shard数来降低集群压力。indexindex_patterns的值支持完整索引名称和索引通配符。不同版本的命令如下。

7.10最新版本

其他版本

PUT /_qos/limiter/<limiterName>
{
  "limiters": {
    "search_shards.concurrent_count": "10"
  },
  "tags": {
    "index": "nginx-log-*"
  }
}

不支持

可以定义多条不同的规则,只要请求命中任意一条规则,就会触发限流。

设置多个限流器配置

支持同时设置限流器的多个配置。indexindex_patterns的值支持完整索引名称和索引通配符。不同版本的命令如下。

7.10最新版本

其他版本

PUT /_qos/limiter/<limiterName>
{
  "limiters": {
    "search.qps": "1000",
    "write.tps": "100000",
    "write.throughput": "1000000",
    "write.max_size_per_request": "1000",
    "search_shards.concurrent_count": "10"
  },
  "tags": {
    "index": "nginx-log-*"
  }
}

不支持

可以定义多条不同的规则,只要请求命中任意一条规则,就会触发限流。

获取限流配置

不同版本获取限流配置的命令如下。

操作

7.10最新版本

其他版本

获取所有限流配置

GET /_qos/limiter
GET /_qos/_ratelimit

获取单个指定的限流配置

GET /_qos/limiter/<limiterName>
GET /_qos/_ratelimit/<limiterName>

获取多个指定的限流配置。多个限流器之间用英文逗号(,)分隔,不支持通配符。

GET /_qos/limiter/<limiterName1,limiterName2>
GET /_qos/_ratelimit/<limiterName1,limiterName2>

删除限流配置

不同版本删除限流配置的命令如下。

操作

7.10最新版本

其他版本

删除单个指定的限流配置

DELETE /_qos/limiter/<limiterName>
DELETE /_qos/_ratelimit/<limiterName>

删除多个指定的限流配置。多个限流器之间用英文逗号(,)分隔,不支持通配符。

DELETE /_qos/limiter/<limiterName1,limiterName2>
DELETE /_qos/_ratelimit/<limiterName1,limiterName2>

常见问题

Q:如何获取限流相关的指标监控信息?

A:可以通过以下API获取:

  • 获取当前指标数据

    • 获取当前所有指标数据

      GET /_qos/limiter/nodes/stats
    • 获取当前指定{node}指标数据

      GET /_qos/limiter/nodes/{nodeId}/stats
    • 获取当前指定{node}和{limiter}指标数据

      GET /_qos/limiter/nodes/{nodeId}/stats/{limiterIds}
  • 获取历史指标数据

    • 获取历史所有指标数据

      GET /_qos/limiter/metric
    • 获取历史指定{limiter}指标数据

      GET /_qos/limiter/metric/{limiterId}

升级插件注意事项

在将aliyun-qos插件升级至最新版本时,需注意以下事项:

  • 由于新旧版本实现机制不同,升级过程中可能出现短暂限流失效,待master节点上的限流插件升级完成后会自动恢复。

  • 在新旧数据转换过程中,可能存在部分限流器转换失败的情况。如果转换失败,需要执行如下命令重新转换。如果执行命令后报错,可多次重试,直至hasErrorfalse。

    POST /_qos/limiter/ops/upgrade

    如果执行以上命令返回错误信息(如unknown action),说明实例中没有旧版限流器,可忽略。