基于EDA和CQRS的拍卖案例

10-09-10 banq
                   

Xtext/Sculptor框架类似JdonFramework,提供一个事件驱动特性,他们项目组基于Sculptor开发了EDA事件驱动架构 CQRS模式的拍卖案例。

在线拍卖系统,接受大量的拍卖,简单模型如下(看懂下面代码需要DDD基础):

ValueObject Bet {
            String betOfferId
            String customerId
            Double amount
            
            Repository BetRepository {
                save;
            }
        }
        
Service BettingEngine {
            inject @BetRepository
            
            placeBet(@Bet bet);
        }
<p>

BettingEngine 处理这些拍卖然后存储信息。如果存在下面需求:

客户A已经完成多少拍卖?

哪些客户出了最高价?

出价最高的前10名有哪些?

当然,普通开发者会认为很容易,只要基于拍卖引擎开发多个查询即可,但是问题来了:

1.性能差:领域模型并没有为各种查询优化。

2.不具有可伸缩性:单个集中式数据库将成为瓶颈。

3.难于改变:在一个单一系统中融入太多功能。

CQRS(Command-Query Responsibility Segregation)能够将命令(修改数据)和查询(读取数据)

分离,将报表查询和业务领域处理保存更新数据两种职责分离。Command处理的结果将通过事件发送到查询子系统.

当一个拍卖发生后,我们发送领域事件Domain events。

DomainEvent BetPlaced {
            - Bet bet
        }

        Service BettingPublisher {
            publishEvent(@BetPlaced betEvent) publish to jms:topic:bet; //发送消息
        }
<p>

以上代码是command这边实现,下面来看看Query查询这里实现,当然要接受事件了。

首先,我们要看看查询功能实现,假设有一个客户来查询他的拍卖信息:

Module customer {
        Consumer BettingConsumer {
            inject @CustomerStatisticsRepository
            subscribe to jms:topic:bet //注意接受JMS消息
        }
        
        Service BettingQueryService {
            getHighBetters => CustomerStatisticsRepository.findHighAverageCustomers; 
        }
   
        Entity CustomerStatistics {
            gap
            String customerId key
            int numberOfBets
            double averageAmount index
            
            Repository CustomerStatisticsRepository { 
                findByKey;
                save;
                List<@CustomerStatistics> findHighAverageCustomers(double limit);
                protected findByCondition;
            }
        }
   }
<p>

Query这边接受到Command那里发出已经进行拍卖的事件以后,就直接可以到仓储中查询,获取新的纪录。

本案例源代码下载

源码是以MongoDB为持久层,使用ActiveMQ 作为事件中线。

[该贴被admin于2010-09-13 09:04修改过]

                   

3
banq
2010-09-10 10:25

由此案例可见,CQRS实现起来非常简单,就是将查询和修改分离,之间使用事件或消息来通讯。

Jdon框架的批量分页查询和模型增删改查本身就是CQRS,他们两者事件是通过缓存清除方式发生通讯,当然具体实现时,也可以使用JF的Domain events来实现修改和查询的通信,也就是,领域模型一旦发生修改,发出事件告知查询报表系统,激活一些功能。

这样的系统比较具有可伸缩性,查询功能和修改分离,查询可以使用分布式缓存或NoSQL如MongoDB这样的系统实现可伸缩,修改只在一台机器上实现,修改完成,通过事件总线,通知所有实现查询的主机。

这套方案非常可靠实用,据我个人了解,在很多大型BOSS(业务支撑)架构中都是这么做的,而且都已经运行,只不过他们没有上升到这个高度,而修改不是针对领域模型,是针对数据库的。

相关文章:

CQRS模式要好于MVC模型

[该贴被banq于2010-09-10 10:26修改过]

cleanearth
2010-09-10 12:37

Repository BetRepository {
    save;
}
<p>

这个是不是应该放在bet的外面?

[该贴被cleanearth于2010-09-10 12:38修改过]

banq
2010-09-10 15:17

原文:EDA CQRS Betting Sample

lostalien
2010-09-10 17:29

我晕。。。。blogspot。。。。。。烦死了。。。我不会翻呃。。。。。。

2Go 1 2 下一页