The Axon Platform offers an innovative and powerful way of sensibly evolving to event-driven microservices. The platform has roots in the well established CQRS (Command Query Responsibility Segregation) and Event Sourcing design patterns as well as the DDD (Domain-Driven Design) architecture paradigm. The Open Source Java Axon Framework is the core of the platform and a starting point for most of our customers.
CQRS and Event Sourcing
The Axon Framework started its life as a library for implementing the CQRS and Event Sourcing patterns in a DDD application.
CQRS describes a way of developing applications that cleanly separate making changes to the application from simply querying the application. This typically results in two separate sets of application models and data sources - the write side and the read side. The read side is populated by the write side typically through events. There are a number of key reasons for implementing this pattern:
- The write side is optimized for changing the state of the application through commands that make sense to a business user. Application state is modeled through DDD aggregates. The read side is highly optimized for querying, resulting in a model that avoids complex queries and maximizes query performance. The read model is typically just DTOs (Data Transfer Objects) per screen. Focusing the write and read sides tends to result in simpler code in both models that would otherwise we combined in a single more complex model that serves both functions.
- The read and write models can be scaled independently, as separate deployments units with dedicated capacity when needed. This is especially important for applications that have high scalability requirements for the read side.
- The read and write sides can use the data storage that makes the best sense for each concern. With the Axon Platform the write side will typically be implemented utilizing Event Sourcing (with perhaps AxonDB) and the read side can be implemented using a relational database or NoSQL data store.
Event Sourcing is a specialized pattern for data storage. Instead of storing the current state for an entity, every change of state is stored as a separate event that makes sense to a business user. The current state is calculated by applying all events that changed the state of an entity. In terms of CQRS, the events stored are the results of executing a command against an aggregate on the write side. The event store also transmits events that it saves. The read side can process these events and builds the targeted data sets it needs for queries. There are a number of key reasons for implementing this pattern:
- The events stored become a complete audit trail for changes made to the application. For this reason, Event Sourcing is traditionally implemented by applications with strong auditing needs. A strong audit trail also makes debugging easier.
- Because every event is stored, it is possible to create reports at any time that you may not have foreseen. These reports can even tell you what happened during a specific point in time in the past. This can include applying ad-hoc analytics to the data, including using AI algorithms. For similar reasons, you can flexibility change the read side of the application as well as integrate with new external systems that you did not foresee.
- Because event sourcing means only adding new data to a store, writes are as fast as possible. Because the read models are populated typically through eventual consistency, locking overhead is minimized.
As you can see, Event Sourcing and CQRS is very closely related and indeed enable each other. The Axon Framework makes it possible to implement Event Sourcing and CQRS with minimal boilerplate code and a proven, battle tested library. The framework provides APIs for easily writing commands, event-sourced aggregates, command handlers, events, event handlers, queries and query handlers.
Evolutionary Event-Driven Microservices
While Axon is rooted in CQRS and Event Sourcing, the platform has a unique value proposition in enabling an innovative evolutionary approach to developing event-driven microservices.
As valuable as the CQRS and Event Sourcing patterns are, in an application that has a high likelihood of remaining a monolith, they are applied in key parts of the application rather than throughout the application. Indeed by default Axon assumes all components are in the same JVM.
However, a key characteristic for Axon is location transparency. If commands, aggregates, command handlers, events, event handlers, queries and query handlers need to be on separate JVMs and typically clustered (perhaps via AxonHub), Axon allows you to make changes only to configuration to make this happen. This is because CQRS and Event Sourcing naturally result in code to be highly decoupled via messages, lending itself to location transparency. What this means is that an Axon application can begin its life as a monolith and be very easily broken up into microservices when needed. Furthermore, the Axon command, event and query buses that facilitate communication can be completely remote and asynchronous just by switching configuration. This asynchronous, event-driven approach to microservices is more loosely coupled, flexible, reliable and scalable as compared with synchronous, typically REST centric approaches to microservices. As long as a majority of the application is developed using CQRS, Event Sourcing and Axon, they can be broken up into arbitrary parts at will, resulting in the finest grain microservices possible if desired (for example to maximize scalability and minimize deployment time for each microservice). Each aggregate entity can even reside in its own isolated microservice and communicate through commands and events.
CQS and Microservices
Implementing CQRS and Event Sourcing throughout the application to maximize evolutionary event-driven microservices flexibility may not be an option for many teams. The approach requires a certain amount of skill, discipline and initial investment. Indeed many teams may have already made the decision to implement microservices and aware of where their service boundaries or DDD bounded context lies. Indeed such applications may not even have a significant need for Event Sourcing.
Such teams can still take advantage of the Axon Platform to realize the benefits of loosely-coupled, asynchronous, event-driven microservices. This technique applies the CQS (Command-Query Separation) pattern to microservices (as you may guess from the naming, the CQRS and CQS patterns share origins). The CQS pattern observes that most application invocations can be categorized as commands or queries, but not both. Following this pattern, all interactions between microservices (perhaps deployed as separate DDD bounded contexts) can be modeled as commands, queries and events managed by the Axon Platform. Axon does not require the use of CQRS or Event Sourcing to implement microservices communication in this way. Internally each microservice is free to implement largely a CRUD style, non-CQRS application model using non event-sourced persistence. Modeling the messages between microservices using CQS still provides better semantic meaning, clarity and simplicity.
Integration Events, Event Sourcing and Microservices
Some teams may have chosen to adopt synchronous, REST based microservices as their principal paradigm. There are important cases where such teams can use the Axon Platform to synchronize distributed data using Integration Events and Event Sourcing.
A common problem in microservices is key data owned by a single microservice but shared across multiple microservices in one form or the other. A highly scalable, flexible and reliable way of synchronizing this data is using Event Sourcing, Integration Events, eventual consistency and Axon. In this technique, the microservice that owns the data uses Event Sourcing to store the data as well as notify all other interested microservices of all changes to the data through DDD Integration Events. An Integration Event is effectively a change in state in a single DDD bounded context (or microservice) that other bounded contexts (or microservices) should react to. Event listeners in interested microservices will process the sourced events and update what is effectively internal read models of the data that interests them. This is also a useful technique for incrementally breaking up an existing monolith.
Sign up for our newsletter
monthly updates about new product releases and invitations to AxonIQ events