Live data from Hacker News

Why Discord is switching from Go to Rust

blog.discordapp.com

251–260 of 670 posts

Re: Why Discord is switching from Go to Rust

#251
post #242
post #51

Earlier quoted context omitted.

Your reply misses the point. We were already doing so few allocations that the GC only ran because it "had to" at every 2 minute mark. The issue was the large heap of many long lived objects.

Did you try to change that interval to a much larger time?

When we investigated, there was no way to change that that we could find - barring compiling go from source (something we could have done, but wanted to avoid.)

Re: Why Discord is switching from Go to Rust

#252
post #157

Seems like you were hitting: runtime: Large maps cause significant GC pauses #9477 [0] Looks like this issue was resolved for maps that don't contain pointers by [1]. From the article, sounds like the map keys were strings (which do contain pointers, so the map would need to be scanned by the GC). If pointers in the map keys and values could be avoided, it would have (if my understanding is correct) removed the need…

Maybe that is what they hit... but it seems there is a pretty healthy chance they could have resolved this by upgrading to a more modern runtime.

Go 1.9 is fairly old (1.14 is about to pop out), and there have been large improvements on tail latency for the Go GC over that period.

One of the Go 1. 12 improvements in particular seems to at least symptomatically line up with what they described, at least at the level of detail covered in the blog post:

https://golang.org/doc/go1.12#runtime

“Go 1.12 significantly improves the performance of sweeping when a large fraction of the heap remains live.“

Re: Why Discord is switching from Go to Rust

#253
post #87
post #16

> After digging through the Go source code, we learned that Go will force a garbage collection run every 2 minutes at minimum. In other words, if garbage collection has not run for 2 minutes, regardless of heap growth, go will still force a garbage collection. > We figured we could tune the garbage collector to happen more often in order to prevent large spikes, so we implemented an endpoint on the service to change…

With recent Go releases, GC pauses have become neglible for most applications. So this should not get into your way. However, it can easily tweaked, if needed. There is runtime.ForceGCPeriod, which is a pointer to the forcegcperiod variable. A Go program, which really needs to change this, can do it, but most programs shouldn't require this. Also, it is almost trivial to edit the Go sources (they are included in the…

You still may have significant CPU overhead from the GC e.g. the twitch article (mentioned elsewhere in comments) measured 30% CPU used for GC for one program (Go 1.5 I think).

Obviously they consider spending 50% more on hardware is a worthwhile compromise for the gains they get (e.g. reduction of developer hours and reduced risk of security flaws or avoiding other effects of invalid pointers).

Re: Why Discord is switching from Go to Rust

#254

Earlier quoted context omitted.

Discord takes longer to start up than Microsoft Word. Desktop development is a total wasteland these days -- there isn't nearly as much effort put into optimization as server side. They're not paying for your local compute, so they can waste as much of it as they want.

I feel that it's not really fair to expect them to natively implement their app on every platform and put tons of resources into it's client performance - anecdotally discord is a very responsive app - see [0]. But think of it this way, all the effort they put into their desktop app works on all major OSes without a problem. They even get to reuse most of the code for access from the browser, with no installation req…

A lot of the startup cost right now is in our really ancient update checker. There are plans to rewrite all of this, now that we understand why it's bad, and have some solid ideas as to what we can do better.

I do think it's reasonable to get the startup time of Discord to be near what VS Code's startup times are. If we remove the updater, it actually starts pretty fast (chromium boot -> JS loaded from cache) is The slow startup time is very much an us problem, and not an electron problem and is something I hope we'll be able to address this year.

Re: Why Discord is switching from Go to Rust

#255
> Discord has never been afraid of embracing new technologies that look promising.

> Embracing the new async features in Rust nightly is another example of our willingness to embrace new, promising technology. As an engineering team, we decided it was worth using nightly Rust and we committed to running on nightly until async was fully supported on stable.

> Changing to a BTreeMap instead of a HashMap in the LRU cache to optimize memory usage.

It is always an algorithm change

Re: Why Discord is switching from Go to Rust

#256

