Tuesday, October 4, 2011

Node.js has jumped the shark

I've been trying to understand this whole Node.js thing that's been going on for the past few days. It's taught me a lot about how the Node.js community tries to reason about problems, and perhaps what's the real problem with Node.

It began with a relatively short rant by Ryan Dahl. Ryan talk's about how he's mad at complex software, which is at least an arguable position. I liked his rant, but Ted Dziuba did not.

Ted Dziuba wrote a brilliant troll post which lambasted Ryan and the concept of Node.js in general. I'm a huge fan of Ted's previous trolling, especially his parody TechCrunch site uncov, which trolled TechCrunch before TechCrunch became a parody of itself. Except in the case of uncov, it would be a few years before TechCrunch became a parody itself. With Node.js, the reaction was almost instantaneous.

Ted's argument centered around the problem of doing non-trivial computation within the event loop of a system like Node, and how that would affect the performance of the system. To illustrate this point, he gave an intentionally deoptimized Fibonacci function, along with the boldface caveat "Yes, I know there's a closed form solution. Shouldn't you be in front of a mirror somewhere, figuring out how to introduce yourself to her?"

Reading through the lines of Ted's trolling, his point is "I'm not specifically talking about Fibonacci. I'm talking about non-trivial computation as a general problem in Node." He specifically chose a slow algorithm to illustrate his point. However, what was the Node community's reaction?

One reaction was to go out and implement Ted's intentionally-retarded Fibonacci algorithm in a bunch of different languages and benchmark how fast the VM could optimize away a crappy algorithm. Based on several benchmarks, V8 actually does a comparatively good way of optimizing away the retarded algorithm compared to a lot of other languages. Cool story bro!

In the Reddit comments for this story I first truly gazed into the abyss of Node.js insanity. Node provides a way to schedule an anonymous function to run the next time it's event loop iterates using a function called nextTick. EventMachine (ugh) users may be familiar with this same pattern with EM.next_tick (which needs to die for most use cases, but that's the subject of another blog post)

Redditor "headzoo" suggests that we provide a "non-blocking solution" by unrolling the Fibonacci loop and execute one iteration of the Node.js event loop, calculating one iteration for each I/O multiplexing system call Node is making. When Ted Dziuba asked "Have you taken epoll into your heart?," I think he had no idea of the depths Node people actually have.

I don't really get what's going on in Node people's heads here. I think they seriously believe that throwing computation into the middle of an event loop is a good idea, because Node's event loop is FAST!!#$#! funroll-loops + nextTick = LUDICROUS SPEED!!

This crap is absolutely insane. For each iteration of the loop, Node is making an expensive system call. It's also defeating all of the mechanisms that V8's impressive JIT would use to optimize this problem, as substantiated by the previously mentioned Nodian's roflbenchmark. Clearly this is a very bad idea. But wait, it gets worse!

It wouldn't take long before another Node.js fan put together a Github project for this technique, which also added an "optimization": memoization! In addition to unrolling each iteration of the Fibonacci function to run within the event loop, it now caches the nth result. Now let's throw ApacheBench at it and see how fast Node can serve the precomputed result where n = 100.

Holy balls, it does 5390.22 requests per second serving a memoized value when I ask ApacheBench to request the same memoized value over and over!!#$! TAKE THAT TED DZIUBA! Is it any good? One word: yes. Did we miss the point that this isn't about Fibonacci? One word: yes. (Side note: I second raganwald in adding "Is it any good? Yes." to the top of all my READMEs)

Memoizing each member of the Fibonacci sequence makes this algorithm O(n) in memory. For shits and grins I installed Node-fib and asked it for the 1 millionth Fibonacci number. Node ground away (on a single core of my quad core i7 MacBook) for about a minute before running out of memory, crashing the entire VM.

Okay, so mistakenly implementing an algorithm this pathologically bad when you're trying to prove a point to someone who's just trolling you is pretty bad, right? But it gets worse. 

