top | item 1552908

Node and Scaling in the Small vs Scaling in the Large

184 points| ssclafani | 15 years ago |al3x.net | reply

64 comments

order
[+] blasdel|15 years ago|reply
He mostly pans the 'less-than-expert programmers' canard, so he never explores the assertion that's at its base — that events are far better for correctness.

Rob Pike has spent the last 25 years developing evented languages, and while the Hoare-style CSP approach he's settled on allows for physical concurrency, he doesn't give a shit about bare-metal performance. The fundamental purpose is to be able to write concise programs that directly model the parallelism of the real world, written in an expository manner as to be more obviously correct.

Pike's point is that you should be getting the best true performance by working in an environment that helps you arrive at the ideal algorithm in it's purest form. Making compromises to get more local physical concurrency is a fool's errand, since at scale you're going to far outgrow single machines anyway!

[+] al3x|15 years ago|reply
When it comes to the Go language, bare-metal performance certainly seemed to be something Pike was giving a shit about when he spoke last week at OSCON and the Emerging Languages Camp I organized. Go in its current fairly young stage has performance that's not too terrible; they've mostly optimized for raw complication speed so far, which is interesting, and uniquely suited to Google's development problems. Pike has said that he wants Go to be a replacement for other systems languages. That's going to mean competing with those languages, performance-wise.

I think Clojure's concurrency model ends up more concisely and correctly expressing the "parallelism of the real world" when you consider the dimension of time. Rich Hickey has done some really important thinking there.

Finally, I think you'll find that anyone with a fixed budget for servers isn't going to think that making the most of "local physical concurrency" on every machine in their cluster is a "fool's errand". Hardware is cheaper than it used to be, but it isn't free, and deploying and maintaining it is costly and time consuming. If you can make the most of your hardware and operations investements with a little more thought-work, why not do so?

[+] _urga|15 years ago|reply
"to be able to write concise programs that directly model the parallelism of the real world"

You nailed it.

[+] moe|15 years ago|reply
(No, I’m not making the “callbacks turn into a pile of spaghetti code” argument, although I think you hear that time and again because it’s an actual developer pain point in async systems.)

Amen.

On my first try I was mostly underwhelmed with node precisely because of the callback hell you end up in. I've already had my share of that in twisted and despite the arguments various people make for it; thanks, but no thanks.

That's not to bash node as a whole, mind you. I'll most certainly revisit it when and if it grows a stable co-routine wrapper or similar spaghetti prevention facilities.

[+] cgbystrom|15 years ago|reply
This the exact reason why I dumped Twisted in favor for gevent (greenlet/coroutine-based NIO library)
[+] KirinDave|15 years ago|reply
I'm glad to see people starting to push back against the cult of “Evented is faster.”

It may be, it may not be. The idea that it always is, though, that's balderdash.

[+] stephenjudkins|15 years ago|reply
I completely agree. Further, as he points out, code using events is fundamentally different than code that uses threads, in ways that aren't immediately clear to someone writing a "hello world" app. Complexities arise in ways that don't in threaded code. I think many of the more naive "event-driven" boosters haven't gotten far enough to see the real potential for pain.

That's not saying threaded code doesn't have its own set of issues; but having written a tool that saw very high traffic, was written an event-driven style, and suffered performance reliability issues, I can say that the event-driven approach is no panacea.

That said, for certain applications, one or the other approach is clearly appropriate. But to make that decision requires an understand of the strengths and drawbacks of each.

[+] aaronblohowiak|15 years ago|reply
As he notes, evented vs threaded is only important within a single machine.

I would argue that your architecture for distributing load across machines is more important than evented vs threaded. If we think that the difference in performance is small (regardless of which is faster,) then the question becomes one of which programming style you prefer. Node's implementation of events means you can have mutable state without worrying about locks or synchronization blocks or whatnot.

[+] dmillar|15 years ago|reply
"It may be, it may not be."

Exactly. As he mentions, engineering any given system presents its own unique set of challenges, and should be addressed as such.

Use the proper tools to solve problems. There are no one-size-fits-all solutions in science. Computer or otherwise.

