Live data from Hacker News

The Way of the Gopher: Making the Switch from Node.js to Golang

medium.com

131–140 of 189 posts

Re: The Way of the Gopher: Making the Switch from Node.js to Golang

#131
post #31
post #15

The crux of the difference seems to be, in the Node.js service: "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)." And…

Node.js has cluster to solve this issue https://nodejs.org/api/cluster.html#cluster_cluster

Which brings us back to 2001 and Apache's prefork model. Threads are pretty battle tested at this point, and allow for different reasoning about the concurrency of a problem. The problem with node is that it pretty much only allows for one type of scaling if you start running into performance problems. Go gives you a much bigger toolbox to work with if, much like the post's author discovered, your problem set does not match up with the answers node provides.

Re: The Way of the Gopher: Making the Switch from Node.js to Golang

#132
post #80

Earlier quoted context omitted.

Two iron-clad rules of data processing: * All data has a type * All I/O is asynchronous and interrupt (event) driven At its inception Unix doubled down on stupid, first by encouraging data to be stored and migrated in the form of untyped text streams, which require ad-hoc parsing and unparsing logic at the endpoints; and secondly by failing to provide asynchronous I/O primitives to user space. POSIX later provided an…

> you could even put the process to sleep until pending I/O is completed and have it take up no CPU during this time. Instead what people do is burn CPU cycles in select/poll loops That's what select() does though: you give it a timeout, and it goes to sleep until either an fd becomes ready or the timeout expires. As an example, the X server on you typical linux laptop uses select() on a whole bunch of sockets, one f…

Sit down in front of an Amiga from the 1980s or early 1990s sometime and you will get a whole new perspective on what constitutes "good enough latency to be interactive". In particular, the UI was always perfectly responsive, even with multiple processes and disk accesses going on in the background -- on a 680x0 machine running tens of megahertz. Once you start spawning enough background tasks and pegging the poor kernel's I/O scheduler, your multi-gigahertz Linux box can't match that sort of claim.

Select is still not nearly as flexible as Windows I/O completion ports, for instance. You cannot kick off an I/O operation, do some other processing, and then wait for the I/O to complete before you use its results with a select loop. You have to do a little bit of processing, pump and poll, do a little bit more processing, pump and poll, etc. You are wasting cpu time compared to the interrupt-driven way, and if you have many processes going at once this can add up in terms of battery power used and latency suffered. Remember that select(2) and poll(2) are system calls -- and all the overhead that goes with that.

The X server, in its effort to implement a GUI which is by nature event driven, historically contained all sorts of hacks in order to simulate the asynchronicity which should come from the OS. And it has always been slow and laggy compared to its counterparts on Windows and Mac OS -- let alone the Amiga where interrupt-driven programming is the norm and the GUI has always been flawlessly responsive even when other tasks are going on.

There's also the fact that nonblocking I/O IS NOT ASYNCHRONOUS I/O. If the kernel needs time to perform an I/O operation -- for example, reads and writes from/to disk -- it WILL block your process doing so. All "nonblocking" really means is "read until read buffer is drained, write until write buffer is full, then return". Your process is still stopped during the read/write! With better primitives such as Windows I/O completion ports that map more closely to the asynchronous I/O subsystems of the underlying architecture -- DMA, interrupts, etc. -- that becomes a non-issue. I/O happens transparently in background from an application (and maybe even kernel) perspective, and nothing is blocked.

In short, nearly anything at all is better than the Unix model in terms of throughput, latency, and more natural programming style. Unix is actively regressive.

Re: The Way of the Gopher: Making the Switch from Node.js to Golang

#133
post #33

I think the author made a pretty good decision to choose a solution which was proven to meet the requirements by another author. However Amazon does provide a tool to batch download multiple things from S3 though. Let's pretend for a moment those tools don't exist already... Let's also pretend Amazon doesn't suggest another solution for when there are lots of GET requests [0]. Let's pretend that using something like…

Another idea is to use lua in Nginx itself, and keep it all within nginx.

Here's an upload example: https://github.com/jamesmarlowe/lua-resty-s3

Re: The Way of the Gopher: Making the Switch from Node.js to Golang

