Hacker News new | past | comments | ask | show | jobs | submit login
Show HN: Lunatic – Actor System for Rust/WebAssembly (github.com/lunatic-lang)
141 points by bkolobara 14 days ago | hide | past | favorite | 47 comments

Erlang/OTP inspired actor systems that run Webassembly code are a brilliant (and potentially way superior) alternative to microservice madness.

Until now adopting Erlang or Akka meant restricting yourself to a single language ecosystem, but Webassembly maturing and more and more languages gaining support means that you can still use a heterogeneous ecosystem while benefiting from easy sandboxing and isolation, almost instant startup, actor snapshotting/migrations, a unified way of inter-service communication ...

All while avoiding the complexities of grpc, building Docker images, Kubernetes, service meshes, "serverless" frameworks, ...

WASM running in the browser pushes languages to adopt it. Even Microsoft is really investing into dotnet support via Blazor [5].

Also check out wascc [1] [2], which is similar, also written in Rust, quite a bit further along , has some very cool concepts around security and code signing, and supports multi-node systems. (not affiliated)

There is also a spec for distributing WASM via OCI (aka Docker) images, which is useful here. [3]

Some Webassembly proposals like interface types [4] will really help out in this context as well. Sadly wasm has not quite been evolving at the pace I would have hoped for since 1.0. Progress is there, but from the perspective of an enthusiastic early adopter it can seem glacially slow.

[1] https://wascc.dev/

[2] https://www.youtube.com/watch?v=vqBtoPJoQOE

[3] https://github.com/solo-io/wasm-image-spec

[4] https://hacks.mozilla.org/2019/08/webassembly-interface-type...

[5] https://dotnet.microsoft.com/apps/aspnet/web-apps/blazor

> OTP inspired actor systems that run Webassembly code are a brilliant (and potentially way superior) alternative to microservice madness

I very much agree with this. While Actor model systems have not been commonly encountered in the circles I've run in (we don't need no stinking XML Web Services, we're going to microservices wooooo), this confluence of (Actors + Rust + Wasmtime) seems perfect for the age of increasingly-parallel CPUs as Moore's Law comes in for a landing.

I hope these kinds of efforts start to represent the dawn of a beneficial trend that starts us down the curve of excitement, cargo culting, then depression, then plateau of standard utility.

This trend doesn't have to get as bad as the OO craze of the 90s, but it needs to grow large enough to get people to stop reinforcing the OO model out of baby-duck syndrome or inertia.

> Until now adopting Erlang or Akka meant restricting yourself to a single language ecosystem,

"Erlang" itself is a single language, but the BEAM/OTP ecosystem isn't usable only from that language (Elixir is fairly widely used, and there are others with less-broad use).

But, even funnier is saying that about Akka: Akka is a JVM library built in Scala and usable from almost any language on the JVM (so, in addition to its "native" Scala you also have Java, Kotlin, Ruby [by way of JRuby], Clojure, and...well, listing languages with JVM implementations that could use Akka could go on virtually forever.)

I could not find any tutorial on running akka on golang, kotlinjs or scala native. I'll let you know how well it runs on python once I rewrite my whole infrastructure to use jython instead

> single language ecosystem

The BEAM supports at least 20 languages.

All of which are tiny niche languages, except Elixir...

I actually think think BEAM gaining the ability to run WASM would be a smart development.

It would make using high performance C/C++/Rust code much easier than the NIF/Ports hassle, with much better sandboxing and scheduling control for the VM.

If they also add WASM actors on top it could expand the interest significantly.

OTP has decades of tuning and improvements that will be hard to match in other projects like this.

"Supports" and "ready for production" are two entirely different things.

