1. GC and context switching internals. This becomes obvious quickly under load. While you can tune Akka in some ways and Akka will generally kick Erlang's ass in terms of performance, the response times and the number of usable concurrent entities are in favor of Erlang.
2. Libraries - what libraries are you going to use in Akka? JDBC/JPA? java.net? HTTP clients to pass REST requests around to modern integration endpoints? Most if not all are blocking and will bring Akka to it's knees when something freezes. Erlang libs are either non-blocking or blocking doesn't matter because it will handle millions of processes with little overhead.
3. Production ops - deploying and rolling back code in Erlang has tons of gotchas, but you can mostly change code and DB schemas on the fly in production, selectively or even run parts of the production load on your laptop to debug it. And you can deploy changes in small increments many times a day without affecting uptime.
4. Best part is failure recovery. In Akka, the node is a single OS process and single JVM. If you leak a file handle or some resource or lock and a thread blocks nothing will recover you until your OS process dies. Erlang is capable of killing processes everywhere, there is no internal global state. Even if you leak something like a file handle in a process, it will be cleaned up when the process terminates like a real OS process. Even if you leak something in ets/mnesia(the global storage), you can go ahead and clean it up from your erlang shell and production doesn't have to stop. If you leak something in Java and you haven't exposed specific interface to clean it, you will have to kill the JVM.
The best known example for Erlang/Beam "http throughput" is WhatsApp's 3 million+ concurrent connections per host. I don't think you get anywhere close in Akka. Maybe max out at 50K per server? Is even that possible?
Also, I'm not aware of good examples that use Akka with Java. Everyone I know using Akka seems to also be using Scala (not sure if it is just some kind of self-selection). I really can't stand Scala's syntax. I tried two or three times but I find it too easy to encounter Perl like unreadable code. Just my opinion though.
Erlang (et. al. green thread models) has a method of concurrency that works well for situations you're using Erlang for. It's not the most efficient or most technically advanced mechanism for handling concurrency.
That being said-
> Without virtual machine support, doing concurrency is really just faking it
This is patently false, because it implies that: - A VM is necessary for "real" concurrency - (by deduction) Anything not utilizing an erlang-identical model is "faking it."
> will result in significant bugs later on that are essentially impossible to debug
I'm going to need to see an anecdote or citation for this.
Personally-speaking, I have a much easier time (quickly) understanding the execution of event-loop-backed cooperative multitasking than high-level, arbitrarily-preempted threads.
Also - I cannot see any reason why Quasar for the JVM would be any easier or harder to debug (from a theoretical, not tooling or practical standpoint) than Erlang actors.
The nuances differentiating the two models aren't great enough to merit bugs that you might see in one place or the other. Unbound, CPU-heavy tasks will cause problems for both systems.
Now this is still on the regular JVM, which will probably have difficulties JITting code that resides in those green-threads (but still better performance than erlang). Also, the entire application is subject to the regular hiccups: gc requires global safepoints, which are reached by making each thread wait when it reaches a local safepoint; on top of the stop-the-world gc operations themselves.
But things are improving: RedHat is developing Shenandoah, a GC that has STW pauses under 10ms. The only thing left is making concurrent the scanning of garbage roots(those reside in the registers and stacks). Their goal for version 2 is to get completely rid of pauses.
A few of his points that would directly apply to your question: 1. BEAM processes are lightweight which means smaller memory footprint and cheaper context switching between processes. 2. As others have mentioned, garbage collection. Processes don't share memory, so data passed between processes are copied. Virding says that this is a tradeoff, but worth the benefits of keeping garbage collection simple and fast. 3. Since processes are VM processes and not OS processes, BEAM can count the number of function calls each process makes. If a process is long running and starving other processes, BEAM can put that process back on the run queue to give other processes necessary time.
These are the ones I can remember from off the top of my head. I recommend giving the talk a listen.
https://www.youtube.com/watch?v=_Pwlvy3zz9M&feature=youtu.be
Obviously that's not the be-all-end-all measure of a VM, but in the context of actors it's pretty damn important. Akka is essentially an actor library bolted onto a VM that really doesn't like what it tries to do. Some people make it work, but there's a lot of friction from the GC that gives rise to some really undesirable performance characteristics.
Given that it already beats the shit out of Erlang, I can only wonder what would happen if the Hotspot guys added a little bit of additional support ... :-)
- BEAM has green-thread-local GC.
- As you mentioned, preemptive scheduling is implemented at the VM-level and is relatively elegant.
- Faster startup times (meh)
- Dynamic typing (subjective)
> JVM is generally more efficient
Depends on the scenario (and JVM implementation) - tracing, STW GC isn't always the best option.
> has better tooling (ide support)
Yes.
> has better libraries
Bit subjective, but there are certainly MORE JVM-compatible libraries.
---
Personally not a fan of Akka simply due to the underlying languages commonly used with it (Scala, Akka)
As a Haskell-user: if forced to choose between Scala and Elixir, I would choose Elixir.
Why would one choose erlang/elixir over akka[0]? Akka seems to implement a lot of common patterns for you. It has actor persistance, cross-node failover, advanced mailbox and routing logic, and is basically a superset of OTP.
The JVM is generally more efficient, has better tooling (ide support), has better libraries, and so on.
The only point I can give to erlang is the pre-emptive scheduling, which is useful for consistently low latency.
[0] http://doc.akka.io/docs/akka/2.4.0-RC3/java.html