After pointing this out, a member of the Node.js community (post now deleted) suggested I might have an obsolete version of Node with a 1GB heap limit (because Node uses a VM targeted at client-side JavaScript where 1GB heaps are an uncommon use case, but hey, let's throw it on the server!) and that I recompile without the 1GB restriction so that this retarded algorithm can continue eating up all my system RAM. He says this as if this is a good idea instead of, I dunno, using a better algorithm.

Clearly the next logical steps are to store previously computed Fibonacci numbers in MongoDB. Or you could build a system with Socket.IO which caches previously computed Fibonacci numbers client-side using a distributed hash table. Then you'd be well on your way to a multimillion dollar cloud-based Fibonacci number service. Eventually you'll probably want to build in an OpenMP C++ native extension to calculate Fibonacci numbers across multiple CPU cores. That way you'll have a truly roflscale Fibonacci web service.

36 comments:

Elise Huard said...

good post :)
I'm guessing the moderate users stayed silent on that one. Clearly the sane answer was: don't use node for cpu intensive tasks - though can perform well for IO-intensive ones. But I guess when you have a nice gilded hammer ...

ReinH said...

> EventMachine (ugh)?

So the most promising solution to the 10k problem and the basis for a large number of popular projects gets dismissed with nothing more than an "ugh"? This does not make you sound credible.

billconan said...

will you use node.js?
should i use node.js?

adron said...

I'm a fan of node.js and of KISS and of not doing dumb shit. This post, has aligned why you'd want each of these things!

...all that and really, this is a hilarious situation. :)

Great post!

tbranyen said...

Apparently the irony in mocking the original post was lost on you.

Jethro Larson said...

If you reduce a community to it's crazies then no community holds up to scrutiny.

Brian G. said...

So dude, I'm like, a lumberjack and I swing this axe probably better than anyone else in the world because I'm so fucking cool and everyone else is a total idiot they probably use saws to get the job done (perrish the thought) without realizing they don't get this wicked sweet gouge in the tree trunk that helps it fall in the proper direction when you hit it with an axe.

Some guy came in here talking about how cool chainsaws are one day. Well, I picked it up and started smashing the blade of the chainsaw into the tree trunk. This thing totally sucks, no matter how hard I bash the thing into the wood the tree barely took a scratch, meanwhile, the chainsaw is totally obliterated.

I can only come to one conclusion: chainsaws are for idiot because it's terrible at cutting down a tree.

Daegalus said...

Just letting you know, any fib libraries for Node were made as a JOKE against Ted's post. we had a field day with it in the Node.js IRC channel. AKA that was a troll library. The recursion of trolling has been fierce.

Derek Gathright said...

There's a dead patch of grass in the front lawn. Quick! Burn the whole house down!

Corbin Simpson said...

Hey, Event Machine isn't the promise, the promise is Twisted, and I explained here (http://corbinsimpson.com/entry/posion-was-the-cure) how to do it in Twisted. The solution? Just put your CPU-intensive blocking stuff in a thread. Ugly, but effective. If only Node could do it...

EscVector said...

Recursive trolling is exactly what is wrong with everything.

Ryan McIlmoyl said...

You can spawn child processes in Node http://nodejs.org/docs/v0.3.1/api/child_processes.html.

There's also a module to implement the WebWorkers API https://github.com/pgriess/node-webworker

raggi said...

@bascule - Aren't we supposed to use GPUs for this math shit?

@Reinh - take it from a maintainer, "ugh" is right, you've clearly never actually read the code. As far as "the most promising solution to the 10k problem", well lol, either you're trolling or you really drank waaaaay too much kool aid on the way through.

troglodyte said...

I encourage all my competitors to use Node.js.

Luke Palmer said...

Algorithms are for people who don't know how to buy RAM.

spoonbeard said...

How embarrassing that the King of Node made such stupid decrees. I wish that communities like this were formed of many, many individuals, so that I could safely disregard the stupid prattlings and focus on the good parts. Unfortunately, much like with the gays and black people, there are official representatives that speak for all of us and negate our individuality. Too bad! I guess we're toast. This article is the final nail in the coffin (until the next 20-something from 4chan posts his own babbling counter-counter-counter troll, of course)

Ruprict said...

Dunno if you saw the Google Group thread on Ted's post, but it was never-ending.

carpeliam said...

When Rails got attacked a few years back because Ruby is slow, Yehuda Katz said Bottom line: don’t let anyone tell you that Ruby web applications need be slow. The language itself is certainly slow, but I don’t see a ton of Fibonacci web applications being built, so the real question is about where the bottlenecks are, and Ruby acquits itself very well. Same deal here, really. Don't try to optimize fibonacci in JavaScript (why would you?!?), just solve the problems that actually matter in the most efficient way you can, and you'll be in fantastic shape.

carpeliam said...
This comment has been removed by the author.
arquebus said...