#134
post #120

I've been coding in Node for a couple of years. I find it interesting. But I'm aware that the async model of Node inverts the flow of control, turning code inside out and makes application logic difficult to scrutinize and reason about. Stack traces in traditional multithreaded languages are easy to understand, whereas in Node a stack trace is necessarily filled with unrelated calls - or perhaps no stack at all in th…

The programming model you are describing is almost exactly the model Go has, it just takes it a step further and allows N:M "green threading", so you can use all your cores.

Re: The Way of the Gopher: Making the Switch from Node.js to Golang

#135

> for each request, Octo typically fetches somewhere between 10–100 keys from S3 I'm really curious as to why this is neccessary - what are the 10-100 keys you are fetching per request ? Just reading the high level article it sounds like there is some issue with what this service is doing, irrespective of the language it's doing it in.

My same thought as well. S3 has a rate limit, which is where a lot of these timeouts or errors are probably happening. Seems like they should be using a database instead.

Re: The Way of the Gopher: Making the Switch from Node.js to Golang

#136

2010 - Making switch from PHP to Ruby 2013 - Making switch from Ruby to Node 2016 - Making switch from Node to Go 2019 - Making switch from Go to {hype}

And as long as new ideas come about (in the form of languages / platforms), people will keep trying, learning, and sharing. Thankfully.

The problem is most of the ideas are not new, they are rehashes of old ideas. Many people aren't learning, they are just jumping on the hype wagon without much reasoning.

Re: The Way of the Gopher: Making the Switch from Node.js to Golang

#137
post #76

Earlier quoted context omitted.

"So what I'm saying is, we should all still be using PHP."

Or Perl, or C. After all, even PHP was once a new hipster language. Of course, it's good to be skeptical of the current hyped flavor of the moment. But some languages really are better than others for specific tasks, and new languages do sometimes improve on their predecessors.

C is still the choice language for many things. Perl is still cool to me, though seems to have been replaced by Ruby for web development.

Re: The Way of the Gopher: Making the Switch from Node.js to Golang

#138
post #31

Earlier quoted context omitted.

Node.js has cluster to solve this issue https://nodejs.org/api/cluster.html#cluster_cluster

Which brings us back to 2001 and Apache's prefork model. Threads are pretty battle tested at this point, and allow for different reasoning about the concurrency of a problem. The problem with node is that it pretty much only allows for one type of scaling if you start running into performance problems. Go gives you a much bigger toolbox to work with if, much like the post's author discovered, your problem set does no…

All is well until you have to deal with SEO for SPAs :) and then there is little choice other then node. https://github.com/audreyt/node-webworker-threads spawn real threads with web workers compatible API.

Re: The Way of the Gopher: Making the Switch from Node.js to Golang

#139

I'm disappointed by the overall tone here. It's as if this were some kind of failure that everybody is piling up on. - She made three passes to fix the existing code base. - After that didn't work, with the CTO's involvement, this Go solution was devised. - It took only 2 weeks to ramp up with Go and build a replacement that solved the problem. - The number of instances needed dropped from 4 to 2 This sounds like a r…

I think the disappointment here is that the OP seemed not to understand the root cause of the problem and implemented a solution in a different language (load balanced worker pool) that could have also worked in the original language without a total rewrite. Then the new language is trotted out as the savior. It sounds like the file fetch workers and request handlers were running on the same process, so the longer-running workers ended up blocking requests. The way it's discussed, it seems like pure luck that they stumbled on a solution that solved this (running the workers on a separate queue/process).

I totally agree that it's impressive that it only took 2 weeks to build the Go version, it just seems like it would have taken 2 days to try the worker pool implementation with Node.js.

Re: The Way of the Gopher: Making the Switch from Node.js to Golang

#140

> for each request, Octo typically fetches somewhere between 10–100 keys from S3 I'm really curious as to why this is neccessary - what are the 10-100 keys you are fetching per request ? Just reading the high level article it sounds like there is some issue with what this service is doing, irrespective of the language it's doing it in.

If it's anything like the websites I've worked, 10s (sometimes even 100s) of database requests to render a page isn't all that strange.
Post reply on HN