In my experience Node.js is more difficult than synchronous code. But it's also, by far, the easiest way to get something running that's massively parallel.
I recently wrote a project that needs to do 100's or 1000's of possibly slow network requests per second. The first try was Ruby threads. That was a disaster (as I should have predicted). I had an entire 8-core server swamped and wasn't getting near the performance I needed.
The next try was node. I got it running and the performance was fantastic. A couple orders of magnitude faster than the Ruby solution and a tenth of the load on the box. But, all those callbacks just didn't sit right. Finding the source of an exception was a pain and control flow was tricky to get right. So, I started porting to other systems to try to find something better. I tried Java (Akka), EventMachine with/without fibers, and a couple others (not Erlang though).
I could never get anything else close to the performance of Node. They all had the same problems I have with Node (mainly that if something breaks, the entire app just hangs and you never know what happened), but they were way more complicated, _harder_ to debug, and slower.
I have a new appreciation for Node now. And now that I'm much more used to it, it's still difficult to do some of the more crazy async things, but I enjoy it a lot more. It's a bit of work, and you have to architect things carefully to avoid getting indented all the way to the 80-char margin on your editor, but you get a lot for that work.
> In my experience Node.js is more difficult than synchronous code. But it's also, by far, the easiest way to get something running that's massively parallel.
It's asynchronous, not actually parallel. Only a single CPU core will be used in node.js.
However, waiting asynchronous tasks will let other tasks run meanwhile, which can feel like parallelism.
Have you tried Haskell? Why haven't you tried Erlang? They're both good choices for writing applications that handle making and receiving thousands of concurrents requests because they have very fast lightweight threads and good exception handling and you don't need to write the kind of code that Node.js forces you to write.
Node is appealing because Javascript is ubiquitous, but I doubt it's harder to learn Erlang than it is to learn to write everything in nested callbacks.
That's why I mentioned that I hadn't tried Erlang. It was one of my first choices, but the library support wasn't there. Tolerant HTML parsing is a requirement for the project, and there doesn't seem to be any good parsers for Erlang.
> I recently wrote a project that needs to do 100's or 1000's of possibly slow network requests per second. The first try was Ruby threads. That was a disaster (as I should have predicted). I had an entire 8-core server swamped and wasn't getting near the performance I needed.
I don't mean to be offensive, but welcome to at least the 1980s. We've known this doesn't scale for ages. The fact that you even tried it and thought it might be a viable solution just shows your education has failed you. I am highly biased against Node, I think it is a giant step backwards. Every blog post I have read that says the opposite admits they have no experience in anything else so they just default to Node being good. I only hope Node is a fad.
> The fact that you even tried it and thought it might be a viable solution just shows your education has failed you
This holier-than-thou attitude is exactly the thing that prevents more people from becoming educated on these kind of subjects. Knowledge and experience on these kinds of subjects are _not_ trivial and are _not_ easy to obtain! Information about what scales, what does not, and why, are scattered all over the place and difficult to find. It may be very obvious to you after you already know it but it's really not. If, instead of spending so much time on declaring other people as dumb or uneducated, people would spend more time on educating other people, then the world would be much better off.
If I told you that the Sun revolved around the earth, would you consider it holier-than-thou to tell me my education has failed me? The knowledge that the original solution (threads in Ruby for handling large numbers of concurrent connections) does not work is not a secret. Even with a peripheral following of Ruby it is well known that this solution would not work, not only is the base Ruby implementation slow but threads have been a known issue in it from day one. The solution is so misaligned with the problem that it is really difficult to validly argue this knowledge is too difficult to find. Yes, scaling to Twitter is another issue, but we're talking about the basics here.
But don't put words in my mouth, I didn't call anyone dumb, I said his education has failed him. This could be himself failing to properly research the problem space, it could be his school for not properly introducing him to the subject, it could be a whole host of things. I never argued he was incapable of learning (clearly he did). And I do spend a lot of time educating people, don't take a singular snapshot of a comment on HN as indication of how my entire life is spent.
If 99% of the world doesn't know that the Sun revolved around the earth, and knowledge of that fact is scattered across a handful of monks in obscure monasteries, then yes that would indeed be a holier-than-thou attitude. And that's exactly what's going on with scaling knowledge.
I would even argue that the Ruby threading problems he's experiencing may not necessarily because Ruby threads don't scale, but possibly because he's using them wrong or because he's not using the right version of Ruby. Ruby 1.8 uses select() to schedule I/O between threads so the more threads and the more sockets you have, the slower things become because select() is linear time. The use of select() also results in a hard limit of about 1024 file descriptors per Ruby 1.8 process. Also, context switching in Ruby 1.8 requires copying the stack. Ruby 1.9 is much better in this regard since it uses native threads and no longer uses select() to schedule threads that are blocked on I/O. I'm running a multithreaded, multiprocess Ruby (1.8!) analytics daemon that generates 12 GB of data per day. It flies. VMWare CloudFoundry's router is written in Ruby + EventMachine. That thing has to process tons and tons of requests and they've found Ruby + EventMachine to be fast enough. To simply say "Ruby doesn't scale and is slow" is too simplistic, and ignoring the underlying more complex reasons would result in one bumping against the same problems in a different context. So no, it isn't so obvious from day 1 that using Ruby would be a problem.
If you think scaling to a few thousand concurrent connections is some closely guarded monk secret then you are making my point all the stronger: our education is failing. The C10k document was released in 1999. That is 12 years we've known how to handle 10k concurrent connections (bare in mind this is not the exact use case mentioned above). Twisted came out a similar time ago. Libevent dates back to at least 2005. Erlang first appeared in 1986, and Erlang was just abstracting how people were already solving concurrency issues into a language. This stuff is not hidden or elite or privileged information. How is it that your average HNer can spout off reasons why NoSQL is claimed to be superior to an RDBMS for scalability yet doesn't seem to know the fundamental concepts? Our education is indeed failing the current generation of programmers if they don't know the basics for a topic that the internet is flooded with.
Finally, I didn't say "ruby is too slow and doesn't scale", I pointed out that the various issues with doing things fast in Ruby have been known for a long time, even to someone only following Ruby. What I did say was that the basic approach the original commentor chose is known to not scale (which it didn't). This is a fundamentally different approach than the VMWare product you mentioned which has chosen a solution similar to Twisted. This approach is known to scale far superior to the original solution.
I've read C10K years ago. I don't consider it a useful educational document. It doesn't go deep enough into the subject and it doesn't describe well enough why things like threading don't work well. I all had to find that out through experience (of writing a web server myself), and even now some things are still blurry. C10K is very old, it doesn't describe recent advances in threading implementations. Why are threads unscalable? Is it because of context switching overhead? Because of the VM addresses required for the thread stacks? Because of frequent CPU cache flushes? C10K doesn't go into those kind of details and it doesn't look like many people know the answer. I suppose I can find out by studying the kernel but frankly I have better things to do with my time, like actually writing software and making a living.
Furthermore C10K is not the complete picture. It describes only connection management, not what you actually do with the connection. The latter plays a non-trivial role in actual scalability.
Nobody said C10K is the end-all-be-all on scaling, nor should it be. It is also false that it doesn't present any arguments for why threads don't scale well. According to the change log the latest change was 2011 which added information on nginx, but the last change prior to that was 2006. That version of the document talks about memory limitations on using threads because of the stack size. While not extensive it also includes a quote from Drepper about context switches. It even points to documents that are pro-threading. My point is that it's been around for 12 years and is easily found and read by anyone. It also contains a plethora if links to more information on the subject. To claim that C10K is not a useful educational document is absurd. But C10K is one document, there are numerous ones out there, a google search away, our knowledge of scaling has anything but stagnated in the last 12 years. Your options aren't C10K or read the kernel source for your favorite OS.
If you're going to argue that those with knowledge need to distribute that knowledge better, that's fine. Knowledge can almost always be distributed better, perhaps someone could make a nice centralized website that has better information than highscalability.com. But at the same time you've just told me that a document that is a great introductory resource on scaling connection handling is not a "useful educational document". You may have better things to do with your time than read kernel source, but is your time so precious you can't do some google searches? Perhaps read an industrial white paper or academic paper on the subject of scalability? You can write all the software you want but if you're ignorant of how to overcome scalability problems are you accomplishing much? And if you're doing tests and learning about what scales but keeping it to yourself you are just as culpable of not educating people.
Known that what doesn't scale? Threads? Sure they do. I could have made Ruby threads work, I guarantee you. Move the network requests into a giant thread pool, and then do everything else synchronously. It was the context switching that was killing me, but you can use threads in such a way that that's not a problem. It's just a lot of work. More work than just using Node, which pretty much does exactly that for me for free.
And on a side note "your education has failed you"? Seriously? You can't just preface something with "I don't mean to be offensive" and then say whatever you like. I don't mean to be offensive, but get yourself some social skills.
I don't understand why saying your education has failed you is considered offensive. In the US we say that about high schoolers all the time but it's a knock on the education system not the students.
Citing your sources would be a great way of asserting your credibility. "Every blog post I have read that says the opposite" doesn't count.
I'd love to read some well-thought-out arguments against node from people who've seriously given node a shot, but I haven't seen any. Granted, I haven't been looking for them, so please prove us wrong.
I don't log the numerous NodeJS blogs I have come across over the year, my opinions on if the authors of Node blogs are qualified isn't really relevant to my point though: NodeJS is a step backwards.
I wrote a comment on reddit that expands on my reasons more, although the second point is less of a problem if people use something like TameJS with Node (which I don't think most people are doing).
I recently wrote a project that needs to do 100's or 1000's of possibly slow network requests per second. The first try was Ruby threads. That was a disaster (as I should have predicted). I had an entire 8-core server swamped and wasn't getting near the performance I needed.
The next try was node. I got it running and the performance was fantastic. A couple orders of magnitude faster than the Ruby solution and a tenth of the load on the box. But, all those callbacks just didn't sit right. Finding the source of an exception was a pain and control flow was tricky to get right. So, I started porting to other systems to try to find something better. I tried Java (Akka), EventMachine with/without fibers, and a couple others (not Erlang though).
I could never get anything else close to the performance of Node. They all had the same problems I have with Node (mainly that if something breaks, the entire app just hangs and you never know what happened), but they were way more complicated, _harder_ to debug, and slower.
I have a new appreciation for Node now. And now that I'm much more used to it, it's still difficult to do some of the more crazy async things, but I enjoy it a lot more. It's a bit of work, and you have to architect things carefully to avoid getting indented all the way to the 80-char margin on your editor, but you get a lot for that work.