上次更新日期:2021 年 3 月 25 日
当我向 Amazon Elasticsearch Service (Amazon ES) 集群提交搜索或写入请求时,请求被拒绝,并收到一条错误消息。为什么会发生这种情况? 简短描述当您在 Elasticsearch 集群中写入或搜索数据时,您可能会收到以下 HTTP 429 错误或 es_rejected_execution_exception 异常:
error":"elastic: Error 429 (Too Many Requests): rejected execution of org.elasticsearch.transport.TransportService$7@b25fff4 on
EsThreadPoolExecutor] "
Reason={"type":"es_rejected_execution_exception","reason":"rejected execution of org.elasticsearch.transport.TcpTransport$RequestHandler@3ad6b683 on EsThreadPoolExecutor]"
以下变量可能会造成 HTTP 429 错误或 es_rejected_execution_exception 异常:
数据节点实例类型和搜索或写入限制 实例指标的高值 活动线程和队列线程发生 HTTP 429 错误的原因可能是在于对向 Elasticsearch 集群发出的搜索和写入请求。拒绝也可能来自集群的单个节点或多个节点。
注意:不同版本的 Amazon ES 使用不同的线程池来处理对 _index API 的调用。Elasticsearch 1.5 和 2.3 版使用索引线程池。Elasticsearch 5.x、6.0 和 6.2 版使用批量线程池。Elasticsearch 6.3 版及更高版本使用写线程池。有关更多信息,请参阅 Elasticsearch 网站上的线程池。
解决方法 数据节点实例类型和搜索或写入限制数据节点实例类型具有固定的虚拟 CPU (vCPU)。将 vCPU 计数代入公式中,以检索节点在进入队列之前可以执行的并发搜索或写入操作。如果活动线程已满,则该线程会溢出到队列并最终被拒绝。有关 vCPU 和节点类型之间关系的更多信息,请参阅 Amazon Elasticsearch Service 定价。
此外,您可以执行的每个节点搜索或每个节点写入次数有限制。此限制基于线程池定义和 Elasticsearch 版本号。有关更多信息,请参阅 Elasticsearch 网站上的线程池。
例如,如果您为 Elasticsearch 集群(版本 7.4)中的五个节点选择了 R5.2xlarge 节点类型,它将有 8 个 vCPU。
使用以下公式计算搜索请求的最大活动线程数:
int ((# of available_processors * 3) / 2) + 1
使用以下公式计算写入请求的最大活动线程数:
int (# of available_processors) + 1
因此,对于一个 R5.2xlarge 节点,您最多可以执行 13 个搜索操作:
(8 VCPUs * 3) / 2 + 1 = 13 operations
对于一个 R5.2xlarge 节点,您最多可以执行 9 个写入操作:
8 VCPUs + 1 = 9 operations
对于具有五个节点的 Elasticsearch 集群,您最多可以执行 65 个搜索操作:
5 nodes * 13 = 65 operations
对于具有五个节点的 Elasticsearch 集群,您最多可以执行 45 个写入 操作:
5 nodes * 9 = 45 operations
实例指标的高值
要对 429 异常情况进行问题排除,请检查 Elasticsearch 集群的以下 Amazon CloudWatch 指标:
IndexingRate:每分钟的索引操作次数。对 _bulk API 的单次调用将添加两个文档并将两个计数更新为四个操作,这些操作可能分布在一个或多个节点上。如果该索引有一个或多个副本,则集群中的其他节点也会共计记录四个索引操作。文档删除不计入 IndexingRate 指标中。 SearchRate:数据节点上所有分区每分钟的搜索请求总数。对 _search API 进行一次调用可能会返回来自很多不同分区的结果。如果一个节点上有五个不同的分区,则该节点将此指标报告为“5”,即使客户端只发出了一个请求。 ThreadpoolWriteQueue:写线程池中列队的任务数。此指标将通知您请求是否因高 CPU 使用量或高索引并发性被拒绝。 ThreadpoolWriteRejected:写线程池中被拒绝的任务数量。 ThreadpoolSearchQueue:搜索线程池中队列的任务数。如果队列大小始终很高,请考虑扩展集群。搜索队列的最大大小为 1000。 ThreadpoolSearchRejected:搜索线程池中被拒绝的任务数。如果此数字持续增长,请考虑扩展集群。注意:列出的线程池指标有助于向您提供有关 IndexingRate 和 SearchRate 的信息。
有关使用 Amazon CloudWatch 监控 Elasticsearch 集群的更多信息,请参阅实例指标。
活动线程和队列线程如果缺少 CPU 或请求并发性高,队列可能会很快填满,从而导致 HTTP 429 错误。要监控队列线程,请检查 Amazon CloudWatch 中的 ThreadpoolSearchQueue 和 ThreadpoolWriteQueue 指标。
要检查活动线程和队列线程是否存在任何搜索被拒绝情况,请使用以下命令:
GET /_cat/thread_pool/search?v&h=id,name,active,queue,rejected,completed
要检查活动线程和队列线程是否存在写入被拒绝情况,请将“search”替代为“write”。输出中的 rejected 和 completed 值是累积节点计数器,它们可以在启动新节点时重置。有关更多信息,请参阅 Elasticsearch 网站上 cat thread pool API 中的带有显式列的示例部分。
注意:每个节点上的批量队列可以容纳 50 到 200 个请求,具体取决于您使用的 Elasticsearch 版本。队列已满时,将拒绝新请求。有关更多信息,请参阅 Elasticsearch 网站上的线程池。
搜索和写入被拒绝的示例错误搜索被拒绝
搜索被拒绝错误表示活动线程繁忙,并且队列达到最大任务数。因此,您的搜索请求可能会被拒绝。您可以配置 Elasticsearch 日志,以便在搜索慢速日志中显示这些错误消息。
注意:为避免额外的开销,请将慢速日志阈值设置为很大的值。例如,如果您的大多数查询需要花费 11 秒,而阈值为“10”,则 Amazon ES 将需要额外的时间来写入日志。您可以通过将慢速日志阈值设置为 20 秒来避免这种开销。然后,只记录一小部分较慢的查询(花费时间超过 11 秒)。
将 Elasticsearch 集群配置为将搜索慢速日志推送到 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 异常表示您的队列已满,任何新请求都将被拒绝。当对 Elasticsearch 集群的请求数超过批量队列大小 (threadpool.bulk.queue_size) 时,会发生此批量队列错误。每个节点上的批量队列可以容纳 50 到 200 个请求,具体取决于您使用的 Elasticsearch 版本。
您可以配置 Elasticsearch 日志,以便在索引慢速日志中显示这些错误消息。
注意:为避免额外的开销,请将慢速日志阈值设置为很大的值。例如,如果您的大多数查询需要花费 11 秒,而阈值为“10”,则 Amazon ES 将需要额外的时间来写入日志。您可以通过将慢速日志阈值设置为 20 秒来避免这种开销。然后,只记录一小部分较慢的查询(花费时间超过 11 秒)。
将 Elasticsearch 集群配置为将搜索慢速日志推送到 Amazon CloudWatch 后,为慢速日志生成设置特定阈值。要为慢速日志生成设置特定阈值,请使用以下 HTTP POST 调用:
curl -XPUT http://<your domain’s endpoint>/index/_settings -d '{"index.indexing.slowlog.threshold.query.<level>":"10s"}'
写入拒绝最佳实践
以下是减少写入拒绝的一些最佳实践:
当文档生成索引速度更快时,写队列的容量不太可能用尽。 根据您的工作负载和期望的性能调整批量大小。有关更多信息,请参阅 Elasticsearch 网站上的调整索引速度。 在应用程序逻辑中添加指数重试逻辑。指数重试逻辑可确保自动重试失败的请求。注意:如果您的 Elasticsearch 集群持续遇到较高的并发请求,则指数重试逻辑将无法帮助解决 429 错误。在流量突然或偶尔出现峰值时,采用此最佳实践。 如果您正在从 Logstash 中提取数据,请调整工作线程计数和批量大小。最佳实践是将批量大小设置为 3 – 5MB 之间。
有关索引性能调整的更多信息,请参阅如何提高我的 Amazon Elasticsearch Service 集群上的索引性能?
搜索拒绝最佳实践下面是减少搜索拒绝的一些最佳实践:
切换到更大的实例类型。Elasticsearch 在很大程度上依赖文件系统缓存来获得更快的搜索结果。对于搜索请求,每个节点上线程池中的线程数等于以下值:int((# of available_processors * 3) / 2) + 1。切换到具有更多 vCPU 的实例,以获取更多线程来处理搜索请求。 为某个给定的索引或具有合理阈值的所有索引启用搜索慢速日志。查看哪些查询需要更长的时间才能执行并为查询实施搜索性能策略。有关更多信息,请参阅 Elasticsearch 网站上的适合初学者的 Elasticsearch 搜索问题排查或高级调整:查找和修复慢速 Elasticsearch 查询。