
Making the Switch from Node.js to Golang - activatedgeek
http://blog.digg.com/post/141552444676/making-the-switch-from-nodejs-to-golang
======
codingdave
Step 1 - Learn a new technology.

Step 2 - Use it until you find its achilles heel.

Step 3 - Learn a new technology which doesn't have that achilles heel.

Step 4 - Goto Step 2.

To break this cycle, you need to appreciate that every language and library
has its strengths and weaknesses. Learning what they are, and tailoring your
architecture appropriately is better than jumping from one place to another
every time you hit a new problem.

------
jondubois
Every single "Why we switched from Node.js to Go" article I've ever read is
rooted in misunderstanding of Node.js - This one is no exception. The problem
was that the codebase was bloated and probably time to scale up or scale out.
I bet that if an experienced Node.js developer rewrote the entire service
again in Node, you would also get 2x speedup.

I can't believe the CTO of digg bought this but I guess ultimately, it's also
about making engineers happy.

Eventually Go will also reach a point where it will start lagging and then
some smart engineer will conclude that you need to switch to C++! Why can't
developers just admit that they don't know how to scale a service?! It's not
the language that's the problem, it's you; it's always you!

~~~
skizm
I'm not a node expert, but here is what seems like the crux of the problem:

> Consequently, when any request timeouts happened, the event and its
> associated callback was put on an already overloaded message queue. While
> the timeout event might occur at 1 second, the callback wasn’t getting
> processed until all other messages currently on the queue, and their
> corresponding callback code, were finished executing (potentially seconds
> later).

