What makes Node.js faster than Java? In a nutshell, it's all about concurrency
strongloop.com
strongloop.com
Node is consistently beaten by multiple Go and Java frameworks across all benchmarks [1], consistently beaten by Scalatra, somewhat inconsistently beaten by the Haskell wai implementation (missing some benchmarks, I suspect wai would continue winning though if they were implemented; also I think those benchmarks are on an older Haskell IO manager). Not only are you choosing a dangerous coding style, you're not even winning the performance you think you are. Node is not faster. And certainly every library for Go, Haskell and Erlang, and probably everything for Scala and Clojure (not 100% sure of their runtime models) is already "async ready", and Java itself probably isn't exactly running short of libraries at this point.
[1]: http://www.techempower.com/benchmarks/#section=data-r8&hw=i7...
However, it is fair to say that when using Java, you have to choose carefully since many API's block on I/O, including those that Java programmers use by default and are most likely to be familiar with.
[1]: http://koajs.com
Remember, Node did not originate a single one of those techniques, despite what it sometimes sounds like. They're rediscovering them from the other communities that tried them, and subsequently discovered that the techniques did not solve their concurrency problems. Watching the Node community has been like watching the greater concurrency community's last 40 years compressed into 4 years; we are right on the verge of the inevitable recognition that these techniques won't save them either (I'm seeing the first traces of this in various blog posts), followed by an eventually dimming of Node's vitality as it slowly becomes clear that Javascript just can't do what Node is asking it to do, at scale. (Can not emphasize the "at scale" enough. Anything works on small cases. Node is good enough to work at medium cases, though the effort starts getting greater distressingly fast, which is only noticed by those who have worked in a saner environment. But it's just not going to work at scale any more than any of the other half-a-dozen virtually identical languages with virtually identical capabilities and virtually identical programmers.)
"Beautiful async code" is where the async is essentially invisible, because everything just is async.
Blocking is a feature. Blocking lets you reason easily, and as Go, Erlang, etc... have proven can be done at breathtaking speed and use all your cores... rather than wrapping your world view around async, use a system that allows you to keep your logic blocking and uses microprocesses to distribute work across a pool of threads. It is freeing to be able to just kick up 300k microprocesses if you need them.
Additionally, the node ecosystem tends to be quantity over quality... many of the available modules are simply more trouble than they are worth... while NPM makes getting them easy, it doesn't make deciding if something is worth using any easier.
"While Java or Node or something else may win a benchmark, no server has the non-blocking ecosystem of Node.js today. Over 50k modules all written in the async style, ready to use. Countless code examples strewn about the web. Lessons and tutorials all using the async style. Debuggers, monitors, loggers, cluster managers, test frameworks and more all expecting your code to be non-blocking async."
is true.
Java has had all of the same async capabilities for many, many years, but nobody uses them because the blocking paradigm is simply easier.
That said, if true scalability is required, I'd suggest living with Akka and the cleaner actors paradigm. However, it's true that eventually you're going to run into the barrier that the vast majority of the java ecosystem is built on blocking io.
(That said, with Java 8, I think we have a real opportunity to change that. I think a parallel "lean java" ecosystem is coming.)
That's exaggeration.
Lots of Java libraries use async and concurrency. Java 7 has NIO.2 which is easy to use. There is also Netty; many projects build upon that.
I'm not here to say Java's ecosystem is richer or better; I'm just saying exaggeration is not useful.
Re: "the vast majority of the java ecosystem" I don't mean to sound dismissive, but lots of languages have code you probably don't want to use based on your preferences or needs. So? Don't use the vast majority of libraries. :) You probably don't anyway.
UPDATE: See also Akka and Clojure's concurrency for useful, popular approaches for the JVM.
http://www.playframework.com/documentation/1.2.7/asynchronou...
Play also dramatically improves Java's general... cruftiness.
Actually, not true in "all" and "ready to use" parts.
I suspect there are enough libraries that, even while exposing supposedly-async API block under the hood. Or require careful handling.
Even core Node libraries are not throughly async. One obvious example is `crypto`, where only I/O stuff (accessing OS entropy pool) is async. Good luck generating a keypair in event loop.
I read it as -- "Node.js doesn't properly support isolated units of concurrency and thus due to being forced to write callbacks inside callbacks that call errbacks for everything, we now have over 50k modules full of callback chains and we call this a GoodThing(tm)".
For example Python's eventlet and gevent are based on greenlet. Greenlet is based underneath on large select/epoll/kqueue/poll loop. So there are callbacks for IO readiness there. However they manage to do some tricks to hide that away behind green threads at the user level. So a user can say: " authorize() ; check_database(); charge_credit_card(); update_database(); send_response()" logic properly for each request for example. Without having to split that logic into a chain of callbacks just because some of them might involve at some point making a socket call.
In the java ecosystem, most of it assumes blocking IO. If you're trying to get out of this mindset, the ecosystem can get in your way -- or at the very least, it's not making your life easier.
For many things, this is fine. If I'm not twitter, I'm trading increased scalability for readability almost every time.
For projects that just need occasional async, I would prefer the grails 2.3 model -- http://grails.org/doc/2.3.0.M1/guide/async.html -- which will get you 95% of the way there in a more readable way. ___
However, I am a bit more charitable toward node. I think this may be a case where there is enough momentum that, as people start hitting the harder problems, engineering solutions will sprout up, and the platform will mature with better patterns turning up (including generators and promises.)
Something I only figured out fairly recently but that shocked me is that Haskell, with its lazy evaluation, you can essentially get asynchronous programs for free, and still write in a synchronous style.
While by default the IO monad is strict (basically makes IO stuff synchronous), there are some non-strict actions that are really easy to use.
Imagine the following program:
Open two ports, and print the first couple of bytes recieved from each port.
In node (at least from the callback-based stuff), at one point you're going to have an inevitable :
while(!done){} //waiting
in Haskell, this program looks roughly like: main = do
socket <- someSocketInitCommand
socket' <- someSocketInitCommand
response <- hGetNonBlocking 1024 socket
response' <- hGetNonBlocking 1024 socket'
print ("1st socket : "++ response ++ "\n second socket:"++response')
Lazy IO in Haskell is what I call blocking on data-dependencies: because of how lazy evaluation works, Haskell is able to keep on going until the very moment you need the result from some async call.It's even crazier that Haskell has the holy grail of async programming : the function that transforms a synchronous function to an asynchronous one.
Instead of having
main = do
x <- a
you simply do main = do
x <- unsafeInterleaveIO a
a becomes asynchronous , and nothing else in your code has to change.(from what I understand unsafeInterleaveIO is called like that because it makes the order of your IO actions a bit uncertain, which is a problem for print statements, but when you're doing async programming this is already the case!)
Laziness makes Haskell crazy neat, and I would really love for lazy features to enter other languages. There are some issues (error handling mainly) but it gives you the best of both worlds, I find.
( I am by no means a Haskell expert, so all this might be wrong, but in my experience things work this way-ish)
foo = do
result <- do_first_thing
do_second_thing result
Kinda sorta roughly desugars into something like this: function foo(cb) { do_first_thing(function(result) { do_second_thing(result, cb); }); }
Synchronous and asynchronous Haskell APIs can have the exact same interface.Futures and actors are quite elegant and simplify reasoning about concurrency.
http://www.techempower.com/benchmarks/#section=data-r8&hw=i7...
NodeJS is far behind with 55% vs PlayFramework 67% on 20-queries test.
That said, I tend to prefer building in NodeJS because it's fast enough for most (unanticipated) use cases.
Concurrency is about doing things in the same time period not necessarily at the exact same time.
If you introduce blocking into an application then to the user it slower, but in terms of computation it could still be faster by some magnitude.
It's like having C block on a network call while having in-browser Javascript concurrently move past it and declaring Javascript faster.
Actually, comparing runtime/platform (Node) to language is completely pointless. Language is, well, only a language, it can't be "faster" or "slower" unless we're talking about coding speed. We have to compare implementations.
And even if we treat Java as a platform, contrary to Node it has ton of highly-varying implementations, so it's still pointless without careful clarifying what one compares. Or they may accidentally find out there's a Java variation with green threads somewhere that may break the whole "look, their ugly threads are slow and our event loops are fast" charm.
The article is just a pure load of non-sense. Highly flammable, though.
It does. But it doesn't have to expose that as callback chains or promises to the whole over-arching infrastructure that sits on top. Concurrency units should be isolated from each other and internally execute whatever their logic is without having to worry about being polluted with callbacks. Then there could be multiple of such concurrency units executing in parallel but that is a the job of a decent VM/runtime/library to handle.
> And at these levels of concurrency, you can’t go creating threads for every connection.
Even something as simple as python gevent can create tens of thousands of green threads without a problem without exposing callback chains for everyone to see.
Erlang VM and something like https://github.com/puniverse/quasar can run with millions of concurrency units so do goroutines and Rust's concurrency units (sorry forgot the name).
> So the whole codepath needs to be non-blocking and async, not just the IO layer.
Quite the opposite. If your whole codepath riddled with callback chains and your project is large now you have a huge headache to deal with.
> This is where Node excels.
If it forces one to use promises/deferreds/futures or nested callbacks, I say it fails.
This allows you to get around some nasty architectural problems you can hit with node, where you must either find a way to manually schedule all of your computation into tiny chunks to avoid latency issues, or face potentially severe costs serializing your data to communicate it between processes. No trolling here, it's really a thing that happens!
People do solve these problems in node, it's just that the "ease" suddenly turns against you, as you must now solve tricky systems problems - such as manually scheduling all of your computation properly - or face potentially unacceptable performance degradation. In these cases the limitations of the platform become your overriding architectural driver - better drivers like logical separation start to take a back seat. It's not pretty - and not necessary in other environments.
Given that you won't encounter these types of problems until later - once you've already built up a large codebase and switching platforms is difficult - I think it's better to start in an environment where you know you have these tools available to you when you need them. Even though I really enjoy programming in node (and I've done a lot of it!), I'm wary of starting anything new there unless I have a good reason. There are a lot of great modules written in node, I just try to keep those components isolated and not let them grow too large.
And socket.io justifies using Node :-)
Moreover, Servlet 3.1 Specification , which is a part of Java EE7, includes JSR-340 Non-blocking I/O. In a typical application , ServletOutputStream and InputStream do read/write in a while loop while holding on to the request thread. This issue is potentially resolved in Servet 3.1 by adding event listeners – ReadListener and WriteListener interfaces. These are then registered using ServletInputStream.setReadListener and ServletOutputStream.setWriteListener. The listeners have callback methods that are invoked when the content is available to be read or can be written without blocking.
The new versions of Glassfish and Tomcat servers already support Servlet 3.1.
So Java already supports async style web applications. The programmers have to brush up their skills.
No, we can't all agree on that. Asynchronous non-blocking might be better in limited scenarios where threads are expensive (memory or cpu or other constraints).
"While Java or Node or something else may win a benchmark, no server has the non-blocking ecosystem of Node.js today. Over 50k modules all written in the async style, ready to use."
Sad to see so much work go into a faulty design. Take a look at this presentation http://www.slideshare.net/e456/tyma-paulmultithreaded1.
For example, I wrote a node script that would run a bunch of compilations of files for custom less and javascript minifacation and other stuff on a large codebase. Node opened so many file connections it would crush the machine and not finish.
A simple bash script ran in about a second.
My point is you should definitely NOT use Node because you think it's faster than Java in every case. In fact, evented everything is a pretty terrible trade off in terms of code quality for performance.
There are so many better/easier/cheaper ways to get a high performance, reliable system without using Node.
Is this even true? There are "57 210" modules in NPM at the moment but many of them are explicitly synchronous
NodeJS does async IO by default,so all nodejs libs do async IO.
My point is , it's not so much about wether ruby or python can have the same capabilities as nodejs they can,it's about wether async libs have an ecosystem to support them or not.
Here we probably see some of the problem. Gevent works in a way that most people don't expect, which is to hack the IO layer itself. You don't need a library to "support" gevent for it to still work within gevent. If the library's "synchronousness" is that it opens sockets and uses them, that Just Works in gevent; every time the library does a "blocking" operation in gevent, gevent replaces it with an entry in some sort of polling loop, and moves to the next eventlet that can do work. I used it to write a highly concurrent program that made a ton of simultaneous XML-RPC calls, and I used gevent + the default "blocking" XML-RPC library from Python's core library. It makes the ecosystem support async, at least for network, timers (sleep), and a few other things.
Gevent has other issues; I don't think it can do the same for disk IO. But especially if you've got a network heavy program, you can just drop gevent in and get perfectly cromulent async.
I think a lot of people don't quite understand this. The Node community's persistent and vocal false belief that "async == visibly event-based structure code" probably isn't helping. But it is also true that gevent is a legitimately weird hack on a language. Cool, but very unusual.
Sounds like a great project to hack in spare time, though.
I've done tests in other cases where NIO had nearly the sustained throughput of the blocking libraries, but had much less jitter. That is the latency through the server was much more consistent with NIO libraries than with the blocking ones. This was in a protocol with few connections but lots of messages per connection.
So blanket statements about the blocking IO vs the NIO libraries being faster require more nuance than that.
Polyglot, async, actor-like concurrent JVM platform.
Last time I checked, event loops and async IO wasn't anything Node had monopoly on. In fact, those are available on every non-toy general purpose platform I remember off my head.
In a typical multi threaded web application scenario, there's usually two main resources floating around: http thread pools, and database connection pools.
Both are typically designed to not scale up too quickly (e.g. wait a bit before adding a new resource) and block when they hit a configured maximum. This is because it is pretty easy for a single web server these days to become a denial-of-service attack on a database, and it's also pretty easy for a single client (especially as the typical home's Internet bandwidth increases) to become a denial-of-service attack on a web server. Sensible defaults should therefore take into account that a web server should be a good actor in an ecosystem, not that a web server should be a requests-per-second speed demon. When I read benchmarks, I tend to believe that they are essentially testing these defaults, because there is rarely discussion of them. A conservatively tuned database connection pool will block earlier in the load test, but I will respect the conservative defaults of the framework in question.
Memory is also crucially important in the sync-vs-async discussion. Once you decouple request state management from a constrained-sized thread pool, you have to predict how much memory each state will consume. Unless you are doing very little work on each request (and the work will go up as you add features), you will consume your web server's memory with request state far before you exhaust its other resources. In a threaded model, the thread overhead itself takes a lot of memory, so request overhead per thread in a threaded model is higher than an async model. But when you're talking about a web application with increasing numbers of features, this becomes less and less the majority of the request.
Here's a sketch of an example. In the typical thread-pool based model, X requests can happen simultaneously based on the configured maximum of handler threads--if more requests come in than can happen at the same time, they go into a queue. This is nice because unless the web application is very simple, it's far easier to predict the memory overhead of http requests in a queue than active simultaneous requests in the application layer, especially because most web servers put maximums on the size of individual http headers. In other words, the memory cost of each http request in the queue is constant, while the memory-per-request-state in the application layer will grow with the number of features that layer on the application.
Of course none of the above has much to do with asynchronicity vs thread-bounded-ness. You can have a web server with a request queue and then a set of asynchronous handlers that feed off the queue. I do have a weak argument for threads in this scenario. In the constant tug-of-war between server resources and request throughput, monitoring becomes very important. In a thread-based-model, it is easy to use operating-system tools to introspect the threads because the operating system knows what they are. In the asynchronous model the process is a heap of undifferentiated ram. In that scenario you need good tooling to predict how well tuned your request state is relative to resources. In the JVM it's pretty easy to do a heap dump and see how much memory each request is taking, I'm not sure if there's an equally convenient scenario in the Javascript runtime(s) Node.js can utilize, but I'm sure there's a way. What I do know, however, is that complexity increases as you add actors and/or callbacks, because request state is now broken into a chain of independent memory consuming entities, as opposed to a single predictable thread stack and references.
In the midst of all the above I tend to go for flexibility, because the needs are situational. Async when you need it, sync when you need it. With sync being the more predictable model for the above reasons. Async is great for socket servers that are fronting a fixed-sized memory store, like memcached, while sync is more predictable (using today's tools) for a user facing web application with non-fixed per-request costs.
Seriously, though, YMMV. The discerning reader will see that I'm not making a fundamental argument for threads or async, because on one level there is no difference between them. Threads are not coupled to CPU cores, so they themselves are floating request state stack waiting to be scheduled by the OS onto a core. Async request state is a further level of application level decoupling where a pool of requests are waiting to be scheduled onto a thread, which in turn will be scheduled onto a CPU. A second difference has nothing to do with sync vs async but with coupling -- a synchronous model implies utilizing a stack that executes one-at-a-time, while an asynchronous model implies message passing (hence the ability for selective parallelism). Both models have pros and cons when it comes to predictability and resource utilization. The separation between the two will probably end up being a historical artifact.
I'm just sketching some things that I think about when reading all these sync vs async benchmarks, because they're kind of like saying that American cars are slower than German cars because of average speeds on the Autobahn vs the 405 in Los Angeles, without a discussion of the posted speed limits, traffic patterns, etc.