SteelBridgeLabs / neo4j-gremlin-bolt

Apache License 2.0
0 stars 1 forks source link

Is Graph Object Thread Safe and How is Session managed #69

Closed jinfenglin closed 6 years ago

jinfenglin commented 6 years ago

In my applicaiton I created too much graph object to connect to the database which lead to a thread lock on server side. So I want to control the number of grpah object. My question is:

  1. Can same graph object shared in multiple thread? I read some article https://stackoverflow.com/questions/28269763/is-com-tinkerpop-blueprints-graph-object-thread-safe which indicating the answer is implementation oriented.
  2. How does each graph instance mange its session, does it have a connection pool?
rjbaucells commented 6 years ago

Yes, the same graph instance can be shared in multiple threads but this is not the recommended way it should be used. while a single graph instance is shared across multiple threads a single transaction instance is created for each thread, so a commit performed on one thread only commits the data that was modified in that thread.

The recommended way to use the library is using the Unit-of-Work pattern. Keep the graph instance life as short as possible, something like:

    // create graph instance
    try (Graph graph = new Neo4JGraph(driver, vertexIdProvider, edgeIdProvider)) {
        // begin transaction
        try (Transaction transaction = graph.tx()) {
            // use Graph API to create, update and delete Vertices and Edges

            // commit transaction
            transaction.commit();
        }
    }

You can control the connection pool size at the time of creating the underlying driver instance, see the driver documentation for more information.

I am using this Tinkerpop implementation in a large Microservices architecture using the Unit-of-Work pattern without any problems, keep the life of the graph and transaction instances as short as possible and configure the connection pool your application needs at the time of creating the driver instance.

jinfenglin commented 6 years ago

Thanks for your response. I realize I close the connections of the graph but not closing the transactions which leads to the thread locks. As you suggested, using the Unit-of-Work pattern solve the issues. Though the application works, when I check the neo4j debug.log, I notice some error message as follow. I guess it is driver related, have you ever met this.

2017-12-29 21:41:48.738+0000 ERROR [o.n.b.t.SocketTransportHandler] Fatal error occurred when handling a client connection: An existing connection was forcibly closed by the remote host An existing connection was forcibly closed by the remote host java.io.IOException: An existing connection was forcibly closed by the remote host at sun.nio.ch.SocketDispatcher.read0(Native Method) at sun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:43) at sun.nio.ch.IOUtil.readIntoNativeBuffer(IOUtil.java:223) at sun.nio.ch.IOUtil.read(IOUtil.java:192) at sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:380) at io.netty.buffer.PooledUnsafeDirectByteBuf.setBytes(PooledUnsafeDirectByteBuf.java:288) at io.netty.buffer.AbstractByteBuf.writeBytes(AbstractByteBuf.java:1106) at io.netty.channel.socket.nio.NioSocketChannel.doReadBytes(NioSocketChannel.java:343) at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:123) at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:645) at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:580) at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:497) at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:459) at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:858) at java.lang.Thread.run(Thread.java:748)

rjbaucells commented 6 years ago

No, I have not seen those messages before. You should check on the Neo4J issues for similar problems since I do not think are related to the way we are using the driver on this project.

michaelahlers commented 6 years ago

@rjbaucells, helpful tip; I've run into a similar problem using Gremlin Scala, and this seems to do the trick. Being new to Neo (and these libraries), I wonder at the performance implications. How significant are the costs here? Also—from your example—are both parts strictly necessary? Is it creating a new Graph instance for each interaction with the database, or reusing one and making all writes transactional (which, by itself, appears to make the graph consistent across threads)?