如何解决 Amazon OpenSearch Service 中的搜索或写入被拒绝问题?

上次更新时间: 2021 年 10 月 19 日

当我向 Amazon OpenSearch Service 集群提交搜索或写入请求时,请求已被拒绝。为什么会发生这种情况?

简短描述

当您在 OpenSearch Service 集群中写入或搜索数据时,您可能会收到以下 HTTP 429 错误或 es_rejected_execution_exception

error":"elastic: Error 429 (Too Many Requests): rejected execution of org.elasticsearch.transport.TransportService$7@b25fff4 on 
EsThreadPoolExecutor[bulk, queue capacity = 200, org.elasticsearch.common.util.concurrent.EsThreadPoolExecutor@768d4a66[Running, 
pool size = 2, active threads = 2, queued tasks = 200, completed tasks = 820898]] [type=es_rejected_execution_exception]"

Reason={"type":"es_rejected_execution_exception","reason":"rejected execution of org.elasticsearch.transport.TcpTransport$RequestHandler@3ad6b683 on EsThreadPoolExecutor[search, queue capacity = 1000, org.elasticsearch.common.util.concurrent.EsThreadPoolExecutor@bef81a5[Running, pool size = 25, active threads = 23, queued tasks = 1000, completed tasks = 440066695]]"

以下变量可能会造成 HTTP 429 错误或 es_rejected_execution_exception 异常:

  • 数据节点实例类型和搜索或写入限制
  • 实例指标的高值
  • 活动线程和队列线程

发生 HTTP 429 错误的原因可能是在于对向集群发出的搜索写入请求。拒绝也可能来自集群的单个节点或多个节点。

注意:不同版本的 Elasticsearch 使用不同的线程池来处理对 _index API 的调用。Elasticsearch 1.5 和 2.3 版使用索引线程池。Elasticsearch 5.x、6.0 和 6.2 版使用批量线程池。Elasticsearch 6.3 版及更高版本使用写线程池。有关更多信息,请参阅 Elasticsearch 网站上的线程池

解决方法

数据节点实例类型和搜索或写入限制

数据节点实例类型具有固定的虚拟 CPU (vCPUs)。将 vCPU 计数代入公式中,以检索节点在进入队列之前可以执行的并发搜索写入操作。如果活动线程已满,则该线程会溢出到队列并最终被拒绝。有关 vCPU 和节点类型之间关系的更多信息,请参阅 Amazon OpenSearch Service 定价

此外,您可以执行的每个节点搜索或每个节点写入次数有限制。此限制基于线程池定义和 Elasticsearch 版本号。有关更多信息,请参阅 Elasticsearch 网站上的线程池

例如,如果您为 Elasticsearch 集群(版本 7.4)中的五个节点选择了 R5.2xlarge 节点类型,则节点将有 8 个 vCPU。

使用以下公式计算搜索请求的最大活动线程数:

int ((# of available_processors * 3) / 2) + 1

使用以下公式计算写入请求的最大活动线程数:

int (# of available_processors)

因此,对于一个 R5.2xlarge 节点,您最多可以执行 13 个搜索操作:

(8 VCPUs * 3) / 2 + 1 = 13 operations

对于一个 R5.2xlarge 节点,您最多可以执行 8 个写入操作:

8 VCPUs = 8 operations

对于具有五个节点的 OpenSearch Service 集群,您最多可以执行 65 个搜索操作:

5 nodes * 13 = 65 operations

对于具有五个节点的 OpenSearch Service 集群,您最多可以执行 40 个写入操作:

5 nodes * 8 = 40 operations

实例指标的高值

要对 429 异常情况进行问题排除,请检查集群的以下 Amazon CloudWatch 指标:

  • IndexingRate:每分钟的索引操作次数。对 _bulk API 的单次调用将添加两个文档并将两个计数更新为四个操作,这些操作可能分布在一个或多个节点上。如果该索引有一个或多个副本,则集群中的其他节点也会共计记录四个索引操作。文档删除不计入 IndexingRate 指标中。
  • SearchRate:数据节点上所有分区每分钟的搜索请求总数。对 _search API 进行一次调用可能会返回来自很多不同分区的结果。如果一个节点上有五个不同的分区,则该节点将此指标报告为 "5",即使客户端只发出了一个请求。
  • CoordinatingWriteRejected:协调节点上发生的拒绝总数。这些拒绝是由 OpenSearch Service 启动以来累积的索引压力造成的。
  • PrimaryWriteRejected:主分区上发生的拒绝总数。这些拒绝是由于自上次 OpenSearch Service 启动以来累积的索引压力造成的。
  • ReplicaWriteRejected:由于索引压力而在副本分区上发生的拒绝总数。这些拒绝是由于自上次 OpenSearch Service 启动以来累积的索引压力造成的。
  • ThreadpoolWriteQueue:写线程池中列队的任务数。此指标将通知您请求是否因高 CPU 使用量或高索引并发性被拒绝。
  • ThreadpoolWriteRejected:写入线程池中被拒绝的任务数量。
    注意:在 OpenSearch 服务 7.9 版本中,原定设置写入队列大小从 200 增加到 10,000。因此,该指标不再是 OpenSearch 服务拒绝的唯一指标。使用 CoordinatingWriteRejectedPrimaryWriteRejectedReplicaWriteRejected 指标来监控版本 7.9 及更高版本中的拒绝情况。有关更多信息,请参阅 UltraWarm 指标
  • ThreadpoolSearchQueue:搜索线程池中队列的任务数。如果队列大小始终很高,请考虑扩展集群。搜索队列的最大大小为 1000。
  • ThreadpoolSearchRejected:搜索线程池中被拒绝的任务数。如果此数字持续增长,请考虑扩展集群。

注意:列出的线程池指标有助于向您提供有关 IndexingRateSearchRate 的信息。

有关使用 Amazon CloudWatch 监控 OpenSearch Service 集群的更多信息,请参阅实例指标

活动线程和队列线程

如果缺少 CPU 或请求并发性高,队列可能会很快填满,从而导致 HTTP 429 错误。要监控队列线程,请检查 Amazon CloudWatch 中的 ThreadpoolSearchQueueThreadpoolWriteQueue 指标。

要检查活动线程和队列线程是否存在任何搜索被拒绝情况,请使用以下命令:

GET /_cat/thread_pool/search?v&h=id,name,active,queue,rejected,completed

要检查活动线程和队列线程是否存在写入被拒绝情况,请将“search”替代为“write”。输出中的 rejectedcompleted 值是累积节点计数器,它们可以在启动新节点时重置。有关更多信息,请参阅 Elasticsearch 网站上 cat thread pool API 中的带有显式列的示例部分。

注意:每个节点上的批量队列可以容纳 50 到 200 个请求,具体取决于您使用的 Elasticsearch 版本。队列已满时,将拒绝新请求。有关更多信息,请参阅 Elasticsearch 网站上的线程池

搜索和写入被拒绝的示例错误

搜索已被拒绝

搜索被拒绝错误表示活动线程繁忙,并且队列达到最大任务数。因此,您的搜索请求可能会被拒绝。您可以配置 OpenSearch Service 日志,以便在搜索慢速日志中显示这些错误消息。

注意:为避免额外的开销,请将慢速日志阈值设置为很大的值。例如,如果您的大多数查询需要花费 11 秒,而阈值为“10”,则 OpenSearch Service 将需要额外的时间来写入日志。您可以通过将慢速日志阈值设置为 20 秒来避免这种开销。然后,只记录一小部分较慢的查询(花费时间超过 11 秒)。

将集群配置为将搜索慢速日志推送到 Amazon CloudWatch 后,为慢速日志生成设置特定阈值。您可以使用以下 HTTP POST 调用为慢速日志生成设置特定阈值:

curl -XPUT http://<your domain’s endpoint>/index/_settings -d '{"index.search.slowlog.threshold.query.<level>":"10s"}'

写入被拒绝

写入被拒绝 429 错误消息表示存在批量队列错误。es_rejected_execution_exception[bulk] 异常表示您的队列已满,任何新请求都将被拒绝。当对集群的请求数超过批量队列大小 (threadpool.bulk.queue_size) 时,会发生此批量队列错误。每个节点上的批量队列可以容纳 50 到 200 个请求,具体取决于您使用的 Elasticsearch 版本。

您可以配置 OpenSearch Service 日志,以便在索引慢速日志中显示这些错误消息。

注意:为避免额外的开销,请将慢速日志阈值设置为很大的值。例如,如果您的大多数查询需要花费 11 秒,而阈值为“10”,则 OpenSearch Service 将需要额外的时间来写入日志。您可以通过将慢速日志阈值设置为 20 秒来避免这种开销。然后,只记录一小部分较慢的查询(花费时间超过 11 秒)。

将集群配置为将搜索慢速日志推送到 Amazon CloudWatch 后,为慢速日志生成设置特定阈值。要为慢速日志生成设置特定阈值,请使用以下 HTTP POST 调用:

curl -XPUT http://<your domain’s endpoint>/index/_settings -d '{"index.indexing.slowlog.threshold.query.<level>":"10s"}'

写入拒绝最佳实践

以下是减少写入拒绝的一些最佳实践:

  • 当文档生成索引速度更快时,写队列的容量不太可能用尽。
  • 根据您的工作负载和期望的性能调整批量大小。有关更多信息,请参阅 Elasticsearch 网站上的调整索引速度
  • 在应用程序逻辑中添加指数重试逻辑。指数重试逻辑可确保自动重试失败的请求。
    注意:如果您的集群持续遇到较高的并发请求,则指数重试逻辑将无法帮助解决 429 错误。在流量突然或偶尔出现峰值时,采用此最佳实践。
  • 如果您正在从 Logstash 中提取数据,请调整工作线程计数和批量大小。最佳实践是将批量大小设置为 3 – 5MB 之间。

有关索引性能优化的更多信息,请参阅如何提高我的 Amazon OpenSearch Service 集群上的索引性能?

搜索拒绝最佳实践

下面是减少搜索拒绝的一些最佳实践:

  • 切换到更大的实例类型。OpenSearch Service 在很大程度上依赖文件系统缓存来获得更快的搜索结果。对于搜索请求,每个节点上线程池中的线程数等于以下值:int((# of available_processors * 3) / 2) + 1。切换到具有更多 vCPU 的实例,以获取更多线程来处理搜索请求。
  • 为某个给定的索引或具有合理阈值的所有索引启用搜索慢速日志。检查哪些查询需要更长的时间才能执行并为查询执行搜索性能策略。有关更多信息,请参阅 Elasticsearch 网站上的适合初学者的 Elasticsearch 搜索问题排查高级优化: 查找和修复慢速 Elasticsearch 查询

Amazon OpenSearch Service 是 Amazon Elasticsearch Service 的后继者。


这篇文章对您有帮助吗?


您是否需要账单或技术支持?