在广泛查询ES时,我得到了
Failed to execute [org.elasticsearch.action.search.SearchRequest@59e634e2] lastShard [true]
org.elasticsearch.common.util.concurrent.EsRejectedExecutionException: rejected execution (queue capacity 1000) on org.elasticsearch.search.
action.SearchServiceTransportAction$23@75bd024b
at org.elasticsearch.common.util.concurrent.EsAbortPolicy.rejectedExecution(EsAbortPolicy.java:62)
at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:823)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1369)
at org.elasticsearch.common.util.concurrent.EsThreadPoolExecutor.execute(EsThreadPoolExecutor.java:79)
at org.elasticsearch.search.action.SearchServiceTransportAction.execute(SearchServiceTransportAction.java:551)
at org.elasticsearch.search.action.SearchServiceTransportAction.sendExecuteQuery(SearchServiceTransportAction.java:228)
at org.elasticsearch.action.search.type.TransportSearchQueryThenFetchAction$AsyncAction.sendExecuteFirstPhase(TransportSearchQueryThenFetchAction.java:83)
定期。
我的计划现在是pause
查询请求,直到队列加载低于x
。您可以在客户端查询其stats
client.admin().cluster().threadPool().stats().iterator();
但由于我的客户端不是数据节点(我认为这就是原因),我得到queue=0
返回,而服务器节点抛出上述错误。
我知道为什么会被抛出,我知道如何更新设置,但这只是推迟了这个错误,并创建了其他人......
如何询问群集节点队列负载是什么?
PS:我正在使用Java Api
除非另有说明,否则我尝试过的,没有要求的结果,空行表示另一次尝试
//Nodes stats
final NodesStatsResponse nodesStatsResponse = client.admin().cluster().prepareNodesStats().execute().actionGet();
final NodeStats nodeStats = nodesStatsResponse.getNodes()[0];
final String nodeId = nodeStats.getNode().getId(); // need this later on
// same as before, but with explicit NodesStatsRequest (with id)
final NodesStatsResponse response = client.admin().cluster().nodesStats(new NodesStatsRequest(nodeId)).actionGet();
final NodeStats[] nodeStats2 = response.getNodes();
for (NodeStats nodeStats3 : nodeStats2) {
Stats stats = nodeStats3.getThreadPool().iterator().next();
}
// Cluster?
final ClusterStatsRequest clusterStatsRequest = new ClusterStatsRequestBuilder(client.admin().cluster()).request();
final ClusterStatsResponse clusterStatsResponse = client.admin().cluster().clusterStats(clusterStatsRequest).actionGet();
final ClusterStatsNodes clusterStatsNodes = clusterStatsResponse.getNodesStats();
// Nodes info?
final NodesInfoResponse infoResponse = client.admin().cluster().nodesInfo(new NodesInfoRequest(nodeId)).actionGet();// here
final NodeInfo[] nodeInfos = infoResponse.getNodes();
for (final NodeInfo nodeInfo : nodeInfos) {
final ThreadPoolInfo info = nodeInfo.getThreadPool();
final Iterator<Info> infoIterator = info.iterator();
while (infoIterator.hasNext()) {
final Info realInfo = infoIterator.next();
SizeValue sizeValue = realInfo.getQueueSize();
// is no == null, then (¿happens?, was expecting a nullpointer, but Thread disappeared)
if (sizeValue == null)
continue;
// normal queue size, no load (oddly found 1000 (expected), and one of 200 in one node?)
final long queueSize = sizeValue.getSingles();
}
}
问题是某些进程需要立即调用(例如用户请求),而其他进程可能会等待数据库太忙(后台进程)。最好是,我将一定数量的队列分配给立即请求的进程,另一部分分配给后台进程(但我还没有看到此选项)。
更新
看起来,我没想到,当单独搜索的总量超过1000时(当x分片或x索引除以1000 / x时,单个批量查询可以获得查询重载)搜索次数)。所以膨胀,,,不是一个选项,除非你可以进行single
查询。因此,当您一次定位700个搜索结果时(考虑到上述声明),您需要知道队列中是否有超过300个项目,因为它会丢弃东西。
总结一下:
假设每个呼叫的负载是最大bulkrequest
,因此我无法组合请求。那么,如何在弹性搜索开始抛出上述异常之前开始暂停请求。所以我可以暂停我的应用程序的一部分,但不能停止另一部分?如果我知道队列已填满,比方说,中途,后台进程必须休眠一段时间。我如何知道(近似)队列加载?
答案 0 :(得分:4)
您尝试查看队列使用情况的方式是错误的,因为您没有查看正确的统计信息。
看一下这段代码:
final NodesStatsResponse response = client.admin().cluster().prepareNodesStats().setThreadPool(true).execute().actionGet();
final NodeStats[] nodeStats2 = response.getNodes();
for (NodeStats nodeStats3 : nodeStats2) {
ThreadPoolStats stats = nodeStats3.getThreadPool();
if (stats != null)
for (ThreadPoolStats.Stats threadPoolStat : stats) {
System.out.println("node `" + nodeStats3.getNode().getName() + "`" + " has pool `" + threadPoolStat.getName() + "` with current queue size " + threadPoolStat.getQueue());
}
}
首先,您需要setThreadPool(true)
才能返回线程池统计信息,否则它将是null
。
其次,您需要ThreadPoolStats
而不是ThreadPoolInfo
用于线程池设置。
所以,这是你的第二次尝试,但不完整。您看到的1000
是设置本身(最大队列大小),而不是实际负载。
答案 1 :(得分:0)
批量拒绝
如果您要遇到队列拒绝,很可能会 由批量索引请求引起的。发送很多批量很容易 通过使用并发导入进程向Elasticsearch请求。更多 更好,对吧?
实际上,每个群集都有一定的限制,无法保留 摄入。超过此阈值后,队列将会 快速填满,新的批量将被拒绝。
这是一件好事。队列拒绝是一种有用的形式 压力。他们让您知道您的群集处于最大容量, 这比将数据粘贴到内存中队列要好得多。 增加队列大小不会提高性能;它只是隐藏 问题。如果您的群集每秒只能处理10,000个文档, 队列是100还是10,000,000 - 你的集群并不重要 仍然每秒只能处理10,000个文档。
队列只是隐藏了性能问题并带来了真正的风险 数据丢失。根据定义,坐在队列中的任何东西都不是 已处理。如果节点发生故障,则所有这些请求都将丢失 永远。此外,队列占用了大量内存,但事实并非如此 理想的。
优雅地处理应用程序中的排队要好得多 处理完整队列的背压。当你收到批量 拒绝,您应该采取以下步骤:
暂停导入线程3-5秒。提取被拒绝的操作 从批量响应,因为很可能是许多行动 成功了。批量响应将告诉您哪个成功和 哪些被拒绝了。仅拒绝发送新的批量请求 动作。如果再次遇到拒绝,请从步骤1开始重复。运用 在此过程中,您的代码自然会适应您的群集负载 并自然退缩。
拒绝不是错误:它们只是意味着您应该稍后再试。
特别是这个When you receive bulk rejections, you should take these steps
我不喜欢。我们应该能够正手处理即将到来的问题。