0
votes

I'm working about a identity, access and role management with SDN 2.1.0-RC4 without AspectJ. This system aims to manage around 120 000 users and data is extracted from legacy and HR applications. I have from 500 to 30000 updates/day, so performance can be a touchy subject I ran some workbenches with default configuration.

I used a very simple and stupid way. A simple class

@TypeAlias("event")
@NodeEntity
public class Event {

    @GraphId
    private Long graphId;

    @Indexed
    private Long eventId;

    @RelatedTo(type="PREVIOUS_EVENT", direction=Direction.OUTGOING)
    private Event previous;

    private String description;

        /.../
}

and I insert data one by one

    /.../
/**
 * 
 */
public void loadAllData() {

    Event root = new Event();
    root.setEventId(0L);
    root.setDescription("ROOT");

    repository.save(root);
    Event curr = root;


    for(int i = 0; i< SIZE; i ++) {
        curr = insertData(curr, i );
    }
}


/**
 * @param curr
 * @param i
 * @return
 */
public Event insertData(Event curr, int i) {
    long lastTime = System.currentTimeMillis();
    Event evt = new Event();
    evt.setEventId(curr.getEventId()+1);
    evt.setPrevious(curr);
    evt.setDescription("event #"+i);
    repository.save(evt);
    curr = evt;
    delais[i] = System.currentTimeMillis() - lastTime;
    return curr;

}
/.../

I test several by overloading theses methods

1) use of @Transactional

@Override
@Transactional
public Event insertData(Event curr, int i) {
    return super.insertData(curr, i);
}

2) Use of neo4j transaction

@Override
public void loadAllData() {
    gds = getContext().getBean(GraphDatabaseService.class);
    super.loadAllData();
}       

@Override
public Event insertData(Event curr, int i) {                
    Transaction tx = gds.beginTx();
    try {
        curr = super.insertData(curr, i);
        tx.success();
    } catch(Exception e) {
        tx.failure();
    } finally {
        tx.finish();
    }
    return curr;

}

I know benchmark are a trolling subject and it's not what I want. So take theses values as they are: a stupid test

Results

JtaTransactionManager

Mean 47,20 ms, Min 21,00 ms, Max 425,00 ms

GraphDatabaseService

Mean 0,90 ms, Min 0,00 ms, Max 3,00 ms

JtaTransactionManager is very slow compared to native neo4j server, but JtaTransactionManager is a global and ambitious TransactionManager.

My purpose is how to lighten or create a custom transactionManager with less ambition, a smaller scope but still using the @Transactional annotation ?

May be I've missed something ?

Thanks you for any potential help or advice.

PS: my configuration

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:neo4j="http://www.springframework.org/schema/data/neo4j"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
        http://www.springframework.org/schema/data/neo4j http://www.springframework.org/schema/data/neo4j/spring-neo4j-2.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">

    <context:annotation-config/>
    <context:spring-configured/>

    <context:component-scan base-package="benchmark"/>

    <neo4j:repositories base-package="benchmark.repository"/>
    <neo4j:config graphDatabaseService="graphDatabaseService"/>


    <bean id="graphDatabaseService" class="org.neo4j.kernel.EmbeddedGraphDatabase" 
      destroy-method="shutdown">
         <constructor-arg index="0" value="data/benchmark.db" />
    </bean>


</beans>

Marc DeXeT

1

1 Answers

2
votes

You use two totally differen transaction batch sizes.

With the "neo4j" TM you use a global tx scope that includes all your updates in one go (aka several hundred or thousand ops).

With the @Transactional you have a tx scope of a single operation. So the overhead of the transaction is added for each operation instead just once.

So try to put an @Transactional around the loadAllData() instead.

Also for a higher insertion speed try to use template.createRelationshipBetween(...., duplicate=true) instead of evt.setPrevious(curr). So you skip all the delta detection and duplication elimination.