Looks like the big challenge is managing a large, LRU cache, which tends to be a difficult problem for GC runtimes. I bet the JVM, with its myriad tunable GC algorithms, would perform better, especially Shenandoah and, of course, the Azul C4. The JVM world tends to solve this problem by using off-heap caches. See Apache Ignite [0] or Ehcache [1]. I can't speak for how their Rust cache manages memory, but the thing to…

One the one hand, yes. On the other hand, all of this sounds much more complex and fragile. This seems like an important point to me:

"Remarkably, we had only put very basic thought into optimization as the Rust version was written. Even with just basic optimization, Rust was able to outperform the hyper hand-tuned Go version."

Re: Why Discord is switching from Go to Rust

#257

Would it have been better if they went with Elixir? Write their code in a functional style. Get the benefits of the Erlang BEAM platform. Their system runs over the web, so time sensitivity isn’t as important, in comparison to video games, VR, or AR. Anyone ever done a performance comparison breakdown between something like Elixir vs. Rust?

"Would it have been better if they went with Elixir?"

No. It would have been unshippably bad. BEAM is generally fairly slow. It was fast at multitasking for a while, but that advantage has been claimed by several other runtimes in 2020. As a language, it is much slower than Rust. Plus, if you tried to implement a gigantic shared cache map in Erlang/Elixir, you'd have two major problems: One is that you'd need huge chunks of the map in single (BEAM) processes, and you'd get hit by the fact BEAM is not set up to GC well in that case. It wants lots of little processes, not a small number of processes holding tons of data. Second is that you'd be trading what in Rust is "accept some bytes, do some hashing, look some stuff up in memory" with generally efficient, low-copy operations, with "copy the network traffic into an Erlang binary, do some hashing, compute the PID that actually has the data, send a message to that PID with the request, wait for the reply message, and then send out the answer", with a whole lot of layers that expect to have time to make copies of lots of things. Adding this sort of coordination into these nominally fast lookups is going to slow this to a crawl. It's like when people try to benchmark Erlang/Elixir/Go's threading by creating processes/goroutines to receive two numbers and add them together "in parallel"; the IPC completely overshadows the tiny amount of work being done. (They mention tokio, but that's still going to add a lot less coordination overhead than Erlang messages.)

Go is a significantly better language for this use case than Elixir/Erlang/BEAM is, let alone Rust.

(This is not a "criticism" of Erlang/Elixir/BEAM. It's an engineering analysis. Erlang/Elixir/BEAM are still suitable for many tasks, just as people still use Python for many things despite the fact it would be a catastrophically bad choice for this particular task. This just isn't one of the tasks it would be suitable for.)

Re: Why Discord is switching from Go to Rust

#258
post #140

Earlier quoted context omitted.

Why would you want to bring up the Actix author's drama? That doesn't seem like something that should reflect on a language one way or the other.

As an outsider to both the Go and Rust cultures, I read the Actix news and walked away with the impression that the Rust ecosystem is less mature.

I wouldn't call rust ecosystem less mature than go, but it wouldn't call either of them mature.

Both have ups and downs. Rust definitely has immature web service ecosystem and it's a result of immature async i/o ecosystem. At the same time go has those things otb.

Re: Why Discord is switching from Go to Rust

#259
post #251
post #242

Earlier quoted context omitted.

Did you try to change that interval to a much larger time?

When we investigated, there was no way to change that that we could find - barring compiling go from source (something we could have done, but wanted to avoid.)

Yes, you have to rebuild go, but that is literally done in a minute. It also would be interesting, if you happen to have some conclusive benchmarks, how the latest Go runtime would perform in this sense.

Re: Why Discord is switching from Go to Rust

#260

Earlier quoted context omitted.

Ok but in rust those pointers can just be borrowed obviating the need for gc at all.

Given it's a cache the entries would not have an existing natural owner… except for the cache itself. There would be no need for a GC to traverse the entire map, but that's because rust doesn't use a GC.

While Rust does not have a discrete runtime GC process, it does utilize reference counting for dynamic memory cleanup.

So you could argue that they are still going to suffer some of the downsides of a GC'ed memory allocation. Some potential issues include non-deterministic object lifespan, and ensuring that any unsafe code they write which interacts with the cache does the "right thing" with the reference counts (potentially including de-allocation; I'm not sure what unsafe code needs to do when referencing reference counted boxes).

Post reply on HN