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

aliyun-qos插件是阿里云Elasticsearch团队自研的插件,能够提高集群的稳定性。该插件能够实现集群级别的读写限流,在关键时刻对指定索引降级,将流量控制在合适范围内。例如当上游业务无法进行流量控制时,尤其对于读请求业务,可根据aliyun-qos插件设置的规则,按照业务的优先级进行适当的降级,来保护Elasticsearch服务的稳定性。

前提条件

已升级插件版本至最新版本。

您可以登录目标Elasticsearch实例的Kibana控制台,通过GET /_cat/plugins?v命令查看该插件的版本。查看插件版本

7.10版本Elasticsearch实例的插件最新版本为7.10.0_ali1.6.0.2,其他版本为<实例版本>-rc4。如果插件版本不是最新版本,您可通过以下方式处理:

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

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

说明
  • 使用aliyun-qos插件时,如果版本低于rc4,会出现unsupported_operation_exception的报错。

  • 当前仅支持升级6.7.0及以上版本的Elasticsearch实例中的aliyun-qos插件,低于6.7.0版本的Elasticsearch实例需要先将实例版本升级到6.7.0及以上,再升级插件版本。

注意事项

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

    说明

    使用aliyun-qos插件前,您可以在插件配置页面查看是否已安装该插件。如果未安装,可参见安装或卸载系统默认插件进行安装。插件安装成功后不可卸载。

  • 在将aliyun-qos插件升级至最新版本时,您需要注意:

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

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

      POST /_qos/limiter/ops/upgrade
      说明

      如果执行以上命令长时间不返回,则说明实例中没有旧版限流器,可忽略。

评估阈值

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

  • 查询请求

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

    说明

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

  • 写入请求

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

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

开启限流功能

aliyun-qos插件的限流功能默认关闭,使用时需要先开启该功能。不同版本的aliyun-qos插件,开启限流功能的代码不同,具体如下。

说明

本文中的命令均可在Kibana控制台上执行,详情请参见登录Kibana控制台

7.10最新版本

其他版本

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

关闭限流功能

您可以通过将限流参数设置为false或null,关闭限流功能。aliyun-qos插件的版本不同,关闭限流功能的代码不同,具体如下。

关闭限流方式

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写入请求,包含index和create。

  • update:doc更新请求。

  • delete:doc删除请求

  • search:查询请求。

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

limiter_type

限流类型。支持三大类:

  • 速率

  • 并发度

  • 单请求限制

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

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

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

  • throughput:吞吐量,只支持action为write、update和delete。支持的单位包含GB、MB、KB等,最大支持2 GB。

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

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

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

  • max_size_per_request:单请求个数上限。只支持action为write、update和delete。

threshold

限流阈值。

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

说明

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

tagName

tag名称。

  • node:当前节点名。

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

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

配置限流器示例

设置查询QPS限流

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

index和index_patterns的值支持完整索引名称和索引通配符。aliyun-qos插件的版本不同,设置查询QPS限流的代码不同,具体如下。

操作

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
}
说明

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

当您在客户端或Kibana控制台上执行数据查询操作时,如果查询QPS超过您设置的限流值,系统会显示如下报错信息。请根据报错信息适当减少查询QPS限流。aliyun-qos插件的版本不同,显示的报错信息不同,具体如下:

  • 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会拒绝接收请求。

index和index_patterns的值支持完整索引名称和索引通配符。aliyun-qos插件的版本不同,设置写入TPS限流的代码不同,具体如下。

7.10最新版本

其他版本

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

不支持

设置Bulk每秒写入大小限流

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

index和index_patterns的值支持完整索引名称和索引通配符。aliyun-qos插件的版本不同,设置Bulk每秒写入大小限流的代码不同,具体如下。

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会拒绝接收请求。

index和index_patterns的值支持完整索引名称和索引通配符。aliyun-qos插件的版本不同,设置Bulk单次请求大小限流的代码不同,具体如下。

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
}
说明

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

当您在客户端或Kibana控制台上执行数据写入操作时,如果单次请求的写入字节数超过设置的限流值,系统会显示如下报错信息。请根据报错信息适当减少单次请求的写入字节数。aliyun-qos插件的版本不同,显示的报错信息不同,具体如下:

  • 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数,来降低集群压力。index和index_patterns的值支持完整索引名称和索引通配符。aliyun-qos插件的版本不同,设置查询shard并发个数限流的代码不同,具体如下。

7.10最新版本

其他版本

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

不支持

说明

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

设置多个限流器配置

支持同时设置限流器的多个配置。index和index_patterns的值支持完整索引名称和索引通配符。aliyun-qos插件的版本不同,设置多个限流器配置的代码不同,具体如下。

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-*"
  }
}

不支持

说明

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

获取限流配置

aliyun-qos插件的版本不同,获取限流配置的代码不同,具体如下。

操作

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>

删除限流配置

aliyun-qos插件的版本不同,删除限流配置的代码不同,具体如下。

操作

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}