使用 neo4j rest http 客户端的性能问题
Performance issues using neo4j rest http client
用 Apache http 客户端替换 neo4j-jdbc 客户端后遇到了这个问题。
当 运行 只有 1k 并发用户执行我们的查询时,似乎我们仍然有问题。
这是我们使用客户端的方式:
https://gist.github.com/IdanFridman/1989b600a0a032329a5e
这就是我们使用该 rest-client 执行查询的方式:
https://gist.github.com/IdanFridman/22637f95ba696f498b6c
分析后,我们看到上述糟糕的性能结果:
每个请求平均延迟 3 秒。
我们应该放弃 neo4j 吗?我们对表演结果感到绝望
谢谢。
所以,你想要更多的并发请求?让我们探索一下我们可以在这里做什么。
查询
首先 - 检查查询是否执行得足够好。 Copy-paste 它是 Neo4j 浏览器,在前面添加 PROFILE
并探索输出。
您的查询可能比您预期的要多得多。这导致等待时间很长,因为 Neo4j 仍在执行查询。
客户
HttpClient 配置
您正在使用 PoolingHttpClientConnectionManager
。
来自文档:
PoolingHttpClientConnectionManager maintains a maximum limit of connections on a per route basis and in total. Per default this implementation will create no more than 2 concurrent connections per given route and no more 20 connections in total.
所以,我们应该增加限制。示例:
PoolingHttpClientConnectionManager cnnMgr = new PoolingHttpClientConnectionManager();
cnnMgr.setMaxTotal(500);
cnnMgr.setDefaultMaxPerRoute(100);
HttpRequest
尝试在请求中添加keep-aliveheader。示例:
request.setHeader("Connection", "keep-alive");
那么,您应该始终尽快关闭您的回复。您不应该依赖这样一个事实,即当您筋疲力尽时,流内容连接已关闭。代码:
try(CloseableHttpResponse response = httpClient.execute(request)) {
// do stuff with response here
// close response when try-with-resource block ends
}
记住 - 您从服务器事务端点接收的内容流回客户端。
return createResultSet(new JsonObject(IOUtils.toString(response.getEntity().getContent())));
因此,在此代码示例中,我们一直在等待,直到我们检索到完整的响应,然后才开始序列化。
在你的情况下,你正在寻找这样的东西:
String rawJsonResult = null;
try(CloseableHttpResponse response = httpClient.execute(request);) {
rawJsonResult = IOUtils.toString(response.getEntity().getContent());
} catch (IOException e) {
throw new RuntimeException(e);
}
return createResultSet(new JsonObject(rawJsonResult));
通过这样做,我们确保我们正在检索结果并在任何序列化发生之前关闭连接。这将为其他并发连接释放资源。
服务器
Neo4j 使用 Jetty 作为 Web 服务器。 Jetty 由 BlockingQueue
支持。这意味着可以处理 x
数量的并发 HTTP 请求。这个 x
是 queue 尺寸。如果我们有超过 x
数量的并发请求,那么在 queue.
中等待空闲点
幸运的是,您可以 configure queue 有多大。您对此感兴趣 属性:
org.neo4j.server.webserver.maxthreads=200
注意:这里没有魔法。默认情况下,Neo4j 使用 cpuCount * 4
数量的 Web 服务器线程。增加这个数字会导致更多的并发请求,但每个请求都会变慢。
Linux
你应该check this。每个 TCP 连接都是一个单独的文件。通常,大多数 Linux 发行版的默认值为 1024
。你需要增加它。你可以试试 40000
.
记住 - 这不仅适用于服务器,也适用于客户端。您不仅要接收连接,而且,您还需要打开它们。
一般说明
你不应该那么相信分析结果。我们在发出 HTTP 请求时等待是完全可以的。总的来说 - 这是沟通中最昂贵的部分。
此外,您应该确保您的客户端和服务器位于同一本地网络中。通过 public 网络发出请求会显着降低性能。
最后一个 - 并发 HTTP 连接数有上限。超过此限制会使数据库几乎无响应(类似于任何其他 Web 应用程序)。您可能需要考虑水平扩展(Neo4j 集群)才能发出更多并发请求。
祝你好运!
用 Apache http 客户端替换 neo4j-jdbc 客户端后遇到了这个问题。
当 运行 只有 1k 并发用户执行我们的查询时,似乎我们仍然有问题。
这是我们使用客户端的方式: https://gist.github.com/IdanFridman/1989b600a0a032329a5e
这就是我们使用该 rest-client 执行查询的方式:
https://gist.github.com/IdanFridman/22637f95ba696f498b6c
分析后,我们看到上述糟糕的性能结果:
每个请求平均延迟 3 秒。
我们应该放弃 neo4j 吗?我们对表演结果感到绝望
谢谢。
所以,你想要更多的并发请求?让我们探索一下我们可以在这里做什么。
查询
首先 - 检查查询是否执行得足够好。 Copy-paste 它是 Neo4j 浏览器,在前面添加 PROFILE
并探索输出。
您的查询可能比您预期的要多得多。这导致等待时间很长,因为 Neo4j 仍在执行查询。
客户
HttpClient 配置
您正在使用 PoolingHttpClientConnectionManager
。
来自文档:
PoolingHttpClientConnectionManager maintains a maximum limit of connections on a per route basis and in total. Per default this implementation will create no more than 2 concurrent connections per given route and no more 20 connections in total.
所以,我们应该增加限制。示例:
PoolingHttpClientConnectionManager cnnMgr = new PoolingHttpClientConnectionManager();
cnnMgr.setMaxTotal(500);
cnnMgr.setDefaultMaxPerRoute(100);
HttpRequest
尝试在请求中添加keep-aliveheader。示例:
request.setHeader("Connection", "keep-alive");
那么,您应该始终尽快关闭您的回复。您不应该依赖这样一个事实,即当您筋疲力尽时,流内容连接已关闭。代码:
try(CloseableHttpResponse response = httpClient.execute(request)) {
// do stuff with response here
// close response when try-with-resource block ends
}
记住 - 您从服务器事务端点接收的内容流回客户端。
return createResultSet(new JsonObject(IOUtils.toString(response.getEntity().getContent())));
因此,在此代码示例中,我们一直在等待,直到我们检索到完整的响应,然后才开始序列化。
在你的情况下,你正在寻找这样的东西:
String rawJsonResult = null;
try(CloseableHttpResponse response = httpClient.execute(request);) {
rawJsonResult = IOUtils.toString(response.getEntity().getContent());
} catch (IOException e) {
throw new RuntimeException(e);
}
return createResultSet(new JsonObject(rawJsonResult));
通过这样做,我们确保我们正在检索结果并在任何序列化发生之前关闭连接。这将为其他并发连接释放资源。
服务器
Neo4j 使用 Jetty 作为 Web 服务器。 Jetty 由 BlockingQueue
支持。这意味着可以处理 x
数量的并发 HTTP 请求。这个 x
是 queue 尺寸。如果我们有超过 x
数量的并发请求,那么在 queue.
幸运的是,您可以 configure queue 有多大。您对此感兴趣 属性:
org.neo4j.server.webserver.maxthreads=200
注意:这里没有魔法。默认情况下,Neo4j 使用 cpuCount * 4
数量的 Web 服务器线程。增加这个数字会导致更多的并发请求,但每个请求都会变慢。
Linux
你应该check this。每个 TCP 连接都是一个单独的文件。通常,大多数 Linux 发行版的默认值为 1024
。你需要增加它。你可以试试 40000
.
记住 - 这不仅适用于服务器,也适用于客户端。您不仅要接收连接,而且,您还需要打开它们。
一般说明
你不应该那么相信分析结果。我们在发出 HTTP 请求时等待是完全可以的。总的来说 - 这是沟通中最昂贵的部分。
此外,您应该确保您的客户端和服务器位于同一本地网络中。通过 public 网络发出请求会显着降低性能。
最后一个 - 并发 HTTP 连接数有上限。超过此限制会使数据库几乎无响应(类似于任何其他 Web 应用程序)。您可能需要考虑水平扩展(Neo4j 集群)才能发出更多并发请求。
祝你好运!