CQRS如何实现读写分离

12-12-20 thinkjava
最近在看CQRS,找了一个DEMO,没有理解CQRS的读写分离体现在哪里?是指应用程序在写入和读取操作上分开的读写分离,还是指写入数据的DB和读取数据的DB分开这个层面的读写分离,如果是前者,那意义没有多大呀,仅仅是写操作和读操作在程序上分离了,降低了两个逻辑之间的耦合,这个意义不大呀,如果是后者,那么我没有看到Write DB和Read DB,只看到整个只有一个DB,写的时候,由一个EventHandler负责将数据写入,比如写入DB1,读取的时候,直接读DB1,这有什么意义呢?在这样的架构下,读操作又如何优化呢?

banq
2012-12-20 11:41
晕,两件事分开了还不是一件好事,分而治之啊。

如果混在一起,进行读优化时还要顾及写操作,顾此失彼。

参考一下伸缩性相关讨论吧。

thinkjava
2012-12-20 11:54
2012-12-20 11:41 "@banq"的内容
如果混在一起,进行读优化时还要顾及写操作,顾此失彼。 ...


读和写混在一起,也可以优先呀,怎么会顾此失彼呢,比如,我有一个DAO,里面有写方法,也有读方法,如果写方法慢,我就想办法优化写方法,如果读方法慢,我就优化读方法,怎么会互相有影响呢?

banq
2012-12-20 12:23
这样做违背单一职责的编程原则,一个类只可以实现一个方面职责。如果你在一个类中实现两个以上职责,就应该分离它们。

dao只是简单系统下一个简单对付办法,就像小公司老板可能什么都做,但是做大了需要分工一样。

当你在简单dao中增加各种优化代码,实际是增加新的职责。至少要用装饰器模式。而读写分开装饰是必然。再自己好好想想实践实践。

banq
2012-12-20 12:23
这样做违背单一职责的编程原则,一个类只可以实现一个方面职责。如果你在一个类中实现两个以上职责,就应该分离它们。

dao只是简单系统下一个简单对付办法,就像小公司老板可能什么都做,但是做大了需要分工一样。

当你在简单dao中增加各种优化代码,实际是增加新的职责。至少要用装饰器模式。而读写分开装饰是必然。再自己好好想想实践实践。

thinkjava
2012-12-20 16:59
2012-12-20 12:23 "@banq"的内容
这样做违背单一职责的编程原则,一个类只可以实现一个方面职责。如果你在一个类中实现两个以上职责,就应该分离它们。

dao只是简单系统下一个简单对付办法,就像小公司老板可能什么都做,但是做大了需要分工一样。 ...

单一职责不是所有情况下都是单一职责吧,比如对于CURD,难道要针对C,U,R,D写四个类吗?通常web开发都是一个DAO类有save,update,delete,find等方法,这些方法都是写在一个DAO里的,都这么写的呀,请问这样写只适合简单系统吗?
另外如果要优化,我可以单独针对save, find分别优化,根本不会彼此受影响,我一直没有明白,WEB开发是否需要CQRS,使用CQRS是不是过度设计,或者CQRS适用的场景如何?请banq老师能不能作一下解释,CQRS到底有多大价值?

[该贴被cloudstack于2012-12-20 17:03修改过]

SpeedVan
2012-12-21 05:08
错了,CQRS不是指数据库上的CRUD,数据库思维上说的查询是囊括一切的,所以无法得到领域思维。而实际上,用户获取数据的read跟业务逻辑中的get是两回事。用户获取数据是组织出来的,特点是“零散”的,而参与业务逻辑的大部分是“集中”的。read不会引起任何状态变化,而get是在引起状态变化时使用。read是相对频繁的,用户浏览数据不一定会发起事件,而get是相对偶然的,只有用户想发生事件才会用到。

用户查询<=实体集合<=>逻辑运算

而进一步提高速度

用户查询<=实体集合有效快照<=同步=实体集合<=>逻辑运算

换成使用数据库的话,就变成

用户查询<=读数据库<=写数据库<=>逻辑运算(逻辑运算来自Command引发,而它运算的数据或对象来自写数据库)

thinkjava
2012-12-21 10:32
嗯,我大体明白你的意思,多谢,能否给我解释一下,对于一个WEB系统,使用CQRS方式(写操作和读操作分开方式)和传统的DAO方式(就是把写方法和读方法写在一个DAO里,比如,save(Entry entry), get(id)或find(id))有多大区别,CQRS的价值有多大?CQRS的使用场景如何?我就是想了解CQRS的读写分离和传统DAO方式相比价值有多大?谢谢回复

[该贴被cloudstack于2012-12-21 10:34修改过]

[该贴被cloudstack于2012-12-21 10:40修改过]

SpeedVan
2012-12-21 12:33
DAO方式只是针对一个对象集,无论如何增删改都会引发各种锁和事务,对于修改多(态变频率大)的情况,即使是单纯的查看也会变得缓慢。

CQRS价值是提高读负载,使用场景可以很多,关键是取舍问题,而这个问题可以通过同步策略来展开。

banq
2012-12-21 14:57
2012-12-21 10:32 "@cloudstack"的内容
于一个WEB系统,使用CQRS方式(写操作和读操作分开方式)和传统的DAO方式(就是把写方法和读方法写在一个DAO里,比如,save(Entry entry), get(id)或find(id))有多大区别 ...


区别是方向不同,一个向南,一个向北。

DAO是以数据为中心,而CQRS是以反映业务语言的领域模型为核心,围绕核心不同,就像老板不同一样。

参见:改变心智这篇文章

在CQRS系统中,DAO属于仓储Repository更下层,如果说CQRS是站在冰山之顶,那么DAO就是山脚下,甚至根本无需DAO,而是改为仓储Repository。

