解决CQRS瓶颈

传统CQRS面临的挑战是读和写都是分享同一个数据库和应用,但是将读和写进行分离,分离成两个路线,又是一种极端的做法,数据库变成两个,应用程序是两套,带来一定的复杂性。

Fighting Bottlenecks with CQRS by Mathias Verraes一文谈了如何利用事件回放解决CQRS中读写瓶颈。

该作者的建议是:将写的领域事件持久化到EventStore中,而读取则不是从另外一个数据库,也是从这个EventStore数据库读取,读取的是持久化的事件,然后将回放结果返回给用户,这样实现一个读查询等功能,需要在领域模型中提供一个通过从EventStore读取事件回放事件的方法。

比如下面是写模型修改模型内部状态:


BankAccount
{
apply(AccountWasDebited Event){
amount = amount - event.amount
}
}

而读取也是通过这个类的一个方法实现:


BankAccount
{
getRecordedEvents(){}
reconstituteFromHistory(eventHistory)){}
}
}

上面是从事件历史中重构用户需要的状态信息。

这样完成写达到即时高一致性,而读是最终一致性。

那么下面如何解决事务问题,比如一张票只能卖一次。
为了买x张票,查询得到2*x(两倍)可用的票集合,进行小于三次循环的预订,应该类似我以前谈到在两个账户之间转账时,进行保留预订一样。

[该贴被banq于2013-12-01 11:49修改过]
[该贴被banq于2013-12-01 11:50修改过]

这里其实体现了事件回溯的必要性,可以解决共享瓶颈,不必要复杂得成为两个系统,在一个系统中实现读写分离,写用于接受命令,更新状态操作,发出领域事件;读回放写的事件获得结果。

相关主题:事件回溯的必要性
http://www.jdon.com/45932

还体现了另外一个设计:如果能够从业务上解决的事务,就不要用技术事务如JTA 2pc或数据库乐观锁等来解决。
相关主题:吐槽下,工行ATM转账
[该贴被banq于2013-12-01 12:19修改过]

但是如何实现 find 搜索呢?