News for hackers. Stuff that matters.
Re:My Node.js is a bit Rusty by orf on Friday September 08, 2023 @03:00AM (#37430410)
> having 25 Node.js instances running for three hours to parse 200GB of data seems like an indication that something isn't quite right.

That’s about 700kb/s.

I’m all for playing with rust, but this post strikes me as engineers being distracted by shiny new things because they are only able to parse a TSV at 700kb/s?

You should be able to understand why your current system performs so absolutely terribly before you decide to rewrite it in any language.

Hand-waving at the garbage collector whilst seemingly doing very little to understand what’s happening doesn’t convince me that there isn’t another, possibly pretty obvious issue going on.

Re:My Node.js is a bit Rusty by pkolaczk on Friday September 08, 2023 @03:09AM (#37430473)
They debugged the problem to be excessive allocations in the tight loop of the TSV parser. If you allocate a separate object per each field, I can imagine how it can result in throughput counted in kB/s instead of GB/s.

We have had very similar issues with Java - excessive heap allocations can bring the system to a crawl and there is often no easy way out.

Re:My Node.js is a bit Rusty by orf on Friday September 08, 2023 @03:28AM (#37430598)
They didn't debug anything. They just stuck a job queue on it and then rewrote part of it in Rust. That's the point of my comment. Using their code in the post (gist here[1]):

   $ pv lol.tsv | node lol.js
   1.71GiB 0:00:07 [ 225MiB/s] [================================>] 100%
   Finished reading the file.
Do we live in a world where engineers using a mature language like NodeJS with a pretty simple line-by-line file reading process and a string split think they hit a hard wall at 700kb/s, and the answer is some inherent problem with excessive allocations and not their bad code?

1. https://gist.github.com/orf/92bc26381e3dc00c8e96af262768591b

Re:My Node.js is a bit Rusty by nerdponx on Friday September 08, 2023 @03:45AM (#37430727)
But is the code shitty? It looks like boring normal code to me. I'm not sure what point you're making here.

The point of the article is that you can write really boring normal code in NodeJS and it's really slow, or you can write really boring normal code in Rust and it's a lot faster, and it's not that hard to use the latter to replace hot paths in the former.

Re:My Node.js is a bit Rusty by mrighele on Friday September 08, 2023 @04:38AM (#37431107)
The point the parent is making is that the boring normal code in NodeJS is not slow, at least not as presented in the article. The bottleneck is probably somewhere else. Allocation is usually not slow in a garbage collected language. Deallocation can be, but that is usually easy to check (for example with the --trace-gc flag, or running with profiling enabled and checking the results with chrome devtools). It would have been nice if they shared such analysis.

With the limited information provided in the article, there are other points that I would check before going as far as writing a module in another language. For example

> records.push({

They are collecting all the parsed rows in a single array. This is going to consume memory proportional to the size of the file, potentially in the same order of magnitude (depends on how much information is being collected and how much discarded).

Re:My Node.js is a bit Rusty by orf on Friday September 08, 2023 @04:02AM (#37430855)
> But is the code shitty? It looks like boring normal code to me. I'm not sure what point you're making here.

1. It should never be that stupidly slow

2. That should be obvious to anyone with a napkin and some math

3. Excessive allocations are highly unlikely to be the root cause of the slowness

4. Instead of debugging, they seemingly spent a lot of time putting it on Kubernetes, scaling it out to 25 instances and then finally rewriting a portion of it in Rust.

The whole thing smells of confusion and multiple issues being conflated together, with the rewrite in rust fixing these by virtue of deletion.

And if the root is was the GC, then some `--trace-gc` output in the post would be nice at the absolute minimum. Showing a for loop with a string split doesn't cut it.

Re:My Node.js is a bit Rusty by maurice2k on Friday September 08, 2023 @04:19AM (#37430967)
Exactly. I'm not a super-expert in Node.js but worked a lot with it and also know a lot of internals.

And I can definitely say: IO speed is pretty good. To be honest, I've never come across a language with bad IO speed and I've seen quite a lot of languages.

I also did some benchmarks (like orf did) and speed is pretty good. Maybe Rust is a little bit better because it's nearer to syscalls than Node.js is but we're not talking about 760kb/s vs. 250mb/s.

200GB of logs and 25 instances means 8GB per instance. Not sure what they're doing, but processing of 8GB taking 3h is like doing it with my 80286 processor ;-) Even with inserting stuff in MongoDB this seems way to slow. And they only replaced the file IO part with Rust...

I guess the records array is getting pretty huge which might result in swapping to disk. But then: don't let it happen, just flush it to the database or whatever. I believe the problem could have been solved with Node.js without issues.

Re:My Node.js is a bit Rusty by disgruntledphd2 on Friday September 08, 2023 @04:01AM (#37430841)
It's probably all the memory allocations. I know that when I do work like this, creating a huge array up front and assigning to that typically results in massive speedups.

I know basically nothing about Node though, so I could be completely wrong here.

Re:My Node.js is a bit Rusty by Karrot_Kream on Friday September 08, 2023 @04:25AM (#37431009)
Yeah that's one way to do it. Another is to reuse structures where possible to not force reallocation. There's a bunch of ways.
Re:My Node.js is a bit Rusty by xmcqdpt2 on Friday September 08, 2023 @07:07AM (#37432054)
Node.js has a decent JIT, or so I've heard. I have experience with the HotSpot JVM. For the JVM this code would absolutely stop allocating on the heap past 10k iterations of the loop. "Split a string then grab the parts in a hot loop" is ground stakes for JIT compilers.

If they are seeing any GC activity once the loop gets hot, something else is going very wrong.

Re:My Node.js is a bit Rusty by disgruntledphd2 on Friday September 08, 2023 @11:26AM (#37434819)
Yeah but if you're appending in a loop you'll need to allocate memory every time, right? Can a JIT avoid or rewrite this?
Re:My Node.js is a bit Rusty by xmcqdpt2 on Friday September 08, 2023 @07:33PM (#37440580)
Yep the Hotspot JIT will absolutely allocate on the stack and reuse memory allocations inside loops. It also has escape analysis and it will detect you don't need the array of strings after the iteration. In that case it usually just allocates the strings directly at their final locations on the record object.
Re:My Node.js is a bit Rusty by disgruntledphd2 on Saturday September 09, 2023 @11:12AM (#37446305)
Wow, that's super cool. Almost makes me wish i did stuff on the JVM (but until someone rewrites LAPACK for it, that seems unlikely).
Re:My Node.js is a bit Rusty by ryanjshaw on Friday September 08, 2023 @07:55AM (#37432372)
The low throughput is definitely a code smell.

In my experience, a common mistake here is to read the data faster than you process it and run out of memory. For example, maybe they have a loop reading lines and doing a bunch of async DB writes: your process will read at disk speed and write at database speed, and you'll run out of memory.

Perhaps this is why it worked to split the file into 8GB units X 25 servers: it didn't blow their memory budget per server.

Re:My Node.js is a bit Rusty by bhaak on Friday September 08, 2023 @04:12AM (#37430919)
Try it with something a little bigger than what you used. Then you would have seen that the GC kicks in and performance goes down after about 2GB of processed data.

With my first try with bigger data it blew up with an out of heap memory error. The article mentions them having memory problems as well. They probably operated at the upper levels of available memory and even got into swapping and then 700kb/s is not surprising.

So yes, this absolutely looks like a memory allocation issue.

Re:My Node.js is a bit Rusty by orf on Friday September 08, 2023 @04:58AM (#37431230)
Yes, of course the unbounded array will cause you to run out of memory. That’s… not news, and it absolutely isn’t a “memory allocation issue” in the sense they are using it in the post.

Try modifying it to clear the array (a DB flush, if you will) every 100k lines.

Re:My Node.js is a bit Rusty by bhaak on Friday September 08, 2023 @05:23AM (#37431421)
That's what you get if you use the (simplified) example code that is in the article. It's also what you can derive from their description of the problem.

Now we don't have any Rust code to compare so we can't say how it's different. But everything points towards to a memory allocation issue that is just not their in simple Rust code.

Re:My Node.js is a bit Rusty by tomhallett on Friday September 08, 2023 @08:37AM (#37432715)
Following you in the abstract, but still a bit confused.

* "unbounded array" - are you referring to `records`?

* If so, is the memory of `records` too large? Or is it that `records[i].pathname` has a reference to `fields[7]`, AND v8 will retain all copies of `fields` until the loop is done?

Do you think this code would be more GC-friendly?

```

let count = 0;

const MAX = 1000;

const flushedRecords = [];

for await (const line of readlineStream) {

  const fields = line.split('\t');

  const httpStatus = Number(fields[5]);

  if (httpStatus < 200 || httpStatus > 299) continue;

  records.push({

    pathname: fields[7],

    referrer: fields[8],

    // ...

  });

  if(count == MAX || isLastLine(line)){

   flushedRecords.push([...records]);

   records = [];
   
    count = 0;

  } else {
    count++;
  }
  

}

```

Or were you thinking something totally different?

Re:My Node.js is a bit Rusty by orf on Friday September 08, 2023 @09:02AM (#37432939)
We know a few concrete things:

1. It parses 200gb at an average rate of 700kb/s

2. The job splits strings into a format that is loaded into mongodb

3. There where OOM errors that went away with a smaller workload

None of this points to an inherent issue with NodeJS and the way it references memory.

The speed issue alone points to a different problem root cause, and the post is completely lacking in concrete analysis.

If v8 is being dumb and retains references to huge strings, then understanding this is the case and forcing a copy (and thus enabling the gc to reclaim data) is quicker and easier than any of their attempts at fixing the issue.

Splitting a small TSV file and loading it into mongo can be done with even the most memory inefficient language without issue.

Re:My Node.js is a bit Rusty by smaudet on Friday September 08, 2023 @11:07AM (#37434474)
"and the post is completely lacking in concrete analysis."

I do agree here, but I think it's telling that the rust solution is, without analysis, just better.

Is this the best developer or best case study? Perhaps not, but it is interesting in that little analysis was needed.

In the case where you have some constraint placed on you (running in the browser, company policy forbids rust e.g.), the analysis is worthwhile. Otherwise, assuming the fix didn't take long (relative to the requisite analysis and dev training), the decision to switch to a less shoot-yourself-in-the-foot language seems reasonable to me.

Re:My Node.js is a bit Rusty by tomhallett on Friday September 08, 2023 @11:42AM (#37435095)
I think we can all agree that the blog article, while interesting and tells a story about the way the author solved a problem, does not have high enough rigor to serve as a benchmark for "don't do this, do this instead", or "this language is bad at this, and this one is better". Those types of statements would require much more rigor and A vs B comparisons where code A and code B are the same, just in different languages.

BUT, what I am interested in - if I'm using javascript to parse a large file line by line, plucking off specific fields like the example does, what can I try to see if it's more GC-friendly? Obviously the answer is always some flavor of "profile it" and "it depends". If the blog author could have gotten a big boost in performance by adding 10 lines of js code to their loop, that is something all readers of the article could benefit from.

I will play around with it and see what I can learn about the V8 GC. For reference: here is a talk about profiling the ruby gc, which helped me fix a memory leak at work (https://www.youtube.com/watch?v=kZcqyuPeDao).

Re:My Node.js is a bit Rusty by Karrot_Kream on Friday September 08, 2023 @01:38PM (#37436782)
There's a lot of other considerations when adding a new language. Questions come up such as:

* How long does it take to ramp up on the new code base (author notwithstanding as a user of Rust outside of the company)?

* If the author of the code is sick and there's a bug, or logic needs to be added, how hard would it be for someone else to do this work?

* What is the build story for the Rust code like? How does it integrate with existing CI?

* How do you store the Rust library? Some artifact store that Node can interact with?

Without more details, unless the company was already writing Rust, this doesn't seem like a reasonable choice at all. Doing some profiling and experimenting with allocation, along with comments as to why you're doing something that's not naive (e.g. appending to a large array) seems much cheaper than doing all this Rust work.

Re:My Node.js is a bit Rusty by nicoburns on Friday September 08, 2023 @04:35AM (#37431085)
> They just stuck a job queue on it and then rewrote part of it in Rust

IMO that's not an inappropriate response here. You can make this code in Node, but it's super-awkward trying to reduce string allocations in JavaScript. Much easier to rewrite in Rust where such things will be fast even with the naive code. For code such as this you can likely do a 1:1 port of the Node code and it will be 10x faster. Which is much better than getting yourself in twists trying to make Node fast at tasks it's not good at.

Re:My Node.js is a bit Rusty by orf on Friday September 08, 2023 @04:49AM (#37431173)
I took the code from their post, the one they highlighted as the issue, string allocations and all, and ran it. It was 1000x as fast as their self-reported runtime.

Does this really, really not scream “there is another issue” to you?

Do you really think, even with string allocations in a hot loop, NodeJS with its very optimised runtime would struggle to hit 1mb/s?

Re:My Node.js is a bit Rusty by LudwigNagasena on Friday September 08, 2023 @08:26AM (#37432630)
Naive Rust code is super-awkward compared to naive JS code. I doubt one can do 1:1 port of anything more complex than Hello World (even FizzBuzz may get you tripped up).
Re:My Node.js is a bit Rusty by __s on Friday September 08, 2023 @08:34AM (#37432694)
Not sure what you mean by naive rust, but for Rust has good webassembly integration. To give you some context, here's a post I made about rewriting 10k lines of js into rust: https://www.reddit.com/r/rust/comments/k3jy5g/i_rewrote_10k_... (I went on to rewrite the server from nodejs to rust too)
Re:My Node.js is a bit Rusty by nicoburns on Friday September 08, 2023 @09:47AM (#37433437)
YMMV, but my Rust code ends up looking pretty much identical to my TypeScript code most of the time. And especially for code like this where there are no complex lifetimes.
Re:My Node.js is a bit Rusty by jplusequalt on Friday September 08, 2023 @10:53AM (#37434268)
I disagree. At my job I rewrote an environment variable injector module written in JavaScript into pure Rust. Not only was it straightforward, but I'm fairly certain I finished the Rust port faster than it would have taken to port it another language like Python or Go.
Re:My Node.js is a bit Rusty by DanielHB on Friday September 08, 2023 @03:13AM (#37430498)
A common technique (at least in Java, never seen it in nodejs) is to have a pool of pre-allocated objects and just reuse them as they are discarded. Essentially manual GC
Re:My Node.js is a bit Rusty by pkolaczk on Friday September 08, 2023 @03:39AM (#37430675)
It is easier said than done, when the whole ecosystem is based on libraries and frameworks that allocate like crazy. Preallocating and reusing introduces complexity and increases likelihood of bugs. And at least in Java you can run into surprising GC troubles with pooling as well. Object pools tend to be promoted to a tenured generation and if you do it too much, you essentially break the generational hypothesis many GCs are optimized for. Generational GCs don't like dealing with objects with long lifetimes.
Re:My Node.js is a bit Rusty by didntcheck on Friday September 08, 2023 @06:51AM (#37431992)
I recall hearing there's something of a parallel ecosystem of near-zero-allocation Java libraries, used in HFT among other things. I'm unsure why people use a GC'd language in the first place if they're going to go to those lengths to avoid it, but presumably there are good reasons (perhaps memory safety, before Rust came along)
Re:My Node.js is a bit Rusty by DanielHB on Friday September 08, 2023 @09:23AM (#37433143)
You use it only for the one class you are allocating a million times per second and let the other ones be GC, often this technique is used within a single heavy function with a tight loop

Most of your application probably doesn't need it and the tight loop might not be big enough to be worth using JNI to write in a non-GC language (as well as maintaining another compiler stack for)

Ideally the runtime should allow you to manually manage memory when you need to, like some keyword that lets you manually keep track of an object lifetime. But as far as I know most GC languages don't have that

Re:My Node.js is a bit Rusty by JackFr on Friday September 08, 2023 @08:07AM (#37432474)
Object pooling is typically not a common pattern in Java these days outside of HFT stuff, and even in those cases it’s often not performance, but determinism that’s the issue. (Connection pooling is still common as with other expensive objects, just not plain object pooling.) Java’s garbage collectors are excellent if you cut with the grain.
Re:My Node.js is a bit Rusty by DanielHB on Friday September 08, 2023 @09:17AM (#37433091)
Yeah, you would only use it in very tight loops in special cases, ideally only within a single heavy function. It would be madness to do object pooling across a large scale codebase
Re:My Node.js is a bit Rusty by DrDroop on Friday September 08, 2023 @03:35AM (#37430647)
Happens JS world aswel SimonDev did a video about it, this one I think: https://www.youtube.com/watch?v=easvMCCBFkQ

This channel is a real gem, show what talent really is: https://www.youtube.com/watch?v=a1L7k35EHIc

Re:My Node.js is a bit Rusty by KeyXiote on Friday September 08, 2023 @05:30AM (#37431482)
Thanks for the vid links, always looking for new channels with informative content.
Re:My Node.js is a bit Rusty by Cthulhu_ on Friday September 08, 2023 @04:25AM (#37431013)
That reminds me of how iOS could achieve fast scrolling of lists, which Facebook and Twitter struggled with for years because they tried to stick with HTML. Basically if you scroll down, a list element from above is moved to the bottom and has its contents replaced.

Anyway, I'm not sure if this is in Java already or is upcoming, but Java will finally add value objects, that is, stack variables instead of just making everything a heap object. For tight loops that will be much more efficient, since it can just reuse the same memory, stay within the cpu registers, etc. (I'm talking out of my ass btw from a superficial knowledge of Go and Java and half-remembered theory from college).

Re:My Node.js is a bit Rusty by MrJohz on Friday September 08, 2023 @04:39AM (#37431111)
Virtual scrolling is a very common technique for rendering large tables or lists in HTML (and pretty much any other environment), and is by no means unique to iOS...
Re:My Node.js is a bit Rusty by lawgimenez on Friday September 08, 2023 @06:33AM (#37431885)
And also common in Android from the very beginning of their ListView now called RecyclerView.
Re:My Node.js is a bit Rusty by masfuerte on Friday September 08, 2023 @07:21AM (#37432138)
The Windows 3.1 list box supported it.
Re:My Node.js is a bit Rusty by xmcqdpt2 on Friday September 08, 2023 @06:59AM (#37432028)
By the way the very same code in Java would absolutely rip through the files with no extra allocations of arrays once the JIT gets seriously involved. A big loop with temporary arrays in it that are used to populate the fields of a record every iteration is HotSpot C2's favourite thing.

Does node not similarly allocate on the stack in hot loops?

Re:My Node.js is a bit Rusty by pkolaczk on Friday September 08, 2023 @07:41AM (#37432262)
Did you actually test it? Some time ago someone at another forum made a similar claim that returning an Optional from a method in Java will be surely optimized as we well, but it turned out that it wasn't (https://pkolaczk.github.io/overhead-of-optional/).
Re:My Node.js is a bit Rusty by xmcqdpt2 on Friday September 08, 2023 @07:42PM (#37440668)
Good point, I should probably check.
Re:My Node.js is a bit Rusty by mhh__ on Friday September 08, 2023 @03:26AM (#37430585)
Realizing that Memory & Memory allocation is almost always where the performance goes wrong in practice takes some wisdom.
Re:My Node.js is a bit Rusty by discreteevent on Friday September 08, 2023 @04:19AM (#37430966)
"almost always [...] wisdom" - Is this sarcasm? Maybe you work in a domain where that is the case but in my experience it's almost always not memory allocation or GC. "Wisdom" if there is any comes from measuring things properly and finding out the hard way that it's not what you think it is.
Re:My Node.js is a bit Rusty by mhh__ on Friday September 08, 2023 @05:30AM (#37431478)
I think it's true more often than not. Also note that I said memory and memory allocation e.g. allocating too much hurts your page tables and your L1 cache.

What field do you have in mind? If it's typically well optimized then fair enough but my bread and butter is compilers which are a pretty typical approximately zero compute, branchy pointer chasing type of workload.

Re:My Node.js is a bit Rusty by insanitybit on Friday September 08, 2023 @08:59AM (#37432914)
I think many people on HN are used to throughput oriented horizontally scalable services, where GC is not particularly relevant because:

a) You don't care about pause times since latency isn't your key metric

b) You can almost always just throw more money at compute power to increase throughput

It's almost always the case in such a system that your bottleneck is on the databases that you're pushing data through, as your main approach of "scale horizontally" typically leads to those sorts of bottlenecks.

Re:My Node.js is a bit Rusty by mhh__ on Friday September 08, 2023 @09:03AM (#37432945)
Forgive me for talking about single programs then.

Databases do typically have exactly the same memory problems though, again this time I mean memory locality rather than allocating it, obviously with the transactional elements on top.

Re:My Node.js is a bit Rusty by alex_lav on Friday September 08, 2023 @03:26AM (#37430586)
> I’m all for playing with rust, but this post strikes me as engineers being distracted by shiny new things because they are only able to parse a TSV at 700kb/s?

They definitely just wanted to A.) Play with Rust, B.) Write a post about it.

This is the key line:

> As an intermediate Rustacean (I do have a fairly successful open-source project written in Rust, called fnm),

It's fine to say "I rewrote this code in Rust because I like Rust". We don't have to do a whole song and dance about why X needed a rewrite in Rust because X wasn't doing a good enough job. People do exactly this work in Node every day successfully. They just wanted to write Rust instead of optimizing some Javascript. _Which is fine_, just totally not newsworthy.

Re:My Node.js is a bit Rusty by _nhh on Friday September 08, 2023 @04:26AM (#37431019)
Couldnt agree more.
Re:My Node.js is a bit Rusty by anonzzzies on Friday September 08, 2023 @04:28AM (#37431033)
I agree, 700kb/s is just impossibly slow; I mean personally I wouldn't use node to do it, but with node you still should be orders faster. Something is not right.
Re:My Node.js is a bit Rusty by z3t4 on Friday September 08, 2023 @04:40AM (#37431114)
[delayed]
Re:My Node.js is a bit Rusty by gchq-7703 on Friday September 08, 2023 @06:29AM (#37431847)
I don't believe that's true. Consider this infinite generator:

    async function* infinite() {
      while (1) {
        yield 'example'
      }
    }

    (async function () {
      for await (const value of infinite()) {
        console.log(value)
      }
    })()
If the generator was consumed all at once, this would never print (because the generator is infinite). `for await... of` should only consume a single step of the stream / generator at a time. It's just syntactic sugar for the usual calls to .next() and etc. See the docs here[0]

[0] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...

Re:My Node.js is a bit Rusty by matharmin on Friday September 08, 2023 @06:39AM (#37431917)
"for await" uses async iterators, which is pretty much the same thing as a stream - just way simpler to use.
Re:My Node.js is a bit Rusty by nightlyherb on Friday September 08, 2023 @07:17AM (#37432109)
N.B. Assuming `readLineStream` in that for await loop is node's readline object, the code is iterating over an asyncIterator[1] which works exactly as what you describe in your solution. (AsyncIterators have a next method that returns a Promise of the next item)

[1] https://nodejs.org/api/readline.html#rlsymbolasynciterator

Re:My Node.js is a bit Rusty by BiteCode_dev on Friday September 08, 2023 @06:23AM (#37431814)
Agree. Espacially, a TSV file is very easy to process in chunks, you don't need a specialized parser like with JSON where most libs just loads the whole thing.

700kb/s smell super fishy.

I can parse that with one Python VM and a few MB of RAM way faster. And node has a JIT.

Besides, let's imagine it would be effectively the case that Python and Node are too slow for this, that would be the perfect case to delegate the task to infra instead of introducing a whole new language and ecosystem plus a rewrite. E.G: a perfect use case for DuckDB.

Re:My Node.js is a bit Rusty by didntcheck on Friday September 08, 2023 @06:59AM (#37432026)
Agreed that there's something else going on here, but it's worth noting that (C)Python uses reference counting (with periodic cycle breaking), rather than tracing GC. Not sure if that actually affects throughput in this scenario though
Re:My Node.js is a bit Rusty by whostolemyhat on Friday September 08, 2023 @07:04AM (#37432042)
Amazing, you read a fairly brief article with a terse description of the problem, and are now convinced you know better than the author.
Re:My Node.js is a bit Rusty by orf on Friday September 08, 2023 @10:47AM (#37434180)
If you read an article with a terse description about the author struggling to ride a bike with 1 wheel missing, would you not assume a second wheel might help?
Re:My Node.js is a bit Rusty by pornel on Friday September 08, 2023 @07:43AM (#37432284)
700KB/s is embarrassingly slow! Modern computers are really fast.

That's a couple of orders of magnitude slower than a WiFi transfer. 1000x slower than SSD read speeds. TSV is possible to parse at RAM speeds — 5000x faster.

I suspect that widespread use of scripting languages, and hosting on micro instances containerized like a turducken, with disks over network, set people's expectations pretty low. You don't need a cluster of 25 machines for simple tabulation of 200GB of data.

Re:My Node.js is a bit Rusty by hestefisk on Friday September 08, 2023 @07:45AM (#37432302)
Exactly my thoughts. I wonder how fast that could be processed by a Perl script or even awk/sed.
Re:My Node.js is a bit Rusty by allarm on Friday September 08, 2023 @09:38AM (#37433335)
AWK/Sed are actually very efficient. See this post for example, it describes parsing 25Tb of data with awk: https://livefreeordichotomize.com/posts/2019-06-04-using-awk...
Re:My Node.js is a bit Rusty by JackFr on Friday September 08, 2023 @08:22AM (#37432592)
> Hand-waving at the garbage collector whilst seemingly doing very little to understand what’s happening doesn’t convince me that there isn’t another, possibly pretty obvious issue going on.

This is pure voodoo profiling. “The job is slow. I guess it’s. . . . here!”

Although the author has my sympathy - I spent a month rewriting a module, optimizing every line of code, squeezing every last bit of performance out to discover that the slowness was entirely due to a downstream SQL statement to which I had made a minor “innocuous” change.

Re:My Node.js is a bit Rusty by insanitybit on Friday September 08, 2023 @08:45AM (#37432794)
You call it voodoo profiling, but isn't it kind of just being experienced?

Like, if you show me code I can probably tell you where the expensive bits are just by looking. I could be wrong, but it's usually not very hard. Complex runtimes make it a lot harder because then I have to reason through things like JIT and any implicit yielding, but even still.

So I'm pretty sympathetic to someone looking at a fairly small section of code, going "oh yeah, that's gonna create a lot of allocations", and then doing work to avoid those allocations. The alternative is that they write benchmarks and start profiling, which is actually quite hard to do well, and takes time. I'm not convinced that the author would have been better served by doing so here.

Re:My Node.js is a bit Rusty by smaudet on Friday September 08, 2023 @09:07AM (#37432990)
I'm inclined to agree - when there's a simple solution (easier more reliable language), use it, the right answer is not "oh you are doing it wrong just follow these contortions and you'll be fine".

Maybe your language that requires contortions is the problem.

Re:My Node.js is a bit Rusty by _gabe_ on Friday September 08, 2023 @10:25AM (#37433917)
I’m curious, have you done much profiling? And what tools have you used if you have? This isn’t a judgment against you, it’s a genuine question because I’m wondering if perhaps I really am just this inexperienced. But the one thing I’ve learned is I’m always very surprised by where the hotspots in my code come from. I always assume big allocations, or bad cache coherency, or O(1) loops when I could use a hash map will be the killers, but then it turns out it’s something else entirely.

Because of this, I’ve just learned to never trust my intuition when it comes to this. Compilers are crazy these days, and it’s very difficult to tell if something will be slow or if the compiler is going to clean it up behind the scenes and make it a non issue. Add to that JIT for certain languages and I don’t even know how you would begin to intuit where a hotspot would be.

Edit: And just for additional context, I’ve used Intel’s VTune profiler, Tracy, Optick, and written a few manual benchmarks. Using these tools isn’t always easy, but they give a lot of insights that I wouldn’t pick up on my own.

Re:My Node.js is a bit Rusty by insanitybit on Friday September 08, 2023 @11:22AM (#37434753)
Oh yes, quite a bit of profiling, certainly. I've used tools like valgrind and cachegrind, perf, manual instrumentation, JMX, or even just `time`, as well as a dozen others I'm sure.

> But the one thing I’ve learned is I’m always very surprised by where the hotspots in my code come from.

Are you looking at small or large codebases? The code in the article is quite tiny. The major complexity in terms of understanding that code's performance is really just V8 specific stuff. As someone who only reads casually about V8 I'd be much less comfortable guessing about performance.

To be clear, there's plenty of times where I can't guess. Certain languages make it really hard, like if there's a lot of inheritance I can't "glance" at the code at all, I have to dig all around the hierarchies. Extremely annoying, I'll 100% have to benchmark in that sort of language.

> Compilers are crazy these days, and it’s very difficult to tell if something will be slow or if the compiler is going to clean it up behind the scenes and make it a non issue.

For sure, like I said, the big question here is V8. If this were in a system I'm more familiar with I'd have an easier time telling you which optimizations would or would not work. But even still it's not too hard to guess, sometimes. Knowledge of your runtime is the big thing, I think. For example, reusing an allocation might seem like a trivial optimization but allocations can actually have effects (like failing) so an optimization that removes one would be somewhat aggressive - the situations where that optimization will kick in is going to depend on your compiler/JIT.

As an example, it's really easy to find documentation about how escape analysis in the JVM works. There are a few rules and you can sometimes look at code and evaluate those rules in your head. You could use those similar rules for C# or Go or JS but you'd be risking that the rules are different in those languages.

Example of an article that goes into some depth on JVM escape analysis and the implications: https://blogs.oracle.com/javamagazine/post/escape-analysis-i...

> Because of this, I’ve just learned to never trust my intuition when it comes to this.

That's totally fine fwiw. I'm definitely pro "just benchmark it", but I will maintain that:

a) Benchmarking and profiling are hard. Getting a representative benchmark of your system under load is particularly difficult and a GC can have wildly different performance characteristics under load.

b) It's often not that hard to guess. The more complex the runtime, the more complex the system, the harder it is to guess.

> and I don’t even know how you would begin to intuit where a hotspot would be.

The short answer is you just learn about how a JIT works just like you learn about how a compiler works.

Just to reiterate, I'm very much pro "measure before optimizing". Like, very pro. But also, the article shows that guessing definitely works. And I think guessing is super effective and a fine tool to use at times. Perhaps I've overstated my ability to "just look at code and see the slow bits" - it's obviously very much dependent on the code itself, my familiarity with the underlying components such as the runtime or compiler, and perhaps a bit of luck.

Re:My Node.js is a bit Rusty by _gabe_ on Friday September 08, 2023 @01:15PM (#37436420)
Thanks for the clarification and detailed response! I think your final two points are probably the two things I was failing to take into consideration here. I’m used to trying to profile medium-ish systems (like 40-50k lines of code) so that was the context I was bringing into this. In regards to the example listed in the article, you are absolutely right about being able to intuit where the hot spots may come from because it’s such a small isolated piece of code.

I’ve still got a long way to go in learning more about profiling, especially when it comes to JITed stuff or things with a heavy runtime. But it’s always nice to hear about how other developers approach profiling (it can feel like black magic to me a lot of the time).

Thanks for the article on escape analysis too! I’ll have to check that out in a bit :)

Re:My Node.js is a bit Rusty by heisenbit on Friday September 08, 2023 @11:36AM (#37434967)
The challenge with profiling is that you are getting some results but the interpretation of these results is extremely context dependent and possibly the issue is outside the context you are examining. It may be the tasks, it may be the glue between tasks and the graphs may not always tell the story. I find having some internal assumptions and being able to test them and building deeper mental model of the critical parts helps to flush out some culprits. Being able to at least eliminate some areas as "ok enough" can help to guide the search. It can be an iterative process where finding the right question and tool is more important than later looking at the data.
Re:My Node.js is a bit Rusty by Mawr on Saturday September 09, 2023 @05:27PM (#37450455)
It's not usually that hard because the higher level the decision, the more impactful it is on performance and the less a compiler will be able to bail you out. That's why you should start optimizing from the highest level and work your way down until the performance is acceptable. Only once you're at the point of optimizing low-level decisions does profiling really start to make sense.

A silly example: it doesn't matter how much you optimize your bubble sort implementation, it'll lose out to the most naively written quicksort, which will lose out to keeping the data always sorted and inserting with binary search, which will lose out to finding out how to make the data inherently sorted, which will lose out to figuring out how to avoid the need for the data to be sorted in the first place. The fastest code is no code at all.

Re:My Node.js is a bit Rusty by insanitybit on Friday September 08, 2023 @08:25AM (#37432626)
> You should be able to understand why your current system performs so absolutely terribly before you decide to rewrite it in any language.

This is the case if the rewrite would take more time than the time it takes to debug and fix the issue. If you already have evidence that this is just an issue with the runtime (ie: "I have a very hard time controlling allocations in this language and allocations are a significant part of the compute time") I don't think it's the wrong call to just pick a language where you have very high confidence that it'll be "just fast".

I've run into this with Python. I just didn't care to figure out what was going on that was making things slow. Rewriting the logic in Rust was not hard, so I did it, and things were fast. I look back now, in this moment, and absolutely don't give a shit about why the Python code was slow or if I could have made it fast.

Re:My Node.js is a bit Rusty by martinald on Friday September 08, 2023 @08:46AM (#37432802)
I'm not a nodejs expert at all, but couldn't they just call the garbage collection manually? Also, wouldn't it be better to have the fields (and httpstatus) variable be declared above the for loop and just replace the contents of the fields variable instead of allocating a new one each time?

The thought process this blog seems to use is 'we have a lot of allocations and nodejs is garbage collected, therefore there is no alternative to using a different language'.

Re:My Node.js is a bit Rusty by insanitybit on Friday September 08, 2023 @08:52AM (#37432854)
Calling it manually wouldn't stop it from being called on its own. Also there are two types of GC calls in node, one for the short lived memory and one for long lived memory (this is a generational gc) so you're going to have to understand where your memory allocations live if you want to do that. That's not too hard, thankfully, thanks to profilers.

But anyway, you'd have to first stop it from being called at all, then call it manually after. This seems very hard, I don't know how much Node would like this, especially as you would have concurrent calls to the GC potentially. There's a very scary difference between "turn off, turn back on" and "turn back on, turn off", which can easily happen if you have multiple concurrent calls to the GC. Imagine if you threw an exception after turning the GC off and never turned it back on? Oof.

I'd frankly prefer someone just uses Rust than starts to fiddle with GC at runtime in such a way.

> Also, wouldn't it be better to have the fields (and httpstatus) variable be declared above the for loop and just replace the contents of the fields variable instead of allocating a new one each time?

Maybe. It's possible that V8 will do that. But also you're adding extra lines to manage your buffer if you want to take control over that allocation. It's probably what I would do tbh, although the post makes it clear that just using Rust, where such management is trivial, is lower cost than expected thanks to the FFI library used.

> The thought process this blog seems to use is 'we have a lot of allocations and nodejs is garbage collected, therefore there is no alternative to using a different language'.

I think the main issue I have with the post is this line:

"Perhaps it's time to consider that JavaScript may be the problem."

Javascript isn't so much "the problem" as it is simply a tool that makes optimizing around allocations difficult. It's very hard to know when you're properly managing your memory or not, and you're subject to the whims of V8 to optimize things for you.

If the author had phrased this instead as "I'm sure there's some way that I could get V8 to optimize the allocations, or avoid them altogether, I'd have faster code - but the cost of doing that is far higher than simply using a language where these problems don't exist" I would have no real objections.

Re:My Node.js is a bit Rusty by giancarlostoro on Friday September 08, 2023 @10:24AM (#37433903)
I'm convinced that most of the time when someone blames Garbage Collection, they're just not digging deeper into their code for a different strategy. It's like when you finally realize why you need database indexes, or the benefits of memoization. You will find it and it will all feel so obvious, and you will likely refactor everywhere else you made the same mistake, and be amazed how much better everything is when you take the time to learn why your performance has downgraded.

Chances are insanely low that the GC is actually your problem.

Re:My Node.js is a bit Rusty by orf on Friday September 08, 2023 @09:06AM (#37432972)
I agree in principal, but they first put it in k8s and then split it into a job queue. They even state that it took over a day to run at one point, implying a lengthy and prolonged attempt at fixing the issue.

If you’re working on something and it’s slow, and during some iteration cycle you find that changing some lines makes it fast, cool. No need to debug it or spend time digging into it.

And it’s good that it’s faster, the post screams “we don’t know how to debug these issues” rather than “we don’t care why it’s slow”.

Re:My Node.js is a bit Rusty by insanitybit on Friday September 08, 2023 @09:23AM (#37433140)
I think we basically agree, some debugging and profiling was probably warranted here, since they were going to go through the effort of horizontal scaling.
Re:My Node.js is a bit Rusty by afavour on Friday September 08, 2023 @09:26AM (#37433177)
> Rewriting the logic in Rust was not hard

For you perhaps but it’s a pretty massive change in the longer term, though. You now have Rust in your codebase. How many engineers on the team will be able to work on it? If you leave tomorrow will the code become a liability?

With the numbers the author is providing it sounds very much like the problem could be solved in Node, even if it means using an unconventional programming style and there would be a smaller maintenance overhead than reaching for Rust.

Re:My Node.js is a bit Rusty by insanitybit on Friday September 08, 2023 @09:34AM (#37433291)
> How many engineers on the team will be able to work on it?

In my experience, basically all of them. Rust isn't that hard to learn on the job, it's maybe hard for some people to learn in isolation.

Obviously adding a new language requires understanding that there's going to need to be build system support, dev support, etc. I guess I assumed that was there? Unless Wiz is still in the 'wild west' phase where you can just do whatever you want.

Re:My Node.js is a bit Rusty by bheadmaster on Friday September 08, 2023 @11:16AM (#37434640)
Personal anecdote:

I've learned Go in a day. Did the Go tour, and immediately felt comfortable writing it.

I've tried learning Rust multiple times, did tours, tutorials, even started reading the book - still don't feel comfortable writing it.

Rust is not a simple language. I say that, and my first language was C++.

Re:My Node.js is a bit Rusty by insanitybit on Friday September 08, 2023 @11:24AM (#37434778)
I've drawn a line between learning Rust at a company and learning Rust in isolation. When you learn Rust at a company you have the full support of the others on your team, who already know Rust. I have experienced this at multiple companies now - picking up Rust when you are on a team of Rust developers is much easier than picking it up in isolation at home.
Re:My Node.js is a bit Rusty by bheadmaster on Friday September 08, 2023 @12:38PM (#37435931)
> When you learn Rust at a company you have the full support of the others on your team, who already know Rust.

Not guaranteed. Maybe it was that one guy who decided to introduce Rust to the codebase, then quit.

But I agree, generally, learning anything is easier when you have someone to ask.

Re:My Node.js is a bit Rusty by earthling8118 on Saturday September 09, 2023 @11:53AM (#37446786)
Another anecdote:

I learn new languages all the time. I make it a personal goal to never let not knowing a language get in the way of what I do.

Rust was one of the easiest I've ever picked up. There is a ton of good information, examples, books, and tooling out there that helps me.

On the other hand I've had to pick up Go several times in the past. It's never stuck. Basically every project I have seen written in it is convoluted and just messed up to read and interact with.

People ALWAYS overstate the effort that Rust takes. There are a lot of spots that you can get messed up on. But not all of us are out here writing code that hits these things. People act like the existence of lifetimes means you have to write them everywhere and think about it. That's not the case for almost any of us.

Re:My Node.js is a bit Rusty by afavour on Friday September 08, 2023 @11:20AM (#37434718)
> Rust isn't that hard to learn on the job, it's maybe hard for some people to learn in isolation.

I have to disagree with that. I've learned Rust but it was one of the most challenging languages I've picked up. Stuff like lifetimes are very difficult to learn on the job without already doing a lot of reading.

Re:My Node.js is a bit Rusty by insanitybit on Friday September 08, 2023 @11:42AM (#37435099)
Just to clarify, you were learning Rust while employed, working on a Rust project, with others on your team who were already familiar with the language?

In that scenario I have never seen onboarding to the language be a problem.

Re:My Node.js is a bit Rusty by nsonha on Friday September 08, 2023 @05:25PM (#37439641)
Who cares, look again what the topic at hand is
Re:My Node.js is a bit Rusty by insanitybit on Friday September 08, 2023 @06:31PM (#37440138)
What? I care. I made a statement about learning Rust in a work environment, that is the topic at hand.
Re:My Node.js is a bit Rusty by nsonha on Friday September 08, 2023 @08:17PM (#37440924)
You're trying very hard to claim that Rust is easy, that is very irrelevant to the topic.

> Just to clarify, you were learning Rust while employed

they did not say that, but you had to frame it that way to, again, claim that Rust is easy, like who cares.

Re:My Node.js is a bit Rusty by insanitybit on Saturday September 09, 2023 @10:32AM (#37445895)
> You're trying very hard to claim that Rust is easy, that is very irrelevant to the topic.

I was responding to this:

> You now have Rust in your codebase. How many engineers on the team will be able to work on it? If you leave tomorrow will the code become a liability?

It's obviously relevant to that question.

> they did not say that,

I said that in my experience learning Rust at companies is easier than learning it in isolation.

They said that they had trouble.

I asked for clarification if they had trouble while learning in a work environment.

You jumped in to say that a work environment isn't relevant.

> like who cares.

Every other person in the thread who is discussing exactly that you absolute dunce

Re:My Node.js is a bit Rusty by satvikpendem on Friday September 08, 2023 @04:44PM (#37439161)
I'm all for rewriting things in Rust too but if it's a fundamental architectural problem that you just port over to the new language, you're essentially brute forcing it with an interpreted to compiled language change rather than solving the underlying issue. For example, running a O(n^2) operation rather than an O(n) one.
Re:My Node.js is a bit Rusty by afavour on Friday September 08, 2023 @09:34AM (#37433294)
Strongly agree. It’s entirely possible that the problems are attributable to GC but there are many alternatives within Node-land that could help: streams? A library that stores data in a typed array rather than raw objects?

Adding an entirely new language and toolchain to your development process reeks of over engineering. Now your project needs a Rust dev on hand, what if you leave? Will there definitely be someone to pick up the slack?

Re:My Node.js is a bit Rusty by marcosdumay on Friday September 08, 2023 @10:18AM (#37433834)
No, I do claim that attitude is completely counterproductive.

This is not some case of bad pick of algorithms. The entire optimization work will happen through microoptimizations spread through the code.

If you insist on doing the microoptimizations on a language that is actively antagonistic to them, you will only create a lot of useless work, and have only mildly useful results to show for it, that will go away as soon as anything on your ecosystem changes (in JS that is measured in what? minutes?). And also, you will end up with an horrible codebase that's probably much less legible than what a lower level language will give you.

And that besides not having any good tooling or community support, because all the tools and the community are focused on developer productivity, not software performance, as that's the entire focus of the language.

Re:My Node.js is a bit Rusty by orf on Friday September 08, 2023 @10:38AM (#37434082)
I can parse a 200gb TSV with NodeJS in under a minute.

Could it be done in 1 millisecond with assembly? Probably.

But we are talking about over a days runtime here. That is not a micro optimisation, regardless of the language you’re using. You’re just using the language wrong, the same as if it took a day to parse with C.

Your attitude, that it’s pointless to even try and investigate performance issues because it’s written in JS rather than whatever language you see as optimal, is totally counterproductive.

Re:My Node.js is a bit Rusty by hnfong on Saturday September 09, 2023 @09:04AM (#37444891)
> Could it be done in 1 millisecond with assembly? Probably.

I know you're probably just knowingly spewing hyperbole to make your point, but unless your L1 cache is 200GB memory bandwidth alone makes this impossible.