使用DAO习惯是因为传统JavaEE或Spring Hibernate等编程模型以数据为中心,以事务脚本来实现功能,而CQRS完全不是这条路线。

如果一个小系统从CQRS入手,其可伸缩性很强,我们一直强调分布式计算,性能高,到处在宣传如何运行更快,通过云计算,如果你的程序很烂,骑上云计算这匹快马会很快,但是代价很高。那只能从自身系统基础开始注重性能提升。

伸缩性能够让你的软件在访问量不断增长时,通过简单配置改动增加新服务器就能提升处理性能。

性能 处理能力或者说延迟 吞吐量都是和精益的软件设计有关系,不是单靠tunning微调或者黑客方式才能达到,当然后者通常是亡羊补牢的办法。

[该贴被banq于2012-12-21 14:59修改过]

thinkjava
2012-12-21 16:14
2012-12-21 14:57 "@banq"的内容
DAO是以数据为中心,而CQRS是以反映业务语言的领域模型为核心,围绕核心不同,就像老板不同一样。
在CQRS系统中,DAO属于仓储Repository更下层,如果说CQRS是站在冰山之顶,那么DAO就是山脚下,甚至根本无需DAO,而是改为仓储Repository

以数据为核心和以领域模型为核心,最终会影响到哪里,我没有明白
我看了CQRS里有一个Repository,功能类似DAO,是和数据库打交道的,没有什么区别,为什么要用Repository称呼? 为什么说Repository是山顶,DAO是山脚,如何理解?如果无需DAO,改为仓储Repository,我感觉是换了个名词,DAO的功能并没有消失呀

[该贴被cloudstack于2012-12-21 16:32修改过]

banq
2012-12-21 16:40
2012-12-21 16:14 "@cloudstack"的内容
我没有明白
我看了CQRS里有一个Repository,功能类似DAO,是和数据库打交道的,没有什么区别 ...


你主要要了解一下DDD领域驱动设计,一两句说不清楚。可在本站多看看其他文章。

我简单说几句,不知你是否能够理解:
DAO是根据需要产生数据对象,今天创建对象A,明天可能有对象B,但是你会发现A和B的字段差不多,又有些同。这样,如果修改相同的字段,两个对象都要修改,修改面扩大,一发动全身,系统难以维护拓展。

而CQRS是围绕反映业务模型的领域模型,如果业务发生变化,直接一个领域模型即可,它相当于老板,老板一改,其他可跟着改。

而在DAO架构下,业务需求一改,先改数据表结构,让围绕数据表的一堆对象都要改。

那么,修改一个领域模型和修改一个数据表结构,表面上修改量是一样的,但是不要忘记,领域模型是代码,而且有方法代码,有些修改完全可以通过方法来实现。

关键是,需求一般是:什么人做什么事产生什么结果,数据表只能记录做了什么事情的结果数据,而不是直接反映了什么事情。需求表达和数据表达之间存在一个翻译。这个翻译环节就增加了信息传播失真,就像多人玩拷贝不走样游戏,最后那人总是无法猜测第一人做的是什么动作。

建议看看老文章:

面向对象与领域建模

数据库已死

一个是面向对象,一个是面向数据库,中心重点不同。所谓重点中心,就是开发一个软件,第一步从哪里开始,DAO是第一个做数据库,然后有DAO,而CQRS是第一个做领域模型,然后有CQRS。先后不同其实是正反不同一样。

[该贴被banq于2012-12-21 16:45修改过]

thinkjava
2012-12-21 21:15
2012-12-21 16:40 "@banq"的内容
CQRS是围绕反映业务模型的领域模型,如果业务发生变化,直接一个领域模型即可,它相当于老板,老板一改,其他可跟着改。 ...

这里的意思是指,如果业务发生变化,我们就创建一个新的领域模型,然后有针对这个新领域模型的领域事件和Handler吗?

thinkjava
2012-12-21 21:25
2012-12-21 16:40 "@banq"的内容
关键是,需求一般是:什么人做什么事产生什么结果,数据表只能记录做了什么事情的结果数据,而不是直接反映了什么事情。需求表达和数据表达之间存在一个翻译。这个翻译环节就增加了信息传播失真,就像多人玩拷贝不走样游戏,最后那人总是无法猜测第一人做的是 ...

这句是说DAO方式是面向数据表,容易造成软件功能和需求不一致,而CQRS正好能描述需求的过程,比如产生了什么样的Command,Command是如何执行的,执行结果如何,是这个意思吗?

SpeedVan
2012-12-21 21:49
2012-12-21 16:14 "@cloudstack"的内容
以数据为核心和以领域模型为核心,最终会影响到哪里,我没有明白
我看了CQRS里有一个Repository,功能类似DAO,是和数据库打交道的,没有什么区别,为什么要用Repository称呼? 为什么说Repository是山顶,DAO是山 ...


一个领域一种语言一种逻辑。领域模型思考的是业务逻辑,通过领域语言直接描述实现有效扩展,而我们使用DAO的时候,是在不断地想如何拼对sql。

如果你懂范畴论的话,我可以说这是两个范畴,甚至可能存在态射,他们相同不相同毫无关系。

额外地:实际上领域化是逻辑化的走向,Repository像DAO主要受语言局限性。其实最终走向,Repository最终会演变成一个集合,通过高阶函数替换所谓的查询。因为内存不能容纳整个数据库,所以Repository会以实现集合接口而存在。我认为Repository是由数据库方负责开发,它犹如驱动,直接对语言进行支持,因为JAVA不行,所以就这样了。

[该贴被SpeedVan于2012-12-21 21:53修改过]

3Go 1 2 3 下一页