2013-12-23 41 views
0

背景: 随着并发线程数量的增加,我们注意到性能下降,同时从ExecutionResult中检索数据。我们的生产应用程序有200个工作线程,在嵌入模式下使用Neo4j 2.0.0社区。例如以毫秒为单位。如何提高Neo4j 2.0 cypher/ExecutionResult在重负载下的性能?

  1. 主题:1,Cypher支架时间:0,萃取时间:188
  2. 主题:10,Cypher支架时间:1,萃取时间:188
  3. 主题:50,Cypher支架时间:1,萃取时间: 2481
  4. 主题:100,Cypher支架时间:1,萃取时间:程序4466

样本输出(滤波结果为线程1):

2013-12-23 14:39:31,137 [main] INFO net.ahm.graph.CypherLab - >>>>>>>>>>>>>>>>>>>>>>>>>>>>> NUMBER OF PARALLEL CYPHER EXECUTIONS: 1 
2013-12-23 14:39:31,137 [main] INFO net.ahm.graph.CypherLab - >>>> STARTED GRAPHDB 
2013-12-23 14:39:39,203 [main] INFO net.ahm.graph.CypherLab - >>>> CREATED NODES 
2013-12-23 14:39:43,510 [main] INFO net.ahm.graph.CypherLab - >>>> WARMED UP 
2013-12-23 14:39:43,510 [pool-1-thread-1] INFO net.ahm.graph.CypherLab - >>>> CYPHER TOOK: 0 m-secs 
2013-12-23 14:39:43,698 [pool-1-thread-1] INFO net.ahm.graph.CypherLab - >>>> GETTING RESULTS TOOK: 188 m-secs 
2013-12-23 14:39:43,698 [pool-1-thread-1] INFO net.ahm.graph.CypherLab - >>>> CYPHER RETURNED ROWS: 50000 
2013-12-23 14:39:43,698 [Thread-4] INFO net.ahm.graph.CypherLab - ### GRAPHDB SHUTDOWNHOOK INVOKED !!! 



2013-12-23 14:40:10,470 [main] INFO net.ahm.graph.CypherLab - >>>>>>>>>>>>>>>>>>>>>>>>>>>>> NUMBER OF PARALLEL CYPHER EXECUTIONS: 10 
... 
2013-12-23 14:40:23,985 [pool-1-thread-1] INFO net.ahm.graph.CypherLab - >>>> CYPHER TOOK: 1 m-secs 
2013-12-23 14:40:25,219 [pool-1-thread-1] INFO net.ahm.graph.CypherLab - >>>> GETTING RESULTS TOOK: 188 m-secs 
2013-12-23 14:40:25,219 [pool-1-thread-1] INFO net.ahm.graph.CypherLab - >>>> CYPHER RETURNED ROWS: 50000 
2013-12-23 14:40:25,234 [Thread-4] INFO net.ahm.graph.CypherLab - ### GRAPHDB SHUTDOWNHOOK INVOKED !!! 


2013-12-23 14:41:28,850 [main] INFO net.ahm.graph.CypherLab - >>>>>>>>>>>>>>>>>>>>>>>>>>>>> NUMBER OF PARALLEL CYPHER EXECUTIONS: 50 
... 
2013-12-23 14:41:41,781 [pool-1-thread-1] INFO net.ahm.graph.CypherLab - >>>> CYPHER TOOK: 1 m-secs 
2013-12-23 14:41:45,720 [pool-1-thread-1] INFO net.ahm.graph.CypherLab - >>>> GETTING RESULTS TOOK: 2481 m-secs 
2013-12-23 14:41:45,720 [pool-1-thread-1] INFO net.ahm.graph.CypherLab - >>>> CYPHER RETURNED ROWS: 50000 
2013-12-23 14:41:46,855 [Thread-4] INFO net.ahm.graph.CypherLab - ### GRAPHDB SHUTDOWNHOOK INVOKED !!! 


