Why does the world need Acton?
We believe the existence of a fault tolerant distributed programming environment with orthogonal persistence will make the world a better place. Acton was created to deliver on that belief.
We want a programming environment that offers persistence so that programmers do not need to spend time writing code to save program state to disk or a database (which in turn writes to disk, typically). There are few such languages in existence and even fewer, if any, in practical use. This is especially important as handling state persistence is particularly hard when writing distributed systems or working in cloud environments. The programmer should not need to spend much time dealing with state persistence.
We want to write small programs that can run together to form a large system. It needs to scale beyond the bounds of a single computer and we don't want the programmer to spend any extra effort to achieve this.
We want the system as a whole to be robust. It must tolerate failures to the hardware compute nodes used to run the system without loss of data or function. It should also help the programmer to write correct software without bugs. It's not practical to avoid bugs entirely but when we have a chance to detect and present them early, that is better than later.
We want a reasonably fast system. Performance is not the highest priority but one shouldn't have to needlessly buy newer or more hardware.
We want to lower the barrier of entry and enable people to build the robust systems that modern society needs and relies on.
What makes Acton different?
Acton adopts the actor model and combines it with a simple to use syntax and a powerful type system. Many good things emanate from the combination of the actor model and a good type system.
In traditional languages, programs use shared memory to allow multiple threads or multiple processes to share state or communicate with each other. Shared memory involves locks to avoid race conditions. Checkpointing the state of a program is hard because it is hard to figure out what parts of the memory you need to checkpoint. It's all like a big hairy spaghetti ball and the safe choice is to checkpoint the entire memory of the program. This could work for small programs but we want to write large distributed programs! The key to efficiently checkpointing a program is to be able to work on smaller parts of the program and in order to do that, we need to get a grip on those smaller parts. That is hard with shared memory. There are papers on this topic with various techniques applied in attempts to realize barriers and snapshot chunks of memory but it is hard to make it work well in practice. In contrast, with actors, each actor has its own private memory which makes it possible to checkpoint the state of individual actors. Further, actors communicate with each other through messages. With our own database that implements queues inside the database, we can both read and modify database cells as well as reading, consuming or putting new items on the queues in the same transaction! This makes it possible to deal with actor checkpoints in a transactionally safe way. Many great things emanate from the actor model!
Actors do not fundamentally resolve the problem of snapshotting since it is still possible to construct a single giant actor that consumes 100GB of RAM and snapshotting that won't be fast. However, the actor model does encourage the use of many smaller actors for concurrency as well as logically splitting up your program in manageable units. In practice, it typically reduces the size and time taken to checkpoint by orders of magnitudes compared to a large traditional program. It brings persistence-through-checkpointing from theoretically feasible to practically viable.
Checkpointing needs to happen when there are externally visible effects. The actor models makes this trivial to determine since anything that is externally visible is going to be a message to another actor. To avoid explicit state checkpointing calls, synchronization primitives or explicit IPC calls that would be forced upon the application developer, we employ
magic advanced techniques in the compiler, made possible by its inherent knowledge of the language. By analyzing the code of the program we can determine suitable locations for inserting checkpointing, and this is in fact what the Acton compiler does. It splits up a program into continuations that are executed by the Acton run time system. After a continuation has been executed, its result, including the actor state, any outgoing messages to other actors as well as the consumption of the incoming message that triggered this continuation to run, is committed atomically in one transaction to the database. All this is possible thanks to the language, compiler, run time system and database working together as one. It is only possible with a new language and that is why we wrote Acton.
With Acton, an application developer simply writes single threaded Acton code and relegates the complex tasks of ensuring state consistency, persistence, fault tolerance and load balancing to the compiler, database and run time system.
We hope you enjoy Acton!
Now and the road ahead
Acton is still relatively young and still has some way to go to fully deliver on the vision. Read more about the current state and outlook.
What's been achieved so far?
We have worked on Acton for years. The first iteration of Acton was essentially a proof of concept where we used Python as the run time for the language with a heavily modified Cassandra database that featured transaction and communication queues for safely storing state. It was tied together by an early version of the Acton compiler, written in Haskell, that took Acton source code as input and produced a Python program which a standard Python interpreter could execute. It would wrap Acton actors in state preserving code that would commit the programs state to the database. This prototype was used to prove the foundational concepts.
Since then we have implemented a new high performance run time system and a new distributed database for backend. Acton code is now compiled to C and then to machine code. The runtime system also features a new lock-free distributed database, written from scratch in C for Acton, making use of efficient optimistic concurrency transaction validation, gossip, bulk updates, integrated communication queues, and several other optimizations that make it fast. The database offers a low level C API for simple but very fast and low latency queries; suitable for building a language run time system on top of! The new run time system in turn is designed to work well together with the database.
The run time system works well standalone too, you don't have to use it together with the distributed database backend. You can use it to write "normal" programs and with native code, it is easy to make small independent programs that are easy to install since there is no need to first install an interpreter.