And you can always feel the Erlang in them (though that's not a bad thing).

I just checked, and I don't know any of them....to tell you the truth, I haven't even heared of them, except Elixir which I heared is a modern version of Erlang.

So? You probably haven't heard of 95% of the languages that has existed and exist. They're niche languages, just like the VM they run on and this doesn't mean they're half-baked like JavaScript which you've heard of.

Actually I looked at some, and they look half baked experimental languages to me. Right now I'm using Python, because PyTorch is written in Python (and C++), not because it's my favourite language. For me library support is more important than the language itself actually.

> All while avoiding the complexities of grpc, building Docker images, Kubernetes, service meshes, "serverless" frameworks,

I don't think this will happen to be honest. The WASM process still has to run somewhere, it's probably going to be wrapped up into those systems.

Also all of the code written against existing system interfaces for IO etc will not be compatible with the WASM runtime, which means you'll have to run WASM + something else too (and the easiest path is probably going to be to use those "ops" systems you mentioned).

The advantage is that you have _one_ Docker container for hosting your wasm host, and they can use some clever communications inside there, instead of having many containers which have to find each other and communicate using only basic networking primitives.

At work I have a Rust web server with basically two parts - What humans see (HTML), and what computers see (API)

The API rarely changes, and I was thinking of splitting them into two services so that I could iterate on the human side without worrying about breaking the API side.

But I don't want to do that because it means extra management overhead in Docker, extra build steps, etc. And the Docker image is unwieldy from having all of Debian packed in it.

So 1 Docker image with 2 Wasm servers in it, is less overhead (of ops) and less risk. I should still use testing to prevent the API breaking, and I still have to figure out a deterministic way to get Wasm images into the server, and measure the performance overhead of Wasm, but it's a tempting option.

I agree, I have settled on a similar principle for the small systems I build: Reduce distributed state and message passing as much as possible, use only one process if possible.

I think I have settled on a typed language using async and writing state to disk with SQLite.

The async functions give me much more context than messaging (Golang, Erlang, GRPC etc) as they preserve the function call stack, SQLite is just the "sync" part of a SQL engine so no message passing there, and types give me machine checkable interfaces.

It's going ok.

>Even Microsoft is really investing into dotnet support via Blazor [5].

I think it's kinda underestimation because Blazor seems to be one of the top "implementations" of support for WebAssembly

Hi! Author here. I wrote more about the motivation behind Lunatic if you are interested, check it out: https://kolobara.com/lunatic/index.html#motivation

Thanks, because from the github page I had no idea what "Actor" meant, though I was interested to know more. Reading the code sample did not give me any better idea what was meant by the word "Actor"

It would be great if every github readme had a "motivation" section at the top. Why not link it there?

Thanks for the suggestion! I have added the link to the Readme.

That's great. I also got interested to read about Erlang and the original Actor pattern there. In your motivation doc I clicked the Erlang/OTP link to the main Erlang page, but I kind of had the same problem there, of having a hard time finding some light reading introducing the motivation of Erlang.

Their documentation section doesn't immediately yield anything that looks like quick reading to understand the motivation or design philosophy. I could not figure out how to navigate https://erlang.org/doc/ to find introductory material.

Do you have any pointers to good reading that would introduce the Actor pattern in Erlang?

You might be better served if you read Elixir's official tutorials. They explain it (although I'm not sure which of them focused on that aspect; but they are only a few so you should be able to find the needed material easily).

Fantastic project! The ability to transform serial compiled languages to run atop an async engine is great.

The examples, though, remind me more of Go routines and CSP rather than actors. They appear to be passing channels around to communicate which is very similar to but different than a mailbox open to any other process. Is that just a temporary approach? One of the best aspects of BEAM is OTP and supervision trees (linking processes) alongside flexible process naming. I'm not sure how channels would mesh with that. Granted this looks early stage and maybe you're planning on building mailboxes or process links or similar.

Also, you might consider providing support for a binary message passing format like Message Pack or CBOR. Excited to see where Lunatic progresses!

Nice work! How do you pass complex objects between actors in Lunatic? Do you have to pass a byte array, or is there a more sophisticated approach where you don't have to serialize and deserialize each message?

Thanks! Currently the heaps and stacks of each actor are completely separate and it's impossible to pass anything without copying it. In the future I would like to add an option to share buffers for efficiency reasons.

just a question: how much memory a wasm process in lunatic consumes as minimum?

You need 1 page (4 kb) for the stack at minimum.

This is the way forward. A wasm-instance-per-actor architecture enables:

- Actor prioritization

- Actor pausing

- Killing actors at arbitrary points

- Actor serialization / migration

- per Actor GC (internal to them)

- Multiple languages

- Inter-actor/host protected shared memory in addition to message passing

Has the potential to be better than Erlang and much, much better than Go.

> Has the potential to be better than Erlang

what's the overhead of a wasm instance?

Author claims 4 KB for a stack page here: https://news.ycombinator.com/item?id=25163677

What about Erlang?

