- 浏览: 160842 次
- 来自: ...
文章分类
- 全部博客 (151)
- Liferay.in.Action (3)
- 集群 (12)
- web (5)
- jna (2)
- 数据库 (7)
- Terracotta (11)
- xml (1)
- Hibernate (3)
- Jdbc (2)
- DDD (10)
- nosql (7)
- 云存储 (3)
- 云产品 (7)
- 云计算 (26)
- Hadoop (11)
- 虚拟化 (5)
- REST (3)
- 程序人生 (11)
- google (2)
- 安全应用 (5)
- LDAP (0)
- 安全技术 (5)
- android (4)
- 网络妙语 (1)
- HTML5 (1)
- 搜索引擎 (1)
- 架构设计 (5)
- redis (3)
- Cassandra (2)
最新评论
-
liwanfeng:
情况是这样的,你的文件我觉得还是比较小,我现在需要处理的XML ...
dom4j处理大文件
原文 http://www.jdon.com/jivejdon/thread/37891
命令查询的责任分离Command Query Responsibility Segregation (简称CQRS)模式是一种架构体系模式,能够使改变模型的状态的命令和模型状态的查询实现分离。这属于DDD
应用领域的一个模式,主要解决DDD
在数据库报表输出上处理方式。
来自Rethinking architecture with CQRS
一文对CQRS进行详细描述。
很多应用都需要持久层保存状态,因为这些状态不能丢失,如果只是放在内存中,而不是持久到磁盘上。状态是在领域模型中,每当模型保存到数据库以后,会有更多复杂的查询,都是使用复杂且慢的SQL语句实现的。比如如下复杂SQL语句:
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 = ? "
);
如此复杂的SQL语句为什么不能用一句简单SQL完成呢?
SELECT * FROM messages WHERE receiving_participant = ?
如果你要这么做,就必须使用到CQRS模式。
Greg Young在infoQ的采访中“State Transitions in Domain-Driven Design
”谈到了CQRS,Greg 解释了把领域模型分为两种:状态校验,以及状态转换,维持当前状态的一个视图。
CQRS架构如下图:
在客户端就将数据的新增修改删除等动作和查询进行分离,前者称为Command,走Command bus进入Domain对模型进行操作,而查询则从另外一条路径直接对数据进行操作,比如报表输出等。
当
一个Command进来时,从仓储Repository加载一个聚合aggregate对象群,然后执行其方法和行为。这样,会激发聚合对象群产生一个事
件,这个事件可以分发给仓储Repository,或者分发给Event
Bus事件总线,比如JavaEE的消息总线等等。事件总线将再次激活所有监听本事件的处理者。当然一些处理者会执行其他聚合对象群的操作,包括数据库的
更新。
因为领域对象操作和数据库保存持久这两个动作分离,因此,数据表结构可以和领域对象松耦合(JiveJdon源码可展示领域对象和数据表不再是一对一对应依赖,这也是使用Hibernate 等ORM框架容易造成的问题),你可以优化数据表结构专门用于查询。
再
者,由于事件驱动了领域模型的状态改变,如果你记录这些事件audit
,将可以将一些用户操作进行回放,从而找到重要状态改变的轨迹,而不是单纯只能依靠数据表字段显示当前状态,至于这些当前状态怎么来的,你无法得知。当你
从数据库中获得聚合体时,可以将相关的事件也取出来,这些叫Event
Sourcing,事件源虽然没有何时何地发生,但是可以清楚说明用户操作的意图。
虽然这种架构有些复杂,但是好处却很多,主要的是实现
透明的分布式处理Transparent distributed
processing,当使用事件作为状态改变的引擎时,你可以通过实现多任务并发处理,比如通过JVM并行计算或事件消息总线机制,事件能够很容易序列
化,并在多个服务器之间传送,(EJB提倡贫血失血模型,实际就是为解决胖模型在多个服务器之间传送时序列化耗费性能,现在我们不序列化模型,而是改变模
型数据的事件)。
你可以让聚合体(胖模型)一直驻留在特定服务器中,这样可以为不同的应用选择不同的SLA。
由于事件处理是异步
的,用户就不必等待所有操作完成(同步则是所有操作完成后才返回操作结果界面给用户,异步架构符合Jdon一直提倡的异步
架构),CQRS实际可以利用BASE原理(CAP定律和BASE思想
),实现最终一致,取得高可伸缩性
,尽管最终一致使很多程序员有些恐慌,但是分布式ACID 事务
却也让他们产生怨恨,其实最终一致其实最多是几个毫秒的延迟,但是你可以充分利用这几秒的延迟做更多事情。
当你使用异步
事件模式以后,可以使用Esper 等EDA工具进行事件拦截和分析,该文作者就是利用它实现 RSA Adaptive Authentication
用户登录后的授权处理。
最后该文作者推荐了一个基于Spring的CQRS的框架cqrs4j
,这个框架是5天前刚刚推出,不过了解Jdonframework
的人也许知道,Jdon框架6.2也是可以实现CQRS,不过是在同年11月上架的,且不谈两个框架比较,单理念上Jdonframework
是世界同步的,说明世界不同角落里人都想到同一个问题了,本文很多理念其实在J道网站已经倡导多时,并且通过Jdonframework
的Domain Events + 异步
实现了。
相关CQRS 讨论
这篇文章其实提出了一个颠覆性的概念:分布式系统之间传输事件,把事件作为数据进行分布,当然也可以把事件作为key-value存储的数据。
目前EJB
标准JavaEE6等都明显落后了,透明化out-of-box分布式架构是一个趋势。
这个概念和EJB
提
出的将实体数据在服务器之间传输完全相反,所以,EJB才积极倡导失血模型,就是模型没有方法(只有setter/getter方法),只有字段数据,没
有行为,就是不能太胖,否则序列化性能就很差,但是没有行为的模型能称为对象模型吗?就像人失去血液能活吗?所以,失血模型是严重违背OO
的,但是因为EJB
把持着实现市场,所以,连同关系数据库编程思路,误导了一代程序员。
Spring
作为另外一个实现市场,虽然Spring
3.0出来了,但是由于其只对组件技术架构实现支持,对模型实体不闻不问(由Hibernate掌管),没有解决模型事件和技术组件架构之间的通讯联系方
式,结果,导致大部分程序员使用SSH或S2SH时,只是由服务触发模型,模型无法再触发其他服务或组件(模型最后成为事件最后终点站,这也是失血模型的
一个特点,数据是被驱动的,但是模型对象不是数据,模型对象有行为,必须可以发出事件驱动其他),或者将服务或组件直接注射到模型中,导致业务模型和技术
架构多点耦合。
以上矛盾也体现了EDA架构和所谓SOA架构的冲突所在。
作为一个好的框架,不对模型进行in-memory支持,而是通过Hibernate的二级缓存
ehcache绕道实现,这是当前Spring+Hibernate(SSH或S2SH)的最大问题所在。另外Hibernate其实是将领域模型和关系数据库进行捆绑,反而让领域模型丧失了其为需求服务的自由,比如异步
加载,即用即取lazy load等等。
所以,从DDD
要求出发,一定要有一个综合将实体模型和服务组件技术架构合起来考虑的框架,比如Qi4j或Jdonframework
,Spring + Hibernate这种分离思路其实是沿袭了EJB
的Session Bean + Entity Bean/JPA思路,这种思路离DDD
要求实在太远,可以看成是模型的汇编语言了。
hibernate JPA等ORM框架由于将关系数据表和实体对象绑定,如果我们直接将这个实体对象作为领域模型的实体(如果不是,系统中有两种实体对象,增加复杂性),那么无疑无法进行查询和命令(比如模型的修改)的分离,也就是是反CQRS模式。
CQRS
和关系数据库的读写分离策略也是相似的,查询是读,而状态修改一般是写,CQRS允许我们为查询优化数据表结构,因为对象领域模型的存储,数据表结构是无
所谓的,但是如果你使用Hibernate/JPA等ORM框架,就很难实现为查询优化数据表结构,因为ORM框架绑定领域模型和数据表。
这里是一个DDD
的Domain Driven Design PPT
,也谈到了CQRS,也称CQS架构,很不错。
下面这张图也是CQS架构图:
[该贴被banq于2009-12-29 11:35修改过]
这里有两种一致性,一个用户界面数据的一致性,还有一个是你说的数据库数据的一致性。
我们通常比较关心的是前者,至于你说的后者,技术上完全没有问题了,比如采取Key-values存储作为数据库即可。
关于是否有实践,你发言的这个论坛就是使用这种架构,因为Jdonframework
就是根据这种原理开发的。至于其他大型实践架构,实际可以参看NoSQL
实践,两者一致的,NOSQL大型实践案例包括EBay Facebook twitter linkedin等世界排名前茅的网站。
关于CQRS,是greg young通过实践提出的,见INFOQ他的访谈录
,谈他的一个实践CQRS心得。
我简短翻译一下他的访谈录(顺便发牢骚:infoQ中国版编辑不知在做什么,这篇重要文章没有翻译?):
greg young当前工作在温哥华的IMIS, British Columbia. 我们开发一个算法交易系统,目前运行在全世界各大交易所,我当前是CTO,大部分时间是关注整体架构。
我们的领域模型是内存模型(in-memory model),代表市场中股票当前状态,我们所有业务策略都运行在这个领域模型中,我们选择领域驱动设计DDD
其实相当不寻常的,对于那些不熟悉的人来说,性能是第一,当你每秒处理20,000消息,...你通常关注可伸缩性
scalability, 低延迟low latency, 但是我们觉得代码的可理解性很重要,我们选择OO
编程可以让我们更加适应变化。
我去年QCon演讲过,我们的实践和经典理论的DDD
区别是:我们实体对象中封装的是可改变的状态,例如:volume-traded 命令是删除我们模型中的volume. 这其实产生一个事件,导致我们领域中的状态发生变化(banq注:典型的状态模式)
这
样非常有用,我们就不必在领域之外再进行状态持久保存,我们只有状态的切换,我们能获取这些状态切换事件,然后传到其他场景bounded
contexts(DDD定义的绑定场景),
而在其他场景当前状态或当前状态的镜像能以不同方式建立和显示,这种情况很普遍,事务系统是以一种方式看数据,而报表系统则以另外不同方式看系统(命令查
询分离 CQRS)
相比围绕数据库的正常传统方式,他们就很象以一种非正常化的方式处理数据,通过将切换事件保存到事件流中,你就可以在
这第一个模型中做你任何传统正常化方式可以做的任何事情,在事件流的另外一边(监听者)有了第二个模型,它是以非正常化呈现,最好的方式是在他们之间建立
一个桥,这比通常同步性质的直接调用要好多,而且更加可伸缩性
。
下面是greg young关于DDD
实践的一些体会,太长,啃原文吧。
发表评论
-
Domain Events异步应用-2
2010-11-03 22:43 992原文 http://www.jdon.com/jive ... -
Domain Events异步应用-1
2010-11-03 22:38 975原文 http://www.jdon.com/jive ... -
Domain Events – 救世主
2010-11-03 22:34 972原文 http://www.jdon.com/jivejdon ... -
DDD的革命: CQRS和Event Sourcing
2010-11-03 22:19 1318原文 http://www.jdon.com/jivejdon ... -
架构的演化和不断新兴的设计
2010-11-03 22:14 883原文 http://www.jdon.com/jivejdon ... -
浅谈领域驱动设计
2010-10-21 22:46 733原文 http://www.blogjava.ne ... -
对领域驱动设计的初步认识(三)
2010-10-21 21:52 1046原文 http://www.jdon.com/ji ... -
对领域驱动设计的初步认识(一)
2010-10-21 21:50 865原文 http://www.jdon.com/ji ... -
对领域驱动设计的初步认识(二)
2010-10-21 21:46 858原文 http://www.jdon.com/jivejdon ...
相关推荐
在这个过程中,需要考虑如何有效地记录状态的变化,包括使用事件溯源等技术。 **4. 设计读模型** 读模型则是针对查询优化的,它可以从写模型中获取数据并转换成更易于查询的形式。这通常涉及到缓存机制的设计,以...
第1章我们的领域: 会议管理系统1 1.1Contoso公司简介1 1.2谁与我们同行2 1.3Contoso会议管理系统3 ...8.2.8重新考虑用户界面193 8.2.9探索事件源的其他用处193 8.2.10探索有界上下文的集成问题193 8.3更多信息194
的Sourcerer是使用事件采购在Java中8实施CQRS架构的自以为是,功能,和存储不可知框架。 Sourcerer固执己见 Sourcerer是一个框架,它支持CQRS / ES架构中使用的一组核心概念,并且对这些构建基块是什么以及如何实现...
- 安全性考虑:设计时应考虑数据保护、身份验证和授权机制。 5. **解决实际问题** - 性能优化:通过负载均衡、数据库优化等手段提高系统性能。 - 可扩展性设计:采用横向扩展或纵向扩展策略,适应未来需求增长。...
Haskell的CQRS介绍这是CQRS + ES架构模式的Haskell实现。 它结合了两种模式,每种模式本身都具有强大的功能,但是它们的组合却成倍地强大。 第一种模式是命令查询责任隔离(CQRS),它用于将应用程序中进行写或更新...
CQRS通过将数据的读取(Query)模型和修改(Command)模型分离,使得每个模型可以独立设计和优化,从而简化系统架构,提高性能。 **CQRS的优势** 1. **提升性能**:读模型和写模型可以独立优化,例如读模型可以...
本文档主要介绍了如何利用OAuth2在基于Akka-CQRS-Http架构的系统中实现资源使用授权。 #### 二、背景 在前文中,我们已经探讨了SSL/TLS安全连接的重要性,这是一种在通信层面实现数据加密的技术方案。然而,仅仅...
4. **架构风格**:不同的应用场景对应不同的架构风格,如互联网应用常采用CQRS(命令查询责任分离)和Event Sourcing,而实时系统可能需要采用反应式架构。 5. **架构评估与演进**:软件架构不是一成不变的,随着...
5. **数据管理**:在微服务架构中,数据库通常被拆分为多个服务专属的数据库,这需要考虑如何处理跨服务的数据一致性,例如使用事件驱动架构和CQRS(命令查询责任分离)。 6. **容错与弹性**:服务需要设计成健壮的...
在实践微服务之前,团队需要考虑以下几个因素:现有的软件架构是否已具备服务化基础、团队的敏捷开发和DevOps能力、架构设计能力、数据库管理策略以及运维支持。对于初涉微服务的团队,推荐从MiniService开始,这是...
9. **架构模式与最佳实践**:文档可能介绍了各种经过验证的架构模式,如SOA(面向服务架构)、CQRS(命令查询职责分离)等,并提供了实施这些模式的最佳实践。 10. **决策框架**:架构规划还包括制定决策框架,以...
报告中可能包含实际项目案例,展示如何应用DDD和微服务解决特定业务场景的问题,例如使用事件驱动架构处理复杂业务流程,或者通过分而治之的策略优化高并发场景。 **总结与展望** DDD与微服务的结合为应对现代企业...
在实践中,架构师还需要考虑非功能性需求,如性能、安全、可伸缩性、容错性和可测试性。例如,负载均衡和分布式缓存可以改善性能和伸缩性;数据加密和权限控制确保安全性;错误处理和冗余设计增强容错性;自动化测试...
- **数据一致性**:使用Event Sourcing和CQRS(命令查询责任分离)处理分布式事务。 - **服务间依赖管理**:使用服务编排工具如Istio进行服务发现和依赖管理。 - **安全性**:实施OAuth2、JWT进行身份验证,使用...
5. **CQRS(命令查询职责分离)**:将处理读操作(查询)的组件与处理写操作(命令)的组件分开,提高系统性能和响应速度。 ### 架构师的角色与责任 架构师在软件项目中扮演着至关重要的角色,他们负责定义系统的...
1. **可扩展性**:设计时应考虑未来可能的需求变化,确保架构具有良好的扩展能力。 2. **模块化**:通过模块化设计提高系统的灵活性和可维护性。 3. **解耦**:降低各组件间的依赖程度,便于独立更新和部署。 4. **...
微服务架构下,数据管理变得复杂,需要考虑分布式事务和一致性问题。CAP理论指导我们权衡一致性、可用性和分区容错性。Event Sourcing和CQRS(命令查询职责分离)等模式有助于解决这些问题。 9. 安全性: 微服务...
- CQRS将命令查询职责分离,使用不同的模型来处理读写操作,提高系统的可伸缩性和响应速度。 6. **最终一致性** - 最终一致性是分布式系统中最常见的事务一致性模型之一。 - 它不要求事务立即达到一致状态,而是...