- 浏览: 39545 次
- 性别:
文章分类
最新评论
-
sunheavenvan:
我觉得不存在提炼出有所谓的本质,提炼的目的是获取较为准确的心智 ...
Jdon007四象图坐标表示 -
yangyi:
好像没有提及Seam给测试和OO设计上带来的便宜,不好意思,还 ...
Seam生命周期 -
buptwhisper:
性能一直是个问题
Seam生命周期 -
sulong:
oojdon 写道如果大家站在Gavin King的角度,包括 ...
Seam生命周期 -
may_cauc:
扬长避短吧,任何一种技术的出现都有其初衷。不要轻易否定,在否定 ...
Seam生命周期
这是axonframework的作者Allard Buijze写的文章,用CQRS来审视架构
banq也做过翻译http://www.jdon.com/jivejdon/thread/37891
Many applications use some form of persistent storage to store its state. However, important information about this state is lost: why is the state as it currently is. Furthermore, a single model is used to store information that is retrieved for many different purposes, often resulting in extremely complex and bog-slow SQL queries. Command Query Responsibility Segregation (CQRS) is an architectural style that makes a clear distinction between commands that change the application state and queries that expose the application state.
My interest in CQRS was triggered when I saw Greg Young explain “State Transitions in Domain-Driven Design” on InfoQ. In this interview, Greg explains how he sees that application would benefit from using separate models for state validation and transition on one side and maintaining a view on the current state on the other. One of the problems that Greg describes is the fact that a single model is often used for different purposes. It is nicely illustrated by the SQL query below. It shows how the model chosen in the application is not suited for the purpose of providing certain information (messages between users, in this case).
Background
queryBuilder.append(
"m.*, " +
"m.origin_participant_id as message_origin_participant_id, " +
"po.first_name as message_origin_participant_first_name, " +
"po.avatar as message_origin_participant_avatar, " +
"po_ua.username as message_origin_participant_username, " +
"CASE WHEN !isnull(po.fieldworker_project_id) THEN 'fieldworker' WHEN !isnull(po_ap.project_id) THEN 'fundraiser' ELSE 'player' END AS message_origin_participant_type, " +
"po.city as message_origin_participant_city, " +
"c.name as message_origin_participant_country, " +
"pd.first_name as message_destination_participant_first_name, " +
"pd.avatar as message_destination_participant_avatar, " +
"pd_ua.username as message_destination_participant_username, " +
"CASE WHEN !isnull(pd.fieldworker_project_id) THEN 'fieldworker' WHEN !isnull(pd_ap.project_id) THEN 'fundraiser' ELSE 'player' END AS message_destination_participant_type, " +
"m.destination_participant_id as message_destination_participant_id " +
"from internal_message m " +
"left join player po on m.origin_participant_id = po.id " +
"left join (select player_id, project_id from ambassador_project where enabled = true group by player_id) po_ap on po_ap.player_id = po.id " +
"left join user_account po_ua on po.user_account_id = po_ua.id " +
"left join country c on po.country_id = c.id " +
"left join player pd on m.destination_participant_id = pd.id " +
"left join (select player_id, project_id from ambassador_project where enabled = true group by player_id) pd_ap on pd_ap.player_id = pd.id " +
"inner join user_account pd_ua on pd.user_account_id = pd_ua.id " +
"where m.destination_participant_id = ? "
);
Wouldn’t it be a lot nice to have a query such as the one below instead?
SELECT * FROM messages WHERE receiving_participant = ?
Achieving such queries is very easy, but doing so without making your model impossible to use for maintaining state integrity and guarding invariants is a lot harder. Well, unless you apply CQRS.
Architecture
The diagram below shows an overview of a typical CQRS architecture.
When a command comes in, it will load an aggregate from the repository and execute certain operations on it. As a result of these operations, the aggregate produces events, which are picked up for storage by the repository and for dispatching by the event bus. The event bus will dispatch each event to all (interested) event handlers. Some of these event handlers will perform actions on other (related) aggregates, some others will update the database tables they manage.
Having handlers update the data in the database means that your tables do not have to be normalized anymore. Instead, CQRS allows you to optimize your tables for the way you want to query them. This makes the data layer processing your queries really simple, and maintainable.
Furthermore, since all state changes are initiated by events, these events become a reliable source for an audit trail. By storing these events, you have an audit trail that you can use to replay the entire application history. Instead of just seeing “current application state” only, you can see all the changes that have led to the current state, providing valuable information trying to find bugs or deal with customer complaints.
Benefits
Matches the natural language used
At first glance, such an architecture might look very complex and over-engineered. However, after taking the first implementation steps, it felt pretty natural. In fact, when you explain the behavior of an application, you use a style that fits CQRS quite nicely: “when an order is approved, we send a confirmation email to the customer”.
Extensibility
Imagine an order management application. With CQRS, you could have an “OrderApproved” event, which is caught by a database updating event handler as well as one that sends an email to the customer with order information. If you later on decide to store the order information in an accounting tool as well, all it takes is adding an event handler that does the accounting integration. And since you can reload historic events as well, you can even reconstruct historic information to put in the accounting table.
Reliable audit trail
As I said above [see section Architecture], the model that is used to process command will generate events. These events are the sole source of state changes for the domain classes. If you want to load an aggregate from persistent storage, it will actually load all the past events of that aggregate. This process is called Event Sourcing. When events become too numerous, you can combine a number of historic events into a single snapshot event. The events that have been combined can then be archived for auditing purposes.
Event Sourcing turns your event storage into an extremely reliable audit trail. The events do no only show what happened and when, but they will also reveal the intention a user had. Not only is it an audit trail that will never move out-of-sync with your application, you can use the audit trail to actually replay all actions in the application. Events are not just a notification of state change, they are also the source of state change.
Transparent distributed processing
When using events as the trigger for state changes, you can easily distribute your application over multiple processing units (servers, JVM’s, whatever). Events can easily be serialized and sent from one server to another over JMS, via the file system or even email. The Spring Integration framework –a messaging framework – fits nicely with the event processing concept.
You could even let certain types of aggregates live on dedicated machines. This allows you to choose different SLA’s for different parts of you application, such as giving order creation a higher priority than sales reporting.
Performance and Scalability
Since event handling is done asynchronously, a user does not have to wait for all changes to be applied. Especially when integrating with external systems, this can improve liveness of an application significantly.
Another aspect of CQRS is that it heavily builds upon BASE (Basic Availability, Soft-state, Eventual consistency) transactions. Although the “eventual” part scares a lot of customers and developers, the price of distributed ACID transactions is one that customer typically resent. In most cases “eventual” is just a matter of several milliseconds. But you’re free to make that seconds, minutes or even hours if your SLA permits it (think of management reports that are only read once a week or month).
Asynchronous analysis
When you build a CQRS style application, all activity in your application is processed using events. This makes it easy to catch these events and monitor them for inconsistent behavior. Event analysis tools like Esper allow you to monitor event streams for patterns that indicate possible fraud.
For example, when you detect that a sudden large number of users has an increased amount of failed login attempts, you could decide to block these accounts for a small period of time. In one of our projects, we use RSA Adaptive Authentication to increase the level of authentication required when someone tries to login on an account that might be the subject of dictionary attacks.
发表评论
-
论继承
2011-09-05 17:37 218继承是现实系统中非常 ... -
Jdon007四象图坐标表示
2011-09-03 11:42 1566http://www.jdon.com/jivejdon/th ... -
面向对象掠影
2011-07-16 22:25 801转自链接:http://www.cnblo ... -
specification 规格模式
2011-02-14 22:57 115MF 和 Evans 发明的模式 -
A comparison of DCI and SOA, in Java_003
2011-02-14 12:43 62DCI和SOA的对照 -
DCI architecture - The Common Sense of Object Orientated Programming
2011-02-14 12:38 77In regular OO, I work with cla ... -
MVC To DCI
2011-02-14 12:29 204MVC to DCI -
DCI in Real World
2011-02-14 12:22 800逃出面向类编程的魔爪,重新思考对象 This is a ... -
DCI之转账简单Example
2011-02-14 11:33 194http://stackoverflow.com/questi ... -
The DCI Architecture
2011-02-14 01:05 1128The DCI Architecture: A ... -
为关系数据库设计对象
2011-02-12 20:36 933这是DDD的原文,我认为最好的结论就是最后加粗 ... -
DDD 概念
2011-02-11 15:22 745来自一个PPT的截图 ... -
UML元素
2011-02-11 14:52 632UML 统一建模语言,它是表达我们OO建模的图形工具,UML图 ... -
DCI and Services (EJB)
2011-02-10 22:38 742http://blog.maxant.co.uk/peb ... -
来自Jdon的DDD总结
2011-02-10 22:31 901http://www.jdon.com/jivejdon/th ... -
DDD设计,为什么我热爱CQRS
2011-02-10 22:25 1466地址是:http://jonathan-oliver.bl ... -
设计模式的脉络
2011-02-10 14:13 697设计模式一般是指GOF那本书引出来的名词,其应该是代码模式,而 ... -
对象设计原则
2011-02-08 00:36 686现在我们面对的是让人 ...
相关推荐
重新思考解决联邦学习中数据异构性的体系结构设计_Rethinking Architecture Design for Tackling Data Heterogeneity in Federated Learning.pdf
Rethinking the Inception Architecture for Computer Vision 重新思考计算机视觉的初始架构 Christian Szegedy, Vincent Vanhoucke, Sergey Ioffe, Jonathon Shlens, Zbigniew Wojna (2015年12月2日提交(v1)...
(过拟合)Rethinking the Inception Architecture for Computer Vision.pdf的论文
Rethinking the Inception Architecture for Computer Vi.pdf
Rethinking Database High Availability with RDMA Networks.pdf 高清完整版
英文原版pdf资料《Statistical Rethinking A Bayesian Course with Examples in R and Stan》
用光谱注意重新思考图形变换器_Rethinking Graph Transformers with Spectral Attention.pdf
Rethinking package的操作文档,rethinking是一个公开的技术文档,这个包是专门用于处理贝叶斯分析使用。
这篇论文貌似有两页格式不大友好,导致翻译软件无法识别,现在提供这部分的中文翻译(我也是自己弄的,质量不一定佳,需者自取)
使用Brms,ggplot2和tidyverse重新进行统计思考:第二版 欢迎我的 的姊妹项目。 我们的目标是翻译McElreath 的代码,使其适合和框架。 当前的0.1.1版本包含所有17章的初稿,这些初稿已编在一起成为一本Bookdown...
Rethinking Productivity in Software Engineering Rethinking Productivity in Software Engineering
Statistical Rethinking A Mostly Bayesian Course in Mostly Non-Bayesian Statistics Richard McElreath 很好的入门资料,学习stan和R不错
Rethinking Text Segmentation数据集太大了,分为两部分上传,合并即可。
重新思考位置编码_Rethinking Positional Encoding.pdf
Rethinking the Heatmap Regression for Bottom-Up Human Pose Estimation 重新思考自下而上人体姿势估计的热图回归
2020-Rethinking Pre-training and Self-training.pdf
这个是行人属性识别框架Rethinking_of_PAR,里面包含了PA100k数据集还有自己训练的PA100K的模型,模型格式为pt格式,此外还有demo.py直接对图片进行推理预测,官方没有提供预训练模型也没有提供对图片预测脚本,这个...
Rethinking Style Transfer From Pixels to Parameterized Brushstrokes 重新思考从像素到参数化笔触的风格转换
EfficientNet论文
使用Brms,ggplot2和tidyverse重新进行统计 我喜欢McElreath的。 然而,我来用Bürkner的偏爱做贝叶斯回归的R.当。 我还更喜欢使用Wickham的绘图,并使用样式的语法(您可能会在或学到)。 因此,该项目试图重新表达...