Before I start this post let me be very clear and precise “I am not advising you to leave NodeJS or shift to Java [PERIOD!!!]”.
I’ve been in this debate and there is a misunderstanding among my geek friends that NodeJS is the future and blah blah blah… I totally love Javascript (No bragging I have a history of being Javascript expert and I’ve been writing some love for JS too); there is no doubt about the beauty of closures, and the prototype styled programming. But when it comes to have Javascript as back-end, its totally a different story.
I find it pretty amusing when people are doing benchmarks of some solid technology stack to NodeJS, and declaring NodeJS to be the fastest thing on earth (just Google NodeJS vs *anything that comes to your mind* and you’ll find results like this, this, and what not). Beyond any doubt NodeJS model is worth attention, but will I use it in my production environment? I doubt that. I’ve worked on NodeJS on real serious basis; and experience was pretty bad. I had to write a complete HTTP client library with Multipart support (Today known as Reston) so that I can send files to Amazon S3 and few other REST services (at that time there was no existing library with HTTP Multipart support, HTTPS had issues and it was all really frustrating for me), to summarize it I have to say following things to my audience:
Enough of my experience lets proceed to benchmarks. I have a typical commodity machine (3GB RAM, Dual Core processor) and as ground rules I will be doing straight forward benchmarks of Java NIO receiving a HTTP request, and responding hello world to it; same applies for NodeJS.
NodeJS code is pretty straight forward. I’ve used Node version 0.4.9. Notice that it relies on the typical ‘http’ module, which in turn relies on ‘net’, ‘stream’ etc. all of them are NodeJS libraries (nothing special from me) and they rely on JIT of V8 (accept the C parts) for speedy execution.
Now for Java I took NIO of Java and selector channels to achieve the same effect as NodeJS (single thread event dispatch). Code as expected is a little longer since I had to write the looping part too, but results are worth the experience. I’ve tried to put everything into a single file as much as I can, so code is not modular/production-ready at all! Here are the two files Runner.java and core.SocketSelectorCore.java. I’ve used HashMaps, String split, indexOf etc. and done basic HTTP header parsing of the request to simulate a normal request flow (read, parse, respond cycle). I’ve used pretty inefficient methods, but they are only there to make things worst for Java.
So launching NodeJS with “node test.js” and running Apache Benchmark (ab -c 1000 -n 100000) 3 times with concurrency level of 1000 yields [detailed dump] an average of almost 4 to 5 K requests per second.
Now before putting the custom written Java NIO event based system on trial; I would like to mention few things. Java is a beast, you get so many options on how to tune the JVM ranging from garbage collection to heap sizes (Checkout Java documentation in-case you are interested). So for my scenario, I used following flags to run my JVM “java -server -XX:+PrintCompilation -XX:+UseConcMarkSweepGC Runner”. Notice I’ve used verbose mode for JIT compilation, so that I can know when JVM is warmed up and I can take my benchmark samples; plus I changed the GC method (I tried different methods, but I liked this one the most). After the JVM warmed up (Google it n00bs) and running same Apache Benchmarks [detailed dump], Java was able to manage 8 to 8.5 K requests per second.
I tried different Heap Sizes and played around with other parameters; results were interesting. I was always above 6K requests per second on my machine. Lowering the concurrency (-c 100) takes figures as high as 11K. If you notice closely I was shipping more bytes per request (as compared to NodeJS), but that didn’t hurt Java and even with my really stupid approach for storing headers I was able to make it this far. Having these results at hand I also played around with JRuby for syntactic awesomeness and wrote a throw away code (Complete replica of Java code). And with a pretty rough code and a minor different flags passed to JRuby, I was again able to manage 4 - 4.5 K requests per second.
So question now remains is why did I do this, and whats the take away? I think answers are pretty clear. I personally love Javascript and NodeJS but I won’t take the argument NodeJS can do X that language Y can’t do. I believe comparing Java or PHP or some X to NodeJS is a stupid buzz that appeared recently. JIT of Java is pretty much state of art, and Google guys are putting in a great effort to bring V8 up-to mark. Frameworks like Netty NIO and Mina have been sitting out there for long time, but have been ignored due to Java’s weird syntax, memory hunger or steep learning curve reasons (I am just saying). Having said all that I’ve just busted the myth, “NodeJS can handle more connections due to its async style, and it enforces you to write code in callback(async) style; thus you write better code”. My answer is pretty simple “Write the core part in Java, wrap it in the JRuby or Scala beauty; and you have a much better way of expressing event driven system”.
EDIT: September 2nd 2011
Well I’ve been busy with work lately and seems like I had a nuclear melt down; and before I knew it the whole reactor exploded! In my previous post Node on Nails (I just realized I am good in making titles like these), just to purse the curiosity I tried to create a basic Java based NIO HTTP system and see the numbers with Node. Here is what I think reactions concluded for me (Will be helpful to you and me when writing a blog post):
Although I was busy at work, but the exploding hatred called me to address the issue; don’t worry I will still be doing more work on it as I get more time.
Edit: 6-Sep 2011
I’ve done some more benchmarks with a full fledged framework. If you have objections on this benchmark try new ones out.
Design by Simon Fletcher. Powered by Tumblr.
© Copyright 2010