what people who are making these "node.js is not concurrent" rants dont understand that there is huge latency involved between a html server and client. And then they use stupid number crunching loops in single threaded code as a benchmark which itself is not doing anything concurrent nor factors in out of order or very late response times.

Tony Morris said...

You can't write or use node.js and expect to be taken seriously. Keep the giggles coming.

Here is parallel fibs in Java: http://t.co/px0EdQYg

...and in Scala: http://t.co/tSFBudt8

lolsuper said...

To realistically think heavy-weight preemptively-scheduled processes are the solution for parallelism leads me to believe you're an idiot.
Get with the program, using native thread-level parallelism is even too granular for current taste. Most abstract the parallelism behind a thread pool, and schedule short-lived tasks. For something like calculating a term in the Fibonacci sequence, you could implement it explicitly in a parallel divide-and-conquer (or "fork-join") way.

MaXPert said...

NodeJS is good at very few things and there is a huge misconception in the community to fit it everywhere. I once had debate on the same topic (URL: http://tumblr.com/xrm4g1ijnx) and results were pretty much same. Node.js community needs some education we should help them, I would call it an effort to help humanity.

Pierre Robes-Roule said...

I can hear Fibonacci laughing in his grave. Anyway, passion is good for innovation.

Isaac said...

Can you answer this question, please? http://news.ycombinator.com/item?id=3077885

Vegas said...

http://fabric-engine.com/2011/11/server-performance-benchmarks/

Node + Fabric is as fast as multithreaded c++

Still early days for us - we will have asynchronous server compute soon, which will remove the locking issue... Then we'll introduce the same approach for Ruby and Django. Aiming for alpha this year.

If node can be this fast, and the server work becomes asynchronous, then it becomes more viable as a general solution.

Eric said...

I know a lot of the stupid people who responded with ways to optimize the terrible algorithm were being genuine, but has it occurred to you that some of them might be trolling the troll?

Node provides mechanisms that let you get complex calculations out of the event loop.

In previous rants by Ryan, he clearly says that we should NEVER block the event loop. The whole point of node is to make everything that blocks an asynchronous operation so we can get on with doing something useful with the system resources.

So when you say that "Node" has jumped the shark, it's not really a stab at node itself, but at stupid people using a good tool in a very bad way.

Or Ted Dziuba - who gets full credit for the idea of intentionally blocking the event loop. =)

peerj said...

lol!

sla said...

I wonder about coordination challenges in event loop systems.
Especially with mix of real time issues:race condition (several IO calls overlapping on some shared state), exceptions (timeout, error) and important ones like cancellation of execution.

Aleksey V. Zapparov A.K.A. ixti said...

Hi,

Nice post :)) I would like to notice that Node.JS does not work with big integers as well :)) I found that when I was trying my dummy comparison here: https://gist.github.com/1271460

Jason Sebring said...
This comment has been removed by the author.
Jason Sebring said...

Ted is a harsh sanity check for fanboys (aka developers who don't think past the marketing) but he makes a valid point to keep your programming light when using Node.js. However, I think this should be the case when doing any web development tasks. Leave it to batch processing and web service calls to do the heavy lifting. Node.js is great for IO which cannot be denied and executes JavaScript which everyone already knows. Node.js is only going to get more powerful. Just use it for its power though, not as a panacea.

Bob Hooker said...

The problem I noted with node.js is that though it is true that for trivial high IO problems node.js is okay, node.js is not generally being adopted for that reason. Rather some designer who knows HTML and learned some JavaScript from Dreamweaver wants to get in on the real business, and tries to sneak node.js in because it promises to allow JavaScript programmers the same pay and status of PHP. .NET and C++ programmers.

Jon.T. said...

Programming properly in JS is actually a lot harder than in PHP or Java. There's a lot of magic and creativity as there used to be in Perl (actually more) and for that reason, a lot of people used to standard programming concepts can't get their mind to understand it and thus hate it. So when Nodejs start to invade the server, all the haters are eager to claim that Nodejs opens the door for less competent programmers to enter the realm of server programming. Entirely not true! Most nodejs programmers made the transition from either PHP, Ruby or Java, because it opens some new perspectives. It seems to me that this entire Nodejs hate has more to do with ignorance, fear, and contempt than anything else.

Unknown said...

What I find funny is that a language like C# or Java will spank that pants off all of these script languages especially for a problem like this

Alex said...

Oh joy, more ad revenue fodder.