2013-12-23 14:44:09,267 [main] INFO net.ahm.graph.CypherLab - >>>>>>>>>>>>>>>>>>>>>>>>>>>>> NUMBER OF PARALLEL CYPHER EXECUTIONS: 100 
... 
2013-12-23 14:44:22,077 [pool-1-thread-1] INFO net.ahm.graph.CypherLab - >>>> CYPHER TOOK: 1 m-secs 
2013-12-23 14:44:30,915 [pool-1-thread-1] INFO net.ahm.graph.CypherLab - >>>> GETTING RESULTS TOOK: 4466 m-secs 
2013-12-23 14:44:30,915 [pool-1-thread-1] INFO net.ahm.graph.CypherLab - >>>> CYPHER RETURNED ROWS: 50000 
2013-12-23 14:44:31,680 [Thread-4] INFO net.ahm.graph.CypherLab - ### GRAPHDB SHUTDOWNHOOK INVOKED !!! 

测试程序:

package net.ahm.graph; 

import java.io.File; 
import java.util.Map; 
import java.util.concurrent.CountDownLatch; 
import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 
import java.util.concurrent.TimeUnit; 

import org.apache.log4j.Logger; 
import org.neo4j.cypher.javacompat.ExecutionEngine; 
import org.neo4j.cypher.javacompat.ExecutionResult; 
import org.neo4j.graphdb.DynamicLabel; 
import org.neo4j.graphdb.GraphDatabaseService; 
import org.neo4j.graphdb.Node; 
import org.neo4j.graphdb.RelationshipType; 
import org.neo4j.graphdb.Transaction; 
import org.neo4j.graphdb.factory.GraphDatabaseFactory; 
import org.neo4j.graphdb.factory.GraphDatabaseSettings; 
import org.neo4j.graphdb.schema.IndexDefinition; 
import org.neo4j.graphdb.schema.Schema; 
import org.neo4j.kernel.impl.util.FileUtils; 
import org.neo4j.kernel.impl.util.StringLogger; 

public class CypherLab { 
    private static final Logger LOG = Logger.getLogger(CypherLab.class); 
    private final static int CONCURRENCY = 100; 

    public static void main(String[] args) throws Exception { 
     FileUtils.deleteRecursively(new File("graphdb")); 
     final GraphDatabaseService graphDb = new GraphDatabaseFactory().newEmbeddedDatabaseBuilder("graphdb") 
       .setConfig(GraphDatabaseSettings.use_memory_mapped_buffers, "true").setConfig(GraphDatabaseSettings.cache_type, "strong") 
       .newGraphDatabase(); 
     registerShutdownHook(graphDb); 
     LOG.info(">>>>>>>>>>>>>>>>>>>>>>>>>>>>> NUMBER OF PARALLEL CYPHER EXECUTIONS: " + CONCURRENCY); 
     LOG.info(">>>> STARTED GRAPHDB"); 
     createIndex("Parent", "name", graphDb); 
     createIndex("Child", "name", graphDb); 
     try (Transaction tx = graphDb.beginTx()) { 
      Node parent = graphDb.createNode(DynamicLabel.label("Parent")); 
      parent.setProperty("name", "parent"); 
      for (int i = 0; i < 50000; i++) { 
       Node child = graphDb.createNode(DynamicLabel.label("Child")); 
       child.setProperty("name", "child" + i); 
       parent.createRelationshipTo(child, RelationshipTypes.PARENT_CHILD); 
      } 
      tx.success(); 
     } 
     LOG.info(">>>> CREATED NODES"); 
     final ExecutionEngine engine = new ExecutionEngine(graphDb, StringLogger.SYSTEM); 
     for (int i = 0; i < 10; i++) { 
      try (Transaction tx = graphDb.beginTx()) { 
       ExecutionResult result = engine.execute("match (n:Parent)-[:PARENT_CHILD]->(m:Child) return n.name, m.name"); 
       for (Map<String, Object> row : result) { 
        assert ((String) row.get("n.name") != null); 
        assert ((String) row.get("m.name") != null); 
       } 
       tx.success(); 
      } 
     } 
     LOG.info(">>>> WARMED UP"); 
     ExecutorService es = Executors.newFixedThreadPool(CONCURRENCY); 
     final CountDownLatch cdl = new CountDownLatch(CONCURRENCY); 
     for (int i = 0; i < CONCURRENCY; i++) { 
      es.execute(new Runnable() { 
       @Override 
       public void run() { 
        try (Transaction tx = graphDb.beginTx()) { 
         long time = System.currentTimeMillis(); 
         ExecutionResult result = engine.execute("match (n:Parent)-[:PARENT_CHILD]->(m:Child) return n.name, m.name"); 
         LOG.info(">>>> CYPHER TOOK: " + (System.currentTimeMillis() - time) + " m-secs"); 
         int count = 0; 
         time = System.currentTimeMillis(); 
         for (Map<String, Object> row : result) { 
          assert ((String) row.get("n.name") != null); 
          assert ((String) row.get("m.name") != null); 
          count++; 
         } 
         LOG.info(">>>> GETTING RESULTS TOOK: " + (System.currentTimeMillis() - time) + " m-secs"); 
         tx.success(); 
         LOG.info(">>>> CYPHER RETURNED ROWS: " + count); 
        } catch (Throwable t) { 
         LOG.error(t); 
        } finally { 
         cdl.countDown(); 
        } 
       } 
      }); 
     } 
     cdl.await(); 
     es.shutdown(); 
    } 