4k sound like not that much to me? Imagine a server with 1M concurrent connections, could it need just 4G? (Plus lots of overheard. And without heap)

Erlang minimum process memory (heap+stack) is about 2472 bytes in 64bit systems.

So 2.5k vs 4k?

I've been pushing away potential suitors to learn Actor-based systems, contenting myself with researching patterns to use with F# MailboxProcessor while I wait for Gleam (the proglang that is basically statically typed Erlang) to mature enough for this newbie to be able to jump in.

But the concept of rust-based Actor frameworks (that compile to WASM!?) is very, very tempting.

I'm a big fan of Gleam! I will put "compiling Gleam to WASM and running on Lunatic" on my "if I find time for it" list.

I have neen trying to think of a way to leverage Cloudflare's workers/durable objects as a poor man's Erlang cluster... I think this might be it!

See also, Bastion: Highly-available distributed fault-tolerant runtime in Rust https://news.ycombinator.com/item?id=22403713

Any comparison with actix(-web)? I know the latest version of actix-web doesn't use the actor model, but actix itself still does.

It seems I've been in my "ignore all new tech stuff" hole for too long when I open a project link and don't understand most of the value/code. It seems very interesting though, I am not knocking the project at all.

So, I write code that compiles to WASM, and then pass that code as a process to Lunatic? Is this pattern intended to be a generation beyond microservices/containers, where rather than writing a "service" that gets put into a container and then managed by a container orchestrator, you're creating processes that get managed by a process manager? To get rid of the container overhead? If that's true, isn't it just all turtles because Lunatic will have to run out of containers (and presumably those will have to be managed/orchestrated)?

I don't think the point is to reduce overhead. It may actually increase it, as long as the overhead for AOT wasm is more than 0. [1] As I understand it, containers have almost no CPU overhead. I have no citation for that.

Lunatic, to me, looks more like a web browser hosting many JavaScript sandboxes. But instead of JavaScript it's wasm, and instead of a web browser, it's only a host process, like node.js. (I don't know if node.js has a concept of running many side-by-side JS actors. Maybe it does)

So you have 1 Unix process hosting many Erlang-like actor processes.

I'm writing a little bit out of my depth, but I think the huge difference is permissions.

Sure, this all might be possible with containers. But Docker, the only container system I've used, is this huge thing. You have to install it, there's a daemon, it hooks into systemd probably, usually you need to be root unless you do everything just right. It requires kernel support for lxc, so I can't run it on the crappy little ARM boards I have to program.

Lunatic, like a web browser hosting JS sandboxes, is _just_ a Unix process. No root, no permissions. I think it will even work on Windows and OS X.

So yeah, if you're talking about web services where you can already manage many Docker containers on a Linux host no-sweat, it might not add much. But if this can be deployed on arbitrary clients with no root and no Linux kernel dependency, it's a very fun toy that must be useful for _something_.

[1] You may find this cool: https://hacks.mozilla.org/2020/02/securing-firefox-with-weba...

Firefox has a C++ font shaping library. Starting in FF 75, they compile the C++ to webasm, then AOT compile the webasm into native code. Resulting in a memory-safe sandbox for C++. There is some overhead, and it looks like a lot of set-up work. They don't give exact percent numbers on runtime overhead.

I don't know if Lunatic is doing JIT or AOT. I'll generously assume that one day they'll do whatever is faster. Part of the point of wasm is to beat JS performance, so I think at least compared to Electron or Node.js (JS sandboxes in a Unix process) it should be competitive.

It's more about fine grained control of errors. WASM/Lunatic could bring many of the benefits of Erlang application design to any wasm friendly language. The creator of Elixir has a nice writeup of the Actor mentality and k8s: http://blog.plataformatec.com.br/2019/10/kubernetes-and-the-...

Pretty slick, reminds me of Erlang in that Actors are just functions. I've always thought this made stateful actors a bit weird since they have to recurse. I like the wasm approach though.

I would love nothing more than for dotnet to adopt something like Erlang's actor system as well AOT compilation to native. I don't think I'd ever leave my house again.

Have you seen Orleans? https://github.com/dotnet/orleans

I believe AOT is now easier/better with .NET 5 so take a look.

And there is: https://getakka.net/

why do you think its better with .net 5?

how does this compare to other "green thread" approaches? Like go channel?

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact