Before developing your first service, it will help to understand how Akka Serverless manages state for your services. You may be accustomed to programming for a traditional architecture where an application tier invokes a database tier to retrieve and manipulate state. This approach imposes stringent requirements on you:
to be aware of the datastore—its location and its behavior—and include logic for connecting and communicating with it.
to be responsible for handling errors associated with managing state—infrastructure level failures as well as domain level errors such as concurrent updates and transactions.
With Akka Serverless, data access and error handling are the domain of the state management system. Your code does not manage database connections or transactional concerns, such as concurrent updates, caching, sharding (distributing across nodes), and routing. Akka Serverless does all of that for you and supplies the state your services need at the proper time. This simplifies your code. After deployment, the way in which Akka Serverless handles state avoids contention for resources and supports scaling and failover—in short, resulting in an elastic and resilient reactive system.
Akka Serverless also support stateless actions.
To gain the benefits of Akka Serverless data management, you need to understand its programming model. You specify service interfaces in a gRPC descriptor that defines any actions as well as data types and supported operations for entities. You are responsible for implementing the actions and Entities that perform business logic.
The following diagram illustrates how these components of an Akka Serverless system work together at runtime.
Entities have the following attributes:
A state model that determines how Akka Serverless stores data. Value Entities update in place, similar to the CRUD model. Event Sourced Entities persist each change in state to a log than can be used to replay events.
At runtime, a key distinguishes each Entity instance from all others. The key can be multi-part, consisting of multiple items. Similar to an address, the key must be unique:
Data items store the Entity’s state:
Entities encapsulate domain logic:
Operations on Entities, which come in the form of commands, can change state.
When an Entity receives a command, they already have everything they need to handle that request.
For example, you might create a
Home service that manages a
House Entity. It needs a unique identifier such as a house
id, which might include
phone number. It will have have other data items such as
visitors. It has operations that can change its state such as adding or removing a
resident. It can refer to other Entities. And it can contain sets of other data, such as when a
resident has multiple
Value Entities support the familiar CRUD (Create, Read, Update, Delete) model of relational databases. Value Entities only persist the current state—unlike Event Sourced Entities, which persist all events that resulted in the current state. You may find Value Entities more straight forward to implement because you do not have to think about events. However, you lose some advantages of Event Sourcing, such as being able to determine the state of an Entity at any point in time.
Event-sourcing is a Reactive technique for managing data in a distributed system. It involves capturing changes to data, as opposed to overwriting existing values. For example, a bank tracks account debits and credits, rather than just recording the balance change. In case of an audit, a bank can reliably point to each transaction that led to the current balance. Similarly, in an event-sourcing system, the changes to data can be replayed in the case of failure or of spinning up new services to handle load.
Akka Serverless Event Sourced Entities store events in a journal. Different services can start reading the journal at different points. This results in what is called "eventual consistency". When all interested parties have read all the entries, the system is consistent—they all have the latest data. Before that, some parties might be behind for a short time, but they are guaranteed to catch up.
When designing Event Sourced Entities, you will want to use techniques for architectures that support that style of isolation. A technique called Event-Storming, for instance, helps develop the definition of the events your system will need as a first-class item.
At runtime, Akka Serverless will create and manage the lifecycle of an Entity’s instances. Under the covers, Akka Serverless uses clustering and cluster-sharding to provide Reactive benefits for your services:
Clustering in a distributed system allows components to be aware of each other and co-operate to achieve a specific outcome. A cluster works together to provide reliability and to manage its own membership. If a member of the cluster fails, new members can be added to replace them. Akka Serverless handles clustering, you get the benefits automatically.
Cluster-sharding divides data amongst members of a cluster. Akka Serverless uses a key element to separate responsibility. For example, orders in a shopping system might be distributed according to the zip code of the ship-to address. All orders for 3399 would go to one specific instance of a service that handles Florida, others would go to the service that handles Montana, and so forth. Cluster-sharding, done correctly, ensures that your data is fairly evenly distributed across the various parts of your system, and not unevenly burdening only a few instances, while others sit idle. Akka Serverless handles cluster-sharding for you entirely—you get the advantages of your data being local to your services without the work.