Actors and Virtual Actors: A Comparison across Akka, Dapr, Orleans, and Service Fabric

Koshy
6 min readApr 1, 2023
actors
Photo by Kyle Head on Unsplash

As the demand for scalable, distributed systems grows, the need for more efficient methods of handling large amounts of data and concurrent requests becomes more pressing. Actors are a popular model for building concurrent and distributed applications. They allow developers to abstract away the complexity of handling shared state and synchronisation by encapsulating application logic in individual units of computation, called actors.

An actor is a computational unit capable of processing messages and maintaining its state. Each actor operates in its own thread of execution, has a unique address and communicates with other actors through asynchronous message passing. When an actor receives a message, it processes it and may send messages to other actors in the system.

This approach offers a high degree of scalability and fault-tolerance.With actors distributed across multiple machines, it can recover from failures independently.

Virtual actors, on the other hand, take the actor model one step further, by adding a layer of indirection between actors and their state storage. Virtual actors are designed to provide a high degree of isolation between actors, which makes it easier to reason about the behaviour of the system. In this model, actors are no longer bound to a specific machine or process, but are instead identified by a unique identifier, and their state is stored in a distributed data store. This allows for even greater scalability and fault-tolerance, since actors can be easily migrated between machines, and can survive machine failures without losing state.

In this article, we’ll compare the actor model and virtual actor model across four popular actor frameworks: Akka, Dapr, Orleans, and Service Fabric.

Akka

Akka is a popular open-source toolkit and runtime for building concurrent and distributed systems using the actor model implemented in Scala. It provides a lightweight, high-performance actor system that can be used to build applications ranging from microservices to large-scale distributed systems. In Akka, actors are organised into hierarchies, with each actor having a parent actor and possibly several child actors. This allows for a high degree of flexibility in the design of the system.

In Akka, actors are implemented as lightweight, thread-safe objects that can be easily created, destroyed, and communicated with. Each actor has a mailbox that receives messages sent to it by other actors, and a message loop that processes those messages one at a time. This approach allows for a high degree of concurrency, since each actor can operate independently of other actors.

Akka also supports clustering, which allows multiple actors to be distributed across multiple machines. In a clustered environment, actors can communicate with each other using either remote messaging or distributed pub/sub messaging. Clustering in Akka enables load balancing and fault tolerance.

However, Akka does not natively support virtual actors. Instead, developers must implement their own virtual actor framework on top of Akka’s actor model.

Akka.NET

Akka and Akka.NET share the same actor model and core concepts. Akka is written using Scala targeting the JVM, while Akka.NET is written in C# targeting the .NET platform and relatively new. A difference worth noting is the configuration mechanism. While Akka uses HOCON (Human-Optimised Config Object Notation), Akka.NET relies on XML.

Dapr

Dapr (Distributed Application Runtime) is an open-source framework for building microservices-based applications. It provides a set of building blocks that can be used to implement common microservices patterns, including service-to-service communication, state management, and event-driven architecture.

Dapr provides a way of defining actors using a declarative syntax, which makes it easy to reason about the behaviour of the system. Internally, Dapr uses a sidecar pattern to manage actors. In Dapr, actors are implemented as stateful services that can be accessed using a standard REST API. Each actor is identified by a unique ID, and its state is stored in a state store, which can be either a distributed database or a key-value store. This approach allows for a high degree of scalability and fault-tolerance, since actors can be easily migrated between machines, and can survive machine failures without losing state.

Dapr also supports distributed pub/sub messaging, which allows actors to communicate with each other without knowing each other’s location or network address.

Orleans

Orleans is an open-source framework for building distributed and high-scale applications using the virtual actor model. It provides a runtime environment that abstracts away the complexity of distributed computing, and allows developers to focus on writing business logic instead of dealing with low-level details.

In Orleans, actors are implemented as virtual objects that can be accessed using a standard API. Each actor is identified by a unique ID, and its state is stored in a distributed database, such as Azure Cosmos DB or Redis. This allows for a high degree of scalability and fault-tolerance, since actors can be easily migrated between machines, and can survive machine failures without losing state.

Orleans uses a hierarchical system for organising actors, with each actor having a unique identity and being able to communicate with other actors in the system. Orlean intrinsically support virtual actors too.

Service Fabric

Service Fabric is another framework that provides support for actors. Service Fabric is a distributed systems platform that provides a highly scalable runtime for hosting microservices, containers, and other types of applications. Service Fabric provides a way of defining actors using a programming model that is based on the actor model. This makes it easy to write highly concurrent, distributed systems that can scale to handle large amounts of data and traffic.

Supports both stateful and stateless actors, with stateful actors being able to store their state in reliable collections that are intrinsically highly available and distributed. Supports both single-machine and multi-machine deployments, with built-in support for load balancing and failover.

Transactions support.

When it comes to applying transactions in distributed actor systems like Akka.net, Dapr, Service Fabric, or Orleans, there are different approaches and trade-offs to consider.

Akka.net uses the At-Least-Once Delivery (ALOD) approach for message delivery. This means that if a message is not acknowledged by the receiving actor, it is retried until it is acknowledged or until a maximum number of retries is reached. Akka.net also supports the use of the distributed data tool called Akka.Cluster.Sharding, which provides automatic routing of messages to the correct actors and automatic rebalancing of actor instances across nodes.

Dapr, on the other hand, provides several building blocks for distributed applications, including actors, state management, and pub/sub messaging. Dapr provides transactional consistency guarantees for state management and pub/sub messaging by leveraging underlying state stores and message brokers that support transactions.

Service Fabric supports the use of Reliable Actors, which are built on top of Reliable Services and Reliable Collections. Reliable Actors provide a programming model that is similar to Akka.net actors, and they also support transactional consistency guarantees through the use of Reliable Collections.

Orleans provides a programming model that is based on the concept of virtual actors, which are implemented as stateful objects that are activated on demand. Orleans provides transactional consistency guarantees through the use of transactions in the underlying storage system.

Conclusion

In conclusion, actors and virtual actors are powerful abstractions for building highly scalable, distributed systems. Akka is a good choice for building scalable, concurrent systems, particularly those that involve clustering. Orleans is a good choice for building distributed and high-scale applications that require virtual actors, with a focus on ease of use and abstraction of low-level details. Service Fabric is a good choice for building distributed systems that require both stateful and stateless actors, with built-in support for load balancing and failover.

Dapr’s focus on microservices and its lightweight nature make it a good fit for applications that require flexibility, scalability, and fault-tolerance. Its support for distributed state management and pub/sub messaging make it a good choice for applications that require asynchronous communication and processing. However, if your application requires more advanced features, such as virtual actors or advanced clustering, Dapr might not be the right choice.

It is possible to use any of these actor frameworks to implement transactional consistency guarantees in a distributed system. However, the approach and trade-offs will differ depending on the specific requirements of the application. For example, Akka.net’s ALOD approach is suitable for applications that can tolerate some degree of message duplication, whereas Dapr’s transactional consistency guarantees are more suitable for applications that require strict consistency guarantees. Similarly, the programming model and performance characteristics of each framework may influence the choice of framework for a particular application.

Stackademic

Thank you for reading until the end. Before you go:

  • Please consider clapping and following the writer! 👏
  • Follow us on Twitter(X), LinkedIn, and YouTube.
  • Visit Stackademic.com to find out more about how we are democratizing free programming education around the world.

--

--

Koshy

A versatile software engineer, he has a range of interests beyond coding. Earlier posts are here : https://devwaves.blogspot.com/