Service Fabric Reliable Actors and Reliable Services
Note: This is a note to self.
Actors are isolated, single-threaded components that encapsulate both state and behavior. They are similar to .NET objects, so they provide a natural programming model. Every actor is an instance of an actor type, similar to the way a .NET object is an instance of a .NET type. For example, an actor type may implement the functionality of a calculator, and many actors of that type could be distributed on various nodes across a cluster. Each such actor is uniquely identified by an actor ID.
Stateless actors, which are derived from the
StatelessActor base class, do not have any state that is managed by the Actors runtime. Their member variables are preserved throughout their in-memory lifetime, just as with any other .NET type. However, when they are garbage-collected after a period of inactivity, their state is lost. Similarly, the state can be lost due to failovers, which can occur during upgrades or resource-balancing operations, or as the result of failures in the actor process or its hosting node.
class HelloActor : StatelessActor, IHello
public Task SayHello(string greeting)
return Task.FromResult("You said: '" + greeting + "', I say: Hello Actors!");
Stateful actorsStateful actors have a state that needs to be preserved across garbage collections and failovers. They derive from the
TStateis the type of the state that needs to be preserved. The state can be accessed in the actor methods via the
Stateproperty on the base class.The following is an example of a stateful actor accessing the state:class VoicemailBoxActor : StatefulActor<VoicemailBox>, IVoicemailBoxActor
public Task<List<Voicemail>> GetMessagesAsync()
Actor state is preserved across garbage collections and failovers when it’s persisted it on disk and replicated across multiple nodes in the cluster. This means that, as with method arguments and return values, the actor state’s type must be data contract serializable
Actor state providersThe storage and retrieval of the state are provided by an actor state provider. State providers can be configured per actor or for all actors within an assembly by the state provider specific attribute. When an actor is activated, its state is loaded in memory. When an actor method finishes, the Actors runtime automatically saves the modified state by calling a method on the state provider. If failure occurs during the Save operation, the Actors runtime creates a new actor instance and loads the last consistent state from the state provider.By default, stateful actors use the key-value store actor state provider, which is built on the distributed key-value store provided by the Service Fabric platform. For more information, see the topic on state provider choices.
Reliable ServicesReliable Services gives you a simple, powerful, top-level programming model to help you express what is important to your application. With the Reliable Services programming model, you get:
- For stateful services, the Reliable Services programming model allows you to consistently and reliably store your state right inside your service by using Reliable Collections. This is a simple set of highly available collection classes that will be familiar to anyone who has used C# collections. Traditionally, services needed external systems for Reliable state management. With Reliable Collections, you can store your state next to your compute with the same high availability and reliability you’ve come to expect from highly available external stores, and with the additional latency improvements that co-locating the compute and state provide.
- A simple model for running your own code that looks like programming models you are used to. Your code has a well-defined entry point and easily managed lifecycle.
- A pluggable communication model. Use the transport of your choice, such as HTTP with Web API, WebSockets, custom TCP protocols, etc. Reliable Services provide some great out-of-the-box options you can use, or you can provide your own.
What makes Reliable Services different?Reliable Services in Service Fabric is different from services you may have written before. Service Fabric provides reliability, availability, consistency, and scalability.
- Reliability–Your service will stay up even in unreliable environments where your machines may fail or hit network issues.
- Availability–Your service will be reachable and responsive. (This doesn’t mean that you can’t have services that can’t be found or reached from outside.)
- Scalability–Services are decoupled from specific hardware, and they can grow or shrink as necessary through the addition or removal of hardware or virtual resources. Services are easily partitioned (especially in the stateful case) to ensure that independent portions of the service can scale and respond to failures independently. Finally, Service Fabric encourages services to be lightweight by allowing thousands of services to be provisioned within a single process, rather than requiring or dedicating entire OS instances to a single instance of a particular workload.
- Consistency–Any information stored in this service can be guaranteed to be consistent (this applies only to stateful services – more on this later)
Stateless Reliable ServicesA stateless service is one where there is literally no state maintained within the service, or the state that is present is entirely disposable and doesn’t require synchronization, replication, persistence, or high availability.For example, consider a calculator that has no memory and receives all terms and operations to perform at once.
Stateful Reliable ServicesA stateful service is one that must have some portion of state kept consistent and present in order for the service to function. Consider a service that constantly computes a rolling average of some value based on updates it receives. To do this, it must have the current set of incoming requests it needs to process, as well as the current average. Any service that retrieves, processes, and stores information in an external store (such as an Azure blob or table store today) is stateful. It just keeps its state in the external state store.
When to use Reliable Services APIsIf any of the following characterize your application service needs, then you should consider Reliable Services APIs:
- You need to provide application behaviour across multiple units of state (e.g., orders and order line items).
- Your application’s state can be naturally modeled as Reliable Dictionaries and Queues.
- Your state needs to be highly available with low latency access.
- Your application needs to control the concurrency or granularity of transacted operations across one or more Reliable Collections.
- You want to manage the communications or control the partitioning scheme for your service.
- Your code needs a free-threaded runtime environment.
- Your application needs to dynamically create or destroy Reliable Dictionaries or Queues at runtime.
- You need to programmatically control Service Fabric-provided backup and restore features for your service’s state*.
- Your application needs to maintain change history for its units of state*.
- You want to develop or consume third-party-developed, custom state providers*.
Comparing the Reliable Actors API and the Reliable Services API
When to choose Reliable Actors API When to choose Reliable Services API Your problem space involves a large number (1000+) of small, independent units of state and logic. You need to maintain logic across multiple components. You want to work with single-threaded objects that do not require significant external interaction. You want to use Reliable Collections (like .NET Reliable Dictionary and Reliable Queue) to store and manage your state. You want the platform to manage communication for you. You want to manage communication and control the partitioning scheme for your service.
Keep in mind that it is perfectly reasonable to use different frameworks for different services within your app. For instance, you might have a stateful service that aggregates data that is generated by a number of actors.
That’s all for a high level summary.