Seems pretty specific to node, no? I mean, just looking at what the article
says (again, I'm not a Node or Go expert) it seems like this problem was
directly alleviated by Go and the speedup wasn't because Go is closer to the
metal, but ultimately had a different method of handling many async network
calls.

~~~
jondubois
I guess you're probably not familiar with the whole "Why I switched from
Node.js to Go" rhetoric - This article is just one of many.

I've heard this "The Node.js event loop gets saturated" argument so many times
- It's the #1 argument used in all articles which promote switching from
Node.js to Go.

The real reason why the event loop is saturated is because your Node.js
process is doing too much work! The solution is to split your process into two
(use the Cluster module or a load balancer - It's super easy).

With goroutines and the like, all Go actually does is delay the inevitable
point when you have to split your main process into two... It doesn't solve
the problem, it just delays it...

I don't know how Go handles the situation where a process gets too many
requests... Maybe it just drops requests (instead of adding latency like
Node.js)? I don't know... But once a program maxes out on total available CPU,
bad things will happen! It doesn't matter what language/engine is being used;
whether requests will start lagging + timing out or that they will start to
get rejected outright; programs cannot transcend CPU constraints.

I don't mind people switching to Go from Node.js because "they feel like it",
but I don't think it's fair to write an article about it claiming that Node.js
is unfit for technical reasons.

There is no meat behind this argument at all and I'm just tired of seeing it
resurface again and again and again on HN. It's starting to look like a
propaganda campaign.

~~~
rounce
> With goroutines and the like, all Go actually does is delay the inevitable
> point when you have to split your main process into two... It doesn't solve
> the problem, it just delays it...

Yes, but Go's concurrency model is far easier to reason about. "I _want_ to do
this thing", and the runtime handles the _how_ and the doing. No need to draw
up some IPC messaging protocol to handle trivial tasks safely. It's a language
feature (ugh sounds so jingoistic). The _cluster_ module is nothing like
goroutines in concept or in practice.

You're making some mighty big assertions there, all the while disregarding the
obvious weakness of a _single_threaded_ event-loop. I'm a total Node.JS fanboy
since 0.2, but as was mentioned elsewhere in the comments, every language is
making trade-offs: substituting shiny new concerns for it's own achilles heel.

------
jorangreef
When I think of event loop blocking, the first thing I think of is GC. I find
it strange that the author doesn't mention or consider GC. They might easily
have been creating too many closures in a loop (a closure per data item,
instead of a single handler for all data items), or millions of long lived
pointers (using a Javascript object as a hash table for caching, instead of a
flat buffer-based hash table).

Did the author tune the size of the libuv threadpool or did they leave it at
the default of 4 threads?

Also, the response times given both for Node and their new system in Go are
really not that great. The results for Go are an anti-climax considering it
was a rewrite. They could probably undercut both times with a better design,
regardless of language.

Node is a great control plane, and you can always use C++ as your data plane.

~~~
majewsky
I would guess that the response times are severely limited by the performance
of S3.

~~~
jorangreef
I haven't worked with S3 for some time. Is latency really that high when in
the same availability zone?

~~~
LusoTycoon
S3 is based on regions.

200ms of latency is quite normal for S3, not designed with that in mind.

------
jhou2
[https://news.ycombinator.com/item?id=11364550](https://news.ycombinator.com/item?id=11364550)

Original thread based on Medium post.

------
krob
Most all major problems with scale are due to single-process threads. Node.js
had it's moment with single-process thread. Blocking will happen even with
events but @ scale. He solved his issue with multiple queue-workers +
messaging between. This alleviated his blocking, and some people spoke to the
fact that node had a cluster workflow which could have also alleviated this
issue as well.

Some languages make this workflow more obvious, and some people get stuck in
the general way of thinking about problems. I think this is more of an
engineering problem and thinking out of the box and ultimately his direction
in looking for resources & help within the general community.

I think when you run into problems like these, you need to try to contact the
community at large to ask about scaling, and ways scaling is generally done
with these types of tasks. Thinking you're the only one who ever experiences
trouble scaling is very juvenile and expresses inexperience & ultimately ego.
Yes, he solved a problem, but he felt he had to uproot himself in the code
already there to do it.

I guess he solved his problem, but he had a quicker path very possibly, he
just didn't know it existed.

------
brian-armstrong
It helps to use the right tool for the job. Go is really perfect for this use
case.

~~~
regularfry
The interesting question is why Node isn't. It's supposed to be fast because
everything's non-blocking, right? So why is this particular use problematic?
What colour _are_ the emperor's clothes, anyway?

------
criddell
I've just started learning Ruby on Rails but Go I'm thinking about Go more
often and am curious about working with it.

Are there Rails-like frameworks for Go? Why I try to Google that, I find lots
of stories about people switching from Rails to Go, but not a lot of
frameworks discussions.

~~~
oelmekki
Hi criddell,

I switched from ruby (and rails) to golang this year as my main language.

If you're thinking "I'm hesitating between ruby on rails and golang", you
should probably go with ruby on rails (no pun intended).

Golang is more low level, and it expects you prefer conceptual simplicity over
abstraction [EDIT: this is why you won't see prominent golang rails-like
framework]. This also means you're supposed to already know how to
architecture a web application (if that's what you want to do) and to know the
techs behind it.

You mention you started to learn RoR, but do you have previous and consequent
experience with web development? If not, definitely use RoR, it will provide
clear guidelines about how to build a web app.

~~~
criddell
I haven't done a lot of web stuff. My day is spent mostly up to my neck in
C++.

I think I'm going to keep plugging away at Rails. If I ever reach a point
where scale is becoming an issue, then I've got a great problem to have.

------
bborud
This article is about not being able to analyze problems and only being able
to express shallow solutions in terms of permutations of existing solutions
without actually thinking about the underlying problem.

Whether the author knows it or not.

Hence, this does not describe a good argument for switching to Go. It
describes a good argument for better education, training and mentoring of
developers so that they become programmers rather than "random assemblers of
bits and pieces".

------
merb
Would've been easier to try patching node to support multiple eventloops where
you can have N event loops for N threads on the server imo.

------
scriptproof
When a request could block the server, for example a request which download or
upload a big file, Node it not for you. Any concurrent language would be
better. Node is perfect when a lot or requests work together, but each one in
a small time or even a long time but step by step. that is my experience and I
hope it will help to choose the right tool for the task.

~~~
regularfry
That misses the point of the article, and misses what they learnt. The point
isn't that a request was blocking the server. That's exactly not what
happened. The point was that they couldn't handle the timeout of the _non_
-blocking request they were making because there were so many other non-
blocking events being processed before the timeout callback could be handled.

They could _probably_ have solved this by scaling out, but I'm not going to
fault their diagnosis or response.

~~~
chadscira
This _could_ have been solved with a simple addition of another queue.

Don't spawn off heavy requests without a throttle / queue, or else you will
overload your single core.

We normally don't think about this because most requests are just tiny queries
/ small http requests.

~~~
ericj5
This. It sounds like the author used a queue and worker pool with the Go
version. There's nothing stopping you from doing the same thing in Node.

I think a lot of people forget this sometimes and just spawn off unlimited
multiple simultaneous requests in Node apps. Doesnt matter what language
you're using, that's never going to turn out well

------
supermatt
so a poorly written app in tech x performs worse than a better written app in
tech y. who would have thought!

~~~
mrweasel
That's not the message of the article. The original application wasn't poorly
written. In fact it was written by people who know Javascript and refactored
multiple times. The new application is written by someone that picked up Go in
a few weeks.

I don't see it as a criticism Node.js either, it's just that Node wasn't the
right tool for the job, in this case. If you pick the correct tools and know
the limitations of your tools, then it becomes less important how proficient
you are with those tools (not irrelevant of cause).

~~~
chadscira
I would like to know more about the implementation.

I have had node do 12000 requests a minute with no problem (on a single core).
In this case they had 4 two core boxes, so they needed each one to at least
perform 42 requests a second under max load.

I want to know more :)

------
chadscira
No mention of Cluster??

[https://nodejs.org/api/cluster.html#cluster_cluster](https://nodejs.org/api/cluster.html#cluster_cluster)

~~~
chadscira
Not really understanding the down votes (maybe the double question mark??),
but oh well.

This is a valid comment considering that the EC2 instance mentioned is a 2
core box, and there is a possibly that the node implementation didn't take
advantage of both cores.

\- Go has multi-core support out of the box

\- Node.js has to be shown a little love, and has limitations. But this would
have been a great use-case for Cluster.

If the Node implementation was using all cores, then I wouldn't have asked
this question. As it stands I don't really know what we are comparing even
with all the graphs.

Also we are still missing a little info on how they handled the requests. When
you have a endpoint on a node server that is not a simple one, it is best to
queue those before handling them (yes a additional queue). This prevents the
process from choking because it just opened up NNN requests to S3.

Most developers are not working with hundreds of HEAVY requests a minute, but
in Node.js this usually has to be handled with care, and does not work out of
the box.

But if you want to pick up a shinier hammer then __Go __for it.

~~~
mrweasel
>Not really understanding the down votes

Personal opinion: Because comments like your original one are annoying as
hell.

They never fail to show up. Someone post an interesting article one how they
solved a particular problem and someone always have to show up with these
pointless comments. Not everyone will know about, in this case Cluster, and
it's not relevant without an explanation.

Article and blog posts about Go seems to attract comments like: You might like
Rust/Elm/Elixir and "that problem could have been solved using X/Y/Z package
or framework".

More often than not it's missing the point, which often is people, with little
or no Go experience are managing to solve really complex problems within very
short time frames.

------
partycoder
If I was to migrate from node.js I would do it to Elixir or Rust.

