Over a million developers have joined DZone.

It’s Over 9000! Neo4j on WebSockets

DZone's Guide to

It’s Over 9000! Neo4j on WebSockets

· Performance Zone
Free Resource

Container Monitoring and Management eBook: Read about the new realities of containerization.


In the last blog post we managed to run Neo4j at Ludicrous Speed over http using Undertow and get to about 8000 requests per second. If we needed more speed we can scale up the server or we can scale out to multiple servers by switching out the GraphDatabaseFactory and using the HighlyAvailableGraphDatabaseFactory class instead in Neo4j Enterprise Edition.

But can we go faster on a single server without new hardware? Well… yes, if we’re willing to drop http and switch to Web Sockets.

WebSocket is a protocol providing full-duplex communications channels over a single TCP connection…allowing for messages to be passed back and forth while keeping the connection open.

Sounds complicated? It’s not, we can add it to our existing Undertow server with 18 more lines of code. No really:

.addPath("/websocket", websocket(new WebSocketConnectionCallback() {
    public void onConnect(WebSocketHttpExchange exchange, WebSocketChannel channel) {
        channel.getReceiveSetter().set(new AbstractReceiveListener() {
            protected void onFullTextMessage(WebSocketChannel channel, BufferedTextMessage message) {
                String data = message.getData();
                try {
                    List<Map<String, AtomicInteger>> results = getCrossReferences(data);
                    WebSockets.sendBinary(ByteBuffer.wrap(objectMapper.writeValueAsBytes(results)), channel, null);
                } catch (IOException e) {
                    WebSockets.sendText("Error:" + e.toString(), channel, null);

We are adding a “/websocket” endpoint to our existing Undertow server that: 1. sets up a channel 2. performs the CrossReference query we’ve seen before when it receives a message and 3. sends the results back. So let’s test this out. I believe Gatling 2.0 has web socket testing integrated, but I’m still using 1.5.3, so we’ll borrow the Gatling Web Sockets Library from Andrew Duffy. To use it, we’ll just compile it and add it to the lib directory of our performance testing project. Let’s create a new web socket test for this that looks very similar to our previous http test:

class TestCrossReferenceWebSocket extends Simulation {
  val testfile = csv("test-data.txt").circular
  val scn = scenario("Cross Reference via WebSocket")
    .exec(websocket("socket").open("ws://localhost:7474/websocket", "socket_open"))
    .during(30) {
        .sendMessage("""{"cc": "${cc}", "phone": "${phone}", "email": "${email}", "ip": "${ip}" }""",
        .pause(0 milliseconds, 1 milliseconds)

Each simulated user will open a connection to the server, spend 30 seconds reading test data from a file, sending requests to the server, and finally it will close the connection once it’s done. Let’s fire it up and oh my…

Screen Shot 2014-03-09 at 3.34.57 PM

Zoom in on that… 28 thousand requests per second… on my laptop. That’s 3.5 times as many requests as last time, and about 22 times what we started out with. Before you even ask, of course you can go faster still if you switch out JSON for a binary serialization format, but I’ll leave that as an exercise for the reader since there are so many of them. Feel free to fork this project on Github and have a go at it.

If you want to try sending Cypher over Web Sockets in MessagePack, you can also take a look at Michael Hunger‘s Cypher Websocker Endpoint project on Github. If ZeroMQ is more your thing, Nigel Small has his ZeroGraph project.

Take the Chaos Out of Container Monitoring. View the webcast on-demand!


Published at DZone with permission of Max De Marzi, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}