    private static void createIndex(String label, String propertyName, GraphDatabaseService graphDb) { 
     IndexDefinition indexDefinition; 
     try (Transaction tx = graphDb.beginTx()) { 
      Schema schema = graphDb.schema(); 
      indexDefinition = schema.indexFor(DynamicLabel.label(label)).on(propertyName).create(); 
      tx.success(); 
     } 
     try (Transaction tx = graphDb.beginTx()) { 
      Schema schema = graphDb.schema(); 
      schema.awaitIndexOnline(indexDefinition, 10, TimeUnit.SECONDS); 
      tx.success(); 
     } 
    } 

    private static void registerShutdownHook(final GraphDatabaseService graphDb) { 
     Runtime.getRuntime().addShutdownHook(new Thread() { 
      @Override 
      public void run() { 
       LOG.info("### GRAPHDB SHUTDOWNHOOK INVOKED !!!"); 
       graphDb.shutdown(); 
      } 
     }); 
    } 

    private enum RelationshipTypes implements RelationshipType { 
     PARENT_CHILD 
    } 
} 
+0

对于200个线程,通过执行所花费的时间是高达4秒钟,然后从ExecutionResult获取的东西花费的时间为10秒。是否有我缺少的线程特定调优参数? –

+1

感谢您回报,这是一个内部同步问题,我们在下一个版本中解决这个问题。 –

+0

嘿迈克尔你知道你让我的圣诞节值得回复。你们是最棒的 !!保持这个令人难以置信的工作! –

回答

1

应该会更好时,这commit is merged in。它将作为2.0.1的一部分发布。 还有一些其他的较小的阻塞点。

你可以尝试限制你的web服务器线程的核心次数(或#核心* 2)?看看是否有帮助?

我的理解是,热身后,并在缓存中拥有热数据集,它只是CPU绑定,而不是读取的I/O限制。所以你让CPU和工作人员挨饿太多。

如果我运行8个100核测试我得到这些分布用于执行查询和取50k的结果:

  • 8线程:500毫秒50%百分位数和90%650ms
  • 100个线程:2600毫秒的50个%百分位数,并在6000ms

代码90%和详细直方图:https://gist.github.com/jexp/a164f6cf9686b8125872

+0

击败它谢谢!任何在2.0.1上的eta? –