【问题标题】:DSE graph more threads result in slow response timesDSE 图更多线程导致响应时间变慢
【发布时间】:2018-03-12 10:43:05
【问题描述】:

我以前问过这个问题。但是再用一个具体的例子来问。

所以我在我的 Mac 上本地运行了 DSE 图。我有一个最简单的顶点创建,下面是遍历。

g.addV("company").property("id", companyId)
.property("name", "company_" + companyId)
.property(VertexProperty.Cardinality.list, "domainurls", "test.com", "anothertest.com")
.next();

现在我正在使用 Java TinkerPop3 API 进行调用。而且我有一个 DseSession 得到了这种方式。

dseCluster = DseCluster.builder()
        .addContactPoints(contactPoints)
        .withGraphOptions(new GraphOptions().setGraphName("profilex_dev"))
        .build();
dseSession = dseCluster.connect();
DseGraph.traversal(dseSession)

我在多线程应用程序中重复使用 GraphTraversalSource 的这一实例。我的观察,线程数越多,响应时间越慢。

我使用 Java Microbenchmarking Harness 进行了测量,以下大致是我发现的

  • 10 线程 - 6 毫秒
  • 50 线程 - 34 毫秒
  • 200 个线程 - 146 毫秒。

所以我的问题是 - 有没有办法优化它以更快地运行 - 需要设置的任何池选项等。在我的例子中,不仅仅是一个公司的创建和更多的图形突变/查询(大约 10 次这样的遍历),随着线程数量的增加,整体响应时间变得次优。

请注意,上述响应时间也适用于简单的图形查询。因此,随着线程的增加,即使是简单的读取也会变慢。 (当然,当线程数较少时非常好)。

【问题讨论】:

  • 可以添加突变/查询的代码吗?有时性能问题可以在那里解决......
  • 另一个问题 - 你使用的是什么版本的驱动程序?
  • 可能这种方式使用遍历源会让事情变慢,你可以尝试切换到GraphStatements并使用DseGraph.statementFromTraversal()方法,而不是直接迭代遍历,并通过会话执行语句。
  • 如果这没有改变,那么您需要检查来自驱动程序的 inFlight 请求 (docs.datastax.com/en/developer/java-driver-dse/1.5/manual/…)。如果在增加线程数时 inFlight 上升,这意味着最终它是驱动程序无法真正解决的 DseGraph 服务器端性能问题。一种解决方案是在同一遍历中批量插入,例如 g.addV().property().addV().property().....
  • @newkek :抱歉耽搁了,监控飞行中的请求没有帮助。飞行中的请求总是不超过 200 个线程(200 是我正在运行的)并且最大负载 = 1024。请注意,即使我只得到一个顶点 g.V(vertexId),情况也是如此。所以我猜这很可能是客户端配置问题

标签: java tinkerpop3 datastax-enterprise-graph


【解决方案1】:

不确定是否应该将其作为“答案”发布,但格式比在评论中更容易。感谢提供完整的测试类,对调试和实验很有帮助。

一直在查看您的测试实现,我确实注意到随着并发级别的提高,吞吐量有所下降。

我相信您所看到的是您的本地服务器节点最初未被使用以及服务器缓存很冷且不够活跃的副作用。您需要更大的预热阶段,以便您的本地节点能够足够快地开始响应,并查看在更高的并发下单个请求时间不会增加的情况。

我运行了您的测试(仅单会话测试),当我的系统使用率较低时,当我开始您的测试时,结果看起来与您的完全相似。

但是,如果在执行 10 - 20 - 50 个请求的测试之前执行一些额外的测试,如下所示:

    dseVertexQueryPerformance.testSingleSession(3000);
    dseVertexQueryPerformance.testSingleSession(6000);
    dseVertexQueryPerformance.testSingleSession(6000);
    dseVertexQueryPerformance.testSingleSession(6000);
    dseVertexQueryPerformance.testSingleSession(6000);
    dseVertexQueryPerformance.testSingleSession(9000);
    dseVertexQueryPerformance.testSingleSession(9000);
    dseVertexQueryPerformance.testSingleSession(9000);
    dseVertexQueryPerformance.testSingleSession(10);
    dseVertexQueryPerformance.testSingleSession(20);
    dseVertexQueryPerformance.testSingleSession(50);
    dseVertexQueryPerformance.testSingleSession(100);
    dseVertexQueryPerformance.testSingleSession(200);

我最终得到如下结果:

End Test ::SingleSession, Average Time: 2.6, Total execution time: 5.891593 ms
For 10 threads, ::SingleSession took 2.6
End Test ::SingleSession, Average Time: 4.4, Total execution time: 7.830533 ms
For 20 threads, ::SingleSession took 4.4
End Test ::SingleSession, Average Time: 1.86, Total execution time: 20.378055 ms
For 50 threads, ::SingleSession took 1.86
End Test ::SingleSession, Average Time: 1.98, Total execution time: 47.487505 ms
For 100 threads, ::SingleSession took 1.98
End Test ::SingleSession, Average Time: 2.295, Total execution time: 92.793991 ms
For 200 threads, ::SingleSession took 2.295

我们可以有效地看到争用是由于 DSE Graph 或整个系统不够温暖。


现在,回顾我上面提到的那些较长的运行,我观察到在使用连接的遍历源时发生了更多的争用或更多的工作。

我建议不要直接迭代遍历源,而是从遍历中创建GraphStatement,如下所述:https://docs.datastax.com/en/developer/java-driver-dse/1.5/manual/tinkerpop/#data-stax-drivers-execution-compatibility

所以在您的测试中,我将getAVertex(GraphTraversalSource g) 更改为:

public class DSEVertexQueryPerformance {
    ...

    private GraphTraversalSource traversalSource = DseGraph.traversal();

    ....

    public long getAVertex(DseSession dseSession) {
        Instant begin = Instant.now();
        dseSession.executeGraph(DseGraph.statementFromTraversal(
            traversalSource.V(vertexId))
        );
        return Duration.between(begin, Instant.now()).toMillis();
    }

通过更改此方法,我能够从使用当前 g.V().next() 版本的 9000 个请求 (dseVertexQueryPerformance.testSingleSession(9000);) 的总执行时间约为 1900 毫秒,使用statementFromTraversal() 方法。

最后,我还建议使用异步查询执行方法 (DseSession.executeGraphAsync()),因为它可以让您并行化所有请求,而无需在客户端使用线程池,最终将减轻客户端应用程序的压力。

【讨论】:

  • 感谢您的详细回复。不过我确实有一个问题。是否可以预先预热服务器并建立缓存。我将继续查看是否有多个虚拟机。一个预热缓存,另一个 VM 进行常规 10,20,50,100 测试将正常工作
猜你喜欢
  • 1970-01-01
  • 2016-12-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-27
  • 1970-01-01
  • 2015-01-10
相关资源
最近更新 更多