Hacker News new | ask | show | jobs
by confounded 2670 days ago
Is Elixir/Erlang considered superior to Go for writing high concurrency web servers?
6 comments

I don't know Go, but that probably depends on your goals. To quote myself from elsewhere:

> Efficiency in the BEAM is mainly in service of its primary goal of fault-tolerance. If one process crashes unexpectedly, the others should continue. By the same logic, if one process is CPU-intensive or IO-blocked, the others should keep making progress smoothly. And if processes are good for isolating errors and performance issues, they should be cheap enough that we can run a lot of them at once. Those assumptions are baked into how the BEAM manages processes.

If raw speed is your only goal, the BEAM probably isn't the best choice. If consistent speed and stability matter, it may be.

More on this at https://dockyard.com/blog/2018/07/18/all-for-reliability-ref...

That was a helpful and interesting article. Thanks.
Not na expert in any of the languages by any means, but Go and Erlanger/Elixir focus on different things:

- Go wants to be performant at high concurrency scale

- Erlang/Elixir wants to keep running at high concurrency scales, whatever the issues are in your application code. Performance comes second.

There's no clear cut answer to your question; I guess if you trust yourself to write servers that will hold a large number of connections while doing a lot of processing then Go has an advantage, otherwise you should probably trust the man-centuries behind the BEAM VM and follow the various blog posts/presentations explaining how you can fine-tune your machine to get to super large scales.

> Performance comes second.

I want to state that performance is too generalize here.

BEAM VM also have a goal of low latency which can be consider as performance. I'm not entirely sure if GO is aiming for that or not. I would never do any numerical stuff on BEAM though, it's very slow.

This article is a bit dated but is interesting between Go and Erlang:

https://www.theerlangelist.com/article/reducing_maximum_late...

Very true, thanks for the article. Go also wants to minimize GC duration by making it per-goroutine and some fancy algorithms to make it as short as possible, so I'd say it's part of it's goals too.
I suspect it's probably much more straight forward to horizontally scale across nodes with Erlang/Elixir and OTP than with Go.
Depends on the definition of superior.

If it's pure benchmarks, then Go is usually going to come in a little bit ahead.

When you get into comparing language design, underlying architectural decisions, problems solved/created/avoided by those decisions it gets more complex.

I did a big write up for code ship a couple of years ago. Had a solid discussion on HN and the comparison remains fairly accurate.

https://news.ycombinator.com/item?id=13497505

What does high concurrency mean?

Both of them give you less flexibility than is necessary to achieve highly efficient use of all threads on a multiprocessor system. For that, you'll need something like a pool of event loops using async/await. This is the system most common in high performance networking in C++, C, and Rust.

Erlang and Go both sacrifice efficiency to improve maintainability and safety by offering a model that allows you to approach concurrency from a more synchronous mindset. Erlang in particular goes beyond Go in that the Actor model is considerably easier to avoid deadlocks and other concurrency bugs in at the expense of a much more opinionated system. Erlang is also less focused on reducing average latency as much as keeping latency predictable at scale.

Long story short, Erlang, Go, and the rest are not apples to apples comparisons, and it takes investment in each language to understand the tradeoffs and use cases for each. You should also view them holistically, as in, what language can my team support, and will the wins from Erlang's message queues outweigh the smaller community, or will Go's mid tier performance be enough to avoid writing on top of the low level libevent and building a custom thread pool or fine tuning Go's scheduler.

Erlang tends to have excellent cpu utilisation if you follow the most basic principles in Erlang and OTP.

The question is if you cannor want to write better concurrent code by rolling it yourself.

In terms of raw performance, Go will be faster. However, the differentiator here is that the BEAM gives you the guarantees and tools to write highly concurrent applications with a sane mental model, fault-tolerance, and isolated processes. As a sibling said, it's fairly easy cluster applications. Additionally, if something truly needs to be ran in another language for performance, you can write a NIF in Rust or something and execute it from Elixir.
Highly depends on which libraries are you talking about. Essentially you cannot claim that Go will be faster. You can say that fasthttp is faster than Cowboy for a hello world application. Every real world application is much more complex and the stack's performance will be decided by its slowest element.
Go is faster than Erlang and not by a small margin, Erlang is a dynamic and immutable language, it hurts performance compare to languages like Go.

Some benchmark about pure CPU computation:

https://benchmarksgame-team.pages.debian.net/benchmarksgame/...

Erlang is really slower than Java

Go and Java now:

https://benchmarksgame-team.pages.debian.net/benchmarksgame/...

You see the big difference, Go and Java are on part but Go usually takes way less memory than Java.

You can't have everything, message passing / immutability with no performance hit.

Elixir/Erlang is slower than java for computationally expensive non tail optimized large struct operations maybe. For simple requests with ginormous thread counts the point of failure is going to get hit way sooner with Java than Erlang. If connecting directly to ETS/Mnesia/Dets instead of converting back and forth between an external persistence layer Erlang/Elixir can be amazingly fast. Doing Map Reduce type operations or performing massive data processing tasks in parallel Erlang/Elixirs is likely going to outperform Java. Anywhere where thread overhead is more critical than raw per thread performance Erlang/Elixir can perform better than alternative solutions.
Instead of downvoting this comment, can someone write why this is incorrect? I realize it might not be a popular writing style, but references were provided.
Because it's not hugely relevant. Yes, Erlang is not a "fast" language by many metrics, but that [very often] is not the reason a team would choose to use it. The sibling and parent comments make up a fairly considered discussion regarding this. A comment in the middle of this conversation saying Go etc win in some benchmark game is a non sequitur
I was replying to someone saying that it depends of the library, the answer is no it doesn't depends of the library, Erlang is not a fast language and it's ok.
There's different kinds of "fast" is the problem.

Are you juggling lots of messages concurrently and orchestrating across complex topologies of nodes? A BEAM language is going to excel. That's why Whatsapp, Discord, and RabbitMQ use Erlang/Elixir.

Are you trying to go really fast in a straight and simple concurrency scenario? Go/Java/C++/Rust is going to be faster than a BEAM language in those scenarios.

You won't want to implement a complex concurrency run-time in Java whereas Elixir is not a good choice for a 3D game engine.

Still, there's nothing wrong with using both.

True. It's highly dependent on what is compared. I should have made my point more clear, however. I care more about what the BEAM provides over performance I can get in other language.
As far as from my tests and what I've seen reported online, Go and Rust have a substantial lead (20% ish) over Erlang for high throughput servers.

EDIT: I believe this is partially due to Go being a lot more CPU efficient overall than Erlang (see below). So for simple servers, Go and Erlang will match performance, but for slightly more complex web servers that need to crunch some data, Go [and Rust] will outperform the Erlang VM. https://stressgrid.com/blog/benchmarking_go_vs_node_vs_elixi...

I would add the detail that for both erlang and elixir, running in one core, multiple cores, or multiple machines is seamless. Clustering is easy.
Well one of the fastest HTTP library out there is rapidoid and fasthttp comes very close to it as well as actix-raw, hyper and tokio-minihttp. Erlang and Elixir is lagged behind with a non trivial margin.