Skip to main content

How Can Reading in Event Sourcing Be Optimized Through CQRS

Patrick Stadler 3 min read
How Can Reading in Event Sourcing Be Optimized Through CQRS

Command Query Responsibility Segregation (CQRS) and Event Sourcing are often presented as dependent on each other. However, the concepts can be used independently. Nevertheless, the properties of CQRS and Event Sourcing support each other. In the last blog post, “Event Sourcing” was introduced. In this second part, we look at how the read side can be optimized with CQRS. To demonstrate the advantages and properties of CQRS, the CAP theorem should first be considered.

The CAP theorem consists of Consistency, Availability, and Partition Tolerance. The CAP theorem states that a distributed system cannot satisfy more than 2 of these points simultaneously. The points can be explained as follows:

  1. Consistency describes the fact that the service should deliver the correct answer to every request.
  2. Availability requires that the service always delivers a response. The time needed for a response can be disregarded.
  3. Partition Tolerance represents more of a property of the underlying system. It must be tolerant of server failures and message loss.

The points defined by the CAP theorem should be interpreted gradually. Therefore, CQRS introduces the term Eventually Consistent. This describes that consistency ultimately always exists, but a short period can occur when an old state of the system is returned. This can make it appear to an external observer that the system fulfills all three points of the CAP theorem. The structure of an example system based on the CQRS concept can be seen in the following figure. The client sends write commands to the Write Model, which converts the commands into events, as explained in the last post about Event Sourcing. These are then persisted in write-side storage, and simultaneously the read side Read Model is informed about the event via a reliable message transmission path. When the client makes a request, the read side responds with the data it currently has. This means consistency between the read and write sides cannot be guaranteed at all times. However, eventual consistency can be guaranteed.

On github, we have extended the example from the Event Sourcing post with this functionality in the “cqrs” branch.

The application contains an actor system. A RootActor creates an AccountSupervisor actor and a CommandBot actor within it. The AccountSupervisor in turn creates the actors of the individual accounts that represent the accounts. The CommandBot sends a random number of commands to the accounts. The commands are then converted into events and stored in the event history of the respective actor. The state of the actor, or in other words the account balance, changes according to the events. The changes from the Event Sourcing application are as follows:

  • The Account actors send their events to the ReadSide actors.
  • The CommandBot actor no longer reads from the Account actors, but only through the ReadSide actors.

The ReadSide actors aggregate the events. For example, a sum of all MoneyDeposits is provided. This is not possible without workarounds in a pure Event Sourcing application. This application is not intended for production use, but only to make the principles easier to demonstrate and explain. There, the ReadSide actors should persist their aggregated data in any database system. Likewise, the event journals of the Account actors should preferably be stored in a NoSQL database.

Akka-Persistence as an extension for Akka provides the functionalities to develop an Event Sourcing and CQRS application for production use. Various plugins for different database systems are available for Akka-Persistence. Google Cloud Datastore offers itself as a highly available, cost-effective, and highly scalable NoSQL database. A plugin for integration into Akka-Persistence is available on the innFactory Github page. https://github.com/innFactory/akka-persistence-gcp-datastore

Written by Patrick Stadler Software Developer

Software Developer bei innFactory mit Expertise in Backend-Entwicklung und Cloud-Architekturen.