[+] Tichy|15 years ago|reply
It's just obvious how "threaded" can be slow even in low scale scenarios. It's less obvious how evented can be slower than the hardware allows (not saying it can't be). If nothing is known about the large scale, it still looks like a clear win for evented.
[+] dmillar|15 years ago|reply
Despite whether you agree with him or not, Alex is one of the best technical writers around. This post is exemplary of that.
[+] mjijackson|15 years ago|reply
Excellent piece of writing.

I haven't done a whole lot of concurrency programming, so before reading this article I didn't realize that the events vs. threads debate is still being had. The example that Ryan Dahl likes to use to illustrate the superiority of the event model whenever he talks about Node is nginx vs. Apache. That example did more in my mind to reinforce the idea of events being superior to threads (in terms of speed and memory consumption) than anything else.

Keep in mind when reading this article that Alex recently left a little company called Twitter. It's safe to say that relatively few companies will ever have to scale the way that Twitter has.

[+] moe|15 years ago|reply
Keep in mind when reading this article that Alex recently left a little company called Twitter. It's safe to say that relatively few companies will ever have to scale the way that Twitter has.

You mean the failwhale way? ;-)

Not meaning to discredit al3x but I really don't consider twitter a success story in terms of scaling. I don't know if it's incompetence or just some truly bad early decisions that they're still suffering from.

But one thing is for sure; other sites of much higher complexity have scaled much more smoothly to similar sizes (facebook, flickr, just two from the top of my head).

[+] felixge|15 years ago|reply
Node does support two models for concurrency: Non-blocking I/O and worker processes.

Non-blocking I/O is no magic pony, so if you need access to more CPU cores, you start creating worker processes that communicate via unix sockets. I would argue that this is a superior scaling path than threads, because if you can already manage the coordination between shared-nothing processes, moving to multiple machines comes natural.

Otherwise I agree with the post. Nothing will allow you to scale a huge system "easily".

[+] rektide|15 years ago|reply
There are features you miss by relying on IPC. UNIX Sockets are zero copy, sure, but you still lose performance doing the marshal/unmarshal tasks, and that could be largely avoided using shared immutable memory.

I'd much rather node have a multi-threaded Web Workers implementation of nodejs that uses immutable shared memory for message passing. Not coincidentally, I'd much rather push the real distributed scaling problems (such as coordination and marshalling/demarshalling) up to a much much higher level in my application stack. As it stands now, I need multiple marshal/unmarshallers, for the IPC layer and the app's scaling-out/distributed layer.

[+] blasdel|15 years ago|reply
> Herein lies my criticism of Node’s primary stated goal: “to provide an easy way to build scalable network programs”. I fundamentally do not believe that there is an easy way to build scalable anything. What’s happening is that people are confusing easy problems for easy solutions.

Even though I disagree with much of his technical argument, this is an extraordinarily important point that I find myself agreeing with more and more upon rereading. Nothing is scalable out of the box, anything can be fucked up, and there's no silver bullet.

[+] rbranson|15 years ago|reply
What people tend to forget about Node.js is that everyone knows JavaScript. This is really it's killer feature against other platforms. The ability to get a team up and running on Node is unparalleled.
[+] jhuckestein|15 years ago|reply
Unfortunately, everybody "thinks" they know JavaScript. This is dangerous in many ways and might just as well be a node disadvantage.
[+] cgbystrom|15 years ago|reply
I think Alex confuses "scaling in the small" with performance. Rewriting Starling in Scala most probably improved Twitter but it did it make it more scalable?

To me as an outsider, it sounds more as Starling (or Kestrel) got its performance upgraded, not scalability.

May sound pedantic, but it's important to differentiate performance from scalability.

[+] jhuckestein|15 years ago|reply
IMHO you may be able to scale node 'in the big' if you plan to scale on a level above node (i.e. in node instances and inter-node communication) instead of changing the code running in node to scale big.
[+] rektide|15 years ago|reply
ryah immediately posted the following series of tweets, to such effect:

"Thanks-some valid criticisms. The story doesn't stop at the process boundary. Concurrency through Spawning&IPC should be discussed"

"ie, "actors", although not explicitly given that name, are baked in. I just don't feel then need to put them inside the same process."

asked about impl discussion;

"Not really. It's not fancy: unix socks, no framing protocols, no RPC daemons. But using what's there is a valid concurrency solution."

[+] jamesshamenski|15 years ago|reply
I think this is a fascinating look at an emerging company diving through the discover process of picking core technologies. al3x, please keep going with these.
[+] blackrabbit|15 years ago|reply
Really great piece; definitely a great writer even in a heavily technical piece like this.

Interested to al3x's thoughts on the RoR vs. Python-Django also.

[+] rufugee|15 years ago|reply
If, on the other hand, you’re working with a system that allows for a variety of concurrency approaches (the JVM, the CLR, C, C++, GHC, etc.), you have the flexibility to change your concurrency model as your system evolves.

I think you have his thoughts right there. Ruby and python don't allow for a variety of concurrency approaches...at least not on the threading side. You have to resort to multi-process or evented schemes.