News for hackers. Stuff that matters.
Re:Rust Is the Future of JavaScript Infrastructure by Zababa on Thursday November 11, 2021 @02:48PM (#29192266)
> With Rust, developers have more control over memory allocation, without it being as painful as C++ or Go.

Memory allocation is painful in Go?

Re:Rust Is the Future of JavaScript Infrastructure by PragmaticPulp on Thursday November 11, 2021 @03:23PM (#29192676)
Definitely not painful for simple operations (obviously).

But every large Go project I've worked on has eventually invested a lot of time into minimizing allocations, rewriting critical path sections to use pools, and various other techniques to improve performance by taking more control over memory allocation. Go's GC is very good, but it still has limitations.

Honestly it's not a bad tradeoff most of the time. Write code that works as quickly as possible, profile it as load scales, and apply further optimization as hot paths are identified. On the other hand, I've been working with Rust long enough that I can almost write the same thing in Rust as fast as I could in Go (Rust is inherently more verbose and requires more cognitive overhead). I've been writing prototypes in Rust more and more lately and haven't really been missing Go as much as I did when I first started with Rust.

Re:Rust Is the Future of JavaScript Infrastructure by romero-jk on Thursday November 11, 2021 @04:17PM (#29193293)
Sure maybe, but here we are talking about short running CLI applications not long running processes. IMO, Go is better suited at this 'js infrastructure' stuff.
Re:Rust Is the Future of JavaScript Infrastructure by Thaxll on Thursday November 11, 2021 @05:56PM (#29194321)
When you work at certain scale with C++ and Rust you ends rewriting a GC inside those language because default allocator are not good enough. That's why GC languages are faster than C++/Rust in some scenarios.
Re:Rust Is the Future of JavaScript Infrastructure by obviouslynotme on Thursday November 11, 2021 @06:59PM (#29194824)
>Any sufficiently complicated C or Fortran program contains an ad hoc, informally-specified, bug-ridden, slow implementation of half of Common Lisp.

- Greenspun's tenth rule

Joking aside, Java VM can be as fast as C++, not C, by using profiling and JIT optimization if tuned to a specific server and only measuring after running for a while. If you are really thinking about your allocators and not just calling malloc, nothing is faster. Half of this is due to less allocator calls and half is due to laying out the memory in a cache-friendly manner.

Re:Rust Is the Future of JavaScript Infrastructure by twic on Thursday November 11, 2021 @02:55PM (#29192365)
Perhaps memory allocation is not, but control over memory allocation is. Like most other managed languages, Go trades less control for more ease of use.
Re:Rust Is the Future of JavaScript Infrastructure by leerob on Thursday November 11, 2021 @02:51PM (#29192314)
That was my takeaway from folks who had moved from Go to Rust. I'm not a Go expert though, so feel free to correct me.

https://blog.discord.com/why-discord-is-switching-from-go-to...

Re:Rust Is the Future of JavaScript Infrastructure by kgeist on Thursday November 11, 2021 @03:26PM (#29192710)
Storing billions of states in garbage-collected memory sounds like using a wrong tool for the job (by the way, I wonder why they didn't use something like Redis? didn't scale well?). I think it's an edge case they ran into -- which doesn't mean Go's memory management is painful per se. It's not secret that large heaps with many old generation objects are problematic in presence of GC. And few projects have requirements of the scale of Discord. For stateless servers, Go is more than enough in my experience; in our services we do allocate garbage like there's no tomorrow and we're yet to run into GC problems, because all caching is delegated to a redis cluster and all garbage we produce during request processing is ephemeral so we don't have large object graphs that would slow down the GC. Rust is perfect for this kind of "core infrastructure" projects where you need maximum performance (Redis itself is written in C), but actual business logic on top of such infrastructure can easily be written in a simpler language like Go and GC is rarely a bottleneck there.
Re:Rust Is the Future of JavaScript Infrastructure by dahfizz on Thursday November 11, 2021 @04:07PM (#29193175)
According to Redis themselves, a high end and well tuned redis server will get you ~200k requests per second[1]. This is if all your application does is send requests in a loop.

Am I correct that redis does not offer a native API and so forces you to craft commands as strings? Just having to run snprintf 500k per second wastes a considerable amount of CPU. Combined with the normal overhead of communicating over a socket, using redis is going to be considerably slower than just keeping that memory in your own process. That's assuming the overhead of the redis internals is 0.

[1] https://redis.io/topics/benchmarks

Re:Rust Is the Future of JavaScript Infrastructure by Karrot_Kream on Thursday November 11, 2021 @05:22PM (#29194010)
The trick is to precompute the Redis command strings whenever possible. We (not going to name names here) use Redis at above that scale. Our keys all have a fixed size, so we preallocate a buffer that can hold the command and the key, clear (so move the write pointer back to the beginning of the key) it on every new request, write directly into the buffer, and then pass a pointer to the buffer when writing to the socket. This is a similar trick we use whenever we're constructing load tests as a lot of the time can be spent creating request bodies instead of just pushing bytes onto the socket as fast as possible.
Re:Rust Is the Future of JavaScript Infrastructure by jacquesm on Thursday November 11, 2021 @06:40PM (#29194687)
That sounds like it is written in highly optimized C, not in Rust?
Re:Rust Is the Future of JavaScript Infrastructure by Karrot_Kream on Friday November 12, 2021 @01:41AM (#29196872)
You can do this in Rust with a mut pointer into the string. You can even do it in Go with a byte buffer. Lots of languages give you the tools to do stuff like this if you look. I hear Python's StringIO does similar things but I'm not as familiar with Pythons runtime in these situations.
Re:Rust Is the Future of JavaScript Infrastructure by kgeist on Thursday November 11, 2021 @04:28PM (#29193428)
In the article, they say:

>The service we switched from Go to Rust is the “Read States” service. Its sole purpose is to keep track of which channels and messages you have read

>On cache key eviction, we commit your Read States to the database. We also schedule a database commit for 30 seconds in the future whenever a Read State is updated.

So it's a separate service whose only purpose is to store data in-memory with occasional commits to persisted DB, which sounded a lot like Redis. But of course, a special optimized service is always going to outperform a general purpose tool such as Redis.

They also replaced HashMaps with BTreeMaps, reduced the number of memory copies they were doing, etc. -- which has nothing to do with Go, but also contributed to a performance increase

Re:Rust Is the Future of JavaScript Infrastructure by Matthias247 on Thursday November 11, 2021 @10:41PM (#29196106)
What is a native API? Sending string commands and parsing the response is as much of an API as a HTTP API is.

It's not a library interface if you mean that - but that always applies for distributed systems.

Re:Rust Is the Future of JavaScript Infrastructure by dahfizz on Friday November 12, 2021 @08:42AM (#29199146)
Yeah, by native API I meant a native library that would allow you to call into redis directly. Native being the qualifier - as opposed to an HTTP API, which is not native.
Re:Rust Is the Future of JavaScript Infrastructure by j03b on Thursday November 11, 2021 @03:19PM (#29192631)
The takeaways in this article are much more why Go's memory model becomes difficult at scale. When you're dealing with memory at Discord scale garbage collection is hard, for example on the mentioned Discord microservice:

> There are millions of Users in each cache. There are tens of millions of Read States in each cache. There are hundreds of thousands of cache updates per second.

This is something that is probably never going to be hit locally in the development toolchain. You can certainly prefer the Rust memory system to Go and have that be a valid reason to use Rust over Go for something like dev toolchains, but you're not going to hit scale problems like those mentioned in the article.

Re:Rust Is the Future of JavaScript Infrastructure by AaronFriel on Thursday November 11, 2021 @03:26PM (#29192708)
Not just at scale, Go doesn't make it obvious when an allocation is on the heap or stack. The escape analysis can change (hopefully without regressions) from version to version of Go, and that can mean performance regressions can happen. It also means small refactors risk de-optimizing code without an obvious reason why that would be the case.

I think more engineers are becoming skeptical of optimizing compilers with that sort of implicit, potential "spooky action at a distance" where nonlocal code can cause performance regressions.

In Haskell, laziness and iterator fusion can do the same thing. Nonlocal code can cause local expressions to compile differently, resulting in - from an engineer's POV - nondeterministic performance, memory usage, GC pressure. "Space leaks" can also occur, again, due to nonlocal effects.

In JavaScript, the JIT can similarly cause local regressions due to nonlocal code. A single expression deep in a call stack mutating an object can result in it no longer fitting an optimized "shape", resulting in function deoptimization.

Just say no to spooky action at a distance in programming languages, in my opinion. It leads to tremendously difficult to debug regressions.

Re:Rust Is the Future of JavaScript Infrastructure by Thaxll on Thursday November 11, 2021 @05:49PM (#29194262)
> the escape analysis can change (hopefully without regressions) from version to version of Go, and that can mean performance regressions can happen.

Because it's not the case with Rust or any compiled language? LLVM has shown regressions wich is what Rust uses to compile code.

2sec search on google: https://github.com/rust-lang/rust/issues/24194

Re:Rust Is the Future of JavaScript Infrastructure by AaronFriel on Thursday November 11, 2021 @07:57PM (#29195179)
Of course there have been regressions, but the semantics of the code don't typically change. A "dead heap allocation", or removing an unused call to malloc, is an interesting example but I think you'd be hard pressed to find a case where it caused a massive performance regression.

I think there may be some edge cases (constant folding, dead code removal) of course, but a change to LLVM cannot cause the 3 sorts of changes I identified in Go, Haskell, and JavaScript.

Re:Rust Is the Future of JavaScript Infrastructure by kgeist on Thursday November 11, 2021 @03:44PM (#29192918)
>Not just at scale, Go doesn't make it obvious when an allocation is on the heap or stack. The escape analysis can change

I thought heap allocations are only triggered by taking pointers, i.e. using reference semantics (including casting to interface and calling a method whose receiver is by-ref)? If I'm careful to only use variables by-value (for types that can afford it, i.e. excluding map/array), what else can trigger heap allocation?

Re:Rust Is the Future of JavaScript Infrastructure by jdreaver on Thursday November 11, 2021 @03:55PM (#29193038)
Making a closure usually requires allocation. For example:

    package main

    import "fmt"

    func main() {
        closure := make_closure()
        fmt.Println("closure():", closure())
    }

    func make_closure() func() int {
        x := 1
        return func() int { return x }
    }
This prints:

    $ go run main.go
    closure(): 1

If x were allocated on the stack, it would get nuked after we returned from make_closure(). In Rust you could move x to the closure, but I think in this Go example x would be heap allocated, assuming the Go compiler doesn't notice it can inline all of this and avoid allocating. Maybe assume a more complex example with a struct that had to be computed via a function argument or something :)
Re:Rust Is the Future of JavaScript Infrastructure by kgeist on Thursday November 11, 2021 @04:19PM (#29193327)
Oh yes, closures too. Coming from C++ background, you kinda intuitively understand when things escape and when they don't, because you assume that Go would implement it in the most straightforward way (like it usually does), and in the case of closures, heap-allocating a captured variable is the simplest implementation (just let GC handle it!) considering the implicit reference semantics (that you can change "x" anywhere outside of the closure and it should be immediately visible in the closure, too). I.e. assume the worst (and don't expect Go to do some clever special-casing similar to move semantics in C++/Rust), and it's often the right answer :)
Re:Rust Is the Future of JavaScript Infrastructure by foota on Thursday November 11, 2021 @03:24PM (#29192691)
I don't know, building JavaScript things involves similar orders of magnitude.
Re:Rust Is the Future of JavaScript Infrastructure by tialaramex on Thursday November 11, 2021 @03:44PM (#29192923)
Two things about this pain:

* They incur the pain even when nothing needs doing. This is really terrible. If you spend ten minutes furiously reading data from a network device into a fixed RAM buffer, twiddling it, and writing it out again, in Rust (or C, C++ and various other explicit allocation languages) you neither allocated nor de-allocated anything, therefore you pay exactly zero for this work you didn't do. In Go you will incur the cost of the GC verifying that yup, everything is as it was, there's nothing to do, apparently five times.

* The pain is swallowed in lumps, you can't spread it out. So you must either size hardware for lump swallowing, even though as we saw above we don't even want to swallow any lumps, or accept poor performance each time a lump is swallowed. With explicit allocation you can choose to swallow bigger lumps (e.g. arena allocation) to reduce overheads elsewhere, but you decide on the size of lumps you want for your allocation.

Re:Rust Is the Future of JavaScript Infrastructure by honkycat on Thursday November 11, 2021 @03:01PM (#29192432)
There is a lot of pain over garbage collection and tuning that in really high pref cases
Re:Rust Is the Future of JavaScript Infrastructure by mountainriver on Thursday November 11, 2021 @02:53PM (#29192344)
Sure when you disable the GC =P