欢迎光临汤雪华的博客

一个人一辈子能坚持做好一件事情就够了!坚持是一种刻意的练习,不断寻找缺点突破缺点的过程,而不是重复做某件事情。
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

CQRS架构介绍

Posted on 2012-02-12 13:49  netfocus  阅读(6642)  评论(6编辑  收藏  举报

CQRS on itself is a very simple pattern. It only describes that the component of an application that processes commands should be separated from the component that processes queries. Although this separation is very simple on itself, it provides a number of very powerful features when combined with other patterns.

The diagrams below show an example of an extended layout of a CQRS-based event driven architecture. The UI component, displayed on the left, interacts with the rest of the application in two ways: it sends commands to the application (shown in the top section), and it queries the application for information (shown in the bottom section).

 

Command handling

The user interface sends commands to make changes to the system. Commands are simple object that contain all the data needed to perform the underlying action. An example of the command could be MoveUserToNewAddress. The command should hold the new address for the user and the user id that indicates which user has moved.

Commands also tent to express intent by there name. For example, although the command MoveUserToNewAddress andCorrectAddressForUser both contain the same data – the address and the user id – the intent is definitely different.

All commands are send to a Command Service. This service receives the commands and routes them to the corresponding command handlers. Command handlers should not contain any business logic. The only thing they do is making changes to aggregate roots from the domain and makes changes to them.

The domain

The command handler retrieves domain objects (Aggregates) from a repository and executes methods on them to change their state. All business logic is captured within these objects and is not used for querying. This allows us to optimize this model for behavior.

Aggregate roots contain the actual business logic and are  responsible for guarding their own invariants. State changes on aggregate roots cause domain events to occur. This sequence of domain events represents all the changes that has been made. This pattern is called event sourcing. Both the Domain Events and the Aggregates form the domain model.
 

The domain events

All state changes in the domain are represented by domain events. They are simple object that contain all data related to the change. We gave two examples of command names. The events that are related to the state change of these commands will be UserMovedToNewAddress and AddressCorrectedForUser. Notice that the names are in the past tense.

The Repository

The repository act as a in-memory aggregate collection. The repository allow us to get a single aggregate by the aggregate id or save a single aggregate root into it. Getting an aggregate root is done by getting all its related events and replaying them to build up the aggregate root into the latest state. Saving an aggregate root will result in persisting all its uncommitted events that occurred while making change to it. The events are stored in the event store and when an aggregate root is saved, all the events will also be published to the event listeners.

The event store

All events that have occurred end up in the event store. It contains all the event that represents the state changes in the system. These can be used to build up the current state by replaying them all. This store can also be used to fill up new or repair existing read model.

The event bus

When an aggregate root is saved via the repository all the uncommitted events that represent the state changes that has been made are persisted into the event store. Beside that, the repository also publish these events via the event bus. This bus publishes it to event listener that has registered itself as one being interested in the events. An important choice to make is whether the bus publishes the events to the subscribers in a synchronous or asynchronous way.

Synchronous means that the event handling that is done by the subscribers blocks the current execution and that this waits for all subscribers to complete before returning to the user. This model is simple and is a sensible default.

Asynchronous would not wait for all subscribers to complete before returning to the user. It will drop the event on the bus and return to the user. This will keep the execution of command fast, but introduces eventual consistency. The read models will be consistent at some point of time.

The event handlers

There are different event handlers subscribed to the events bus. The most common one are denormalizers. These event handlers take events and makes changes to the read model based on them. For example, a denormalizer could update the users address in the user table based on the data in the UserMovedToNewAddress event. But it could also update the total number of users in city X based on that the same event.

Event handlers are not only interesting to keep the read model up to date. But they could also be written to make changes to an external system or send warning email to the business when certain event occur. It could also be that an event handler issues a new command . Event handlers are great components to extent the system with new functionality without making changes in it.

Read models

An important part of every application is data. Most of the screen in an user interface request it. But every screen just tents to have a different view on the data. For example, one wants all the products with there name, price and category, while another wants the products with there name and top 3 latest product review score and name of the reviewer.

Read models are models that can be optimized for data querying. And what is a optimal query? That is a query that just queries the data from one source. In other words: select * from x where y. No joining, just give me the data. We can accomplish this by creating one table per view. So that every view can just request data by a simple query.

Your read model doesn’t even have to be a relational database, it could be a document based database that contains a collection for every view.