您现在的位置 >> Hadoop教程 >> Hadoop实战 >> 专题  
 

Domain Events异步应用

【作者:Hadoop实战专家】【关键词:实现 查询 】 【点击:3406次】【2013-05-1】
Domain Events领域事件定义见这里Domain Events – 救世主,领域事件可以实现领域业务模型与技术架构之间的松耦合,达到实现类似DCI架构同样效果。 由于针对messageCount有一些专门操作,我们就不能直接在Account中实现这些操作,可以使用一个专门值对象实现。  

相关热门搜索:机器学习算法实现 一个操作系统的实现 虚拟化技术原理与实现

大数据标签:bigdata

Domain Events异步应用  2009年11月21日 09:47
DDD领域驱动设计      EDA事件架构      JdonFramework      jivejdon

25

顶一下

Domain Events领域事件定义见这里Domain Events – 救世主,领域事件可以实现领域业务模型与技术架构之间的松耦合,达到实现类似DCI架构同样效果。

DCI是通过设定一个场景对象,让与这个场景有关的功能在场景中混合实现,注入参与者角色和参与模型;而领域事件则是通过松散的事件达到场景目标,不同场景对应不同领域事件。下面以JiveJdon实例说明领域事件应用。

在JiveJdon的Account中有一个计算该用户发帖总数字段messageCount,如下:


public class Account{

   private int messageCount;
   
   public int getMessageCount(){
       return messageCount;
   }

}

这个messageCount是通过查询该用户所有发帖数查询出来的,也许你会问,为什么不将用户发帖总数设置为数据表一个字段,这样用户发帖时,更新这个字段,这样只要直接查询这个字段就可以得到messageCount?

没有设立专门持久字段的原因如下:
1. 从模型设计角度看:messageCount字段归属问题,messageCount其实是一个表示Account和Message两个实体的关系关联统计字段,但是这种关联关系不属于高聚合那种组合关系的关联,不是Account和Message的必备属性,根据DDD的高聚合低关联原则,能不要的关联就不要,因此放在哪里都不合适。

2.从性能可伸缩性角度看:如果我们将messageCount放在第三方专门关联表中,那么用户增加新帖子,除了对Message对应的表操作外,还需要对这个关联表操作,而且必须是事务的,事务是反伸缩性的,性能差,如果象messageCount各种统计字段很多,跨表事务边界延长,这就造成整体性能下降。

3.当然,如果将messageCount硬是作为Account表字段,由于整个软件的业务操作都是Account操作的,是不是将其他业务统计如threadCount等等都放到Account表中呢?这会造成Account表变大,最终也会影响性能。

那么messageCount每次都通过查询Message对应表中用户所有发帖数获得,这也会导致性能差,表中数据越多,这种查询就越费CPU。

使用缓存,因为Account作为模型被缓存,那么其messageCount值将只有第一次创建Account执行查询,以后就通过缓存中Account可直接获得。

所以,根据DDD,在AccountRepository或AccountFactory实现数据表和实体Account的转换,Account中的值都是在这个类中通过查询数据表获得的。

当访问量增加时,这里又存在一个性能问题,虽然一个Account创建时,messageCount查询耗时可能觉察不出,但是如果是几十几百个Account第一次创建,总体性能损耗也是比较大的,鉴于我们对可伸缩性无尽的追求,这里还是有提升余地。

从设计角度看,由于messageCount不是Account的必备字段,因此,不是每次创建Account时都要实现messageCount
的赋值,可采取即用即查方式。所以,我们需要下面设计思路:


public class Account{

   private int messageCount = -1;
   
   public int getMessageCount(){
       if(messageCount == -1)
           //第一次使用时即时查询数据表
       return messageCount;
   }

}

怎么实现这个功能呢?使用Hibernate的懒加载?使用Lazy load需要激活Open Session In View,否则如果Session关闭了,这时客户端需要访问messageCount,就会抛lazy Exception错误,但是OSIV只能在一个请求响应范围打开,messageCount访问可能不是在这次请求中访问,有可能在后面请求或其他用户请求访问,所以,这个懒加载必须是跨Session,是整个应用级别的.

实际上,只要Account保存在缓存中,对象和它的字段能够跨整个应用级别,这时,只要在messageCount被访问即时查询数据表,就能实现我们目标,其实如此简单问题,因为考虑Hibernate等ORM框架特点反而变得复杂,这就是DDD一直反对的技术框架应该为业务设计服务,而不能成为束缚和障碍,这也是一山不容二虎的一个原因。

这带来一个问题,如何在让Account这个实体对象中直接查询数据库呢?是不是直接将AccountRepository或AccountDao注射到Account这个实体呢?由于AccountDao等属于技术架构部分,和业务Account没有关系,只不过是支撑业务运行的环境,如果将这么多计算机技术都注射到业务模型中,弄脏了业务模型,使得业务模型必须依赖特定的技术环境,这实际上就不是POJO了,POJO定义是不依赖任何技术框架或环境。

POJO是Martin Fowler提出的,为了找到解决方式,我们还是需要从他老人家方案中找到答案,模型事件以及Event模式也是他老人家肯定的,这里Account模型只需要向技术环境发出一个查询Event指令也许就可以。

那么,我们就引入一个Domain Events对象吧,以后所有与技术环境的指令交互都通过它来实现,具体实现中,由于异步Message是目前我们已知架构中最松耦合的一种方案,所以,我们将异步Message整合Domain Events实现,应该是目前我们知识水平能够想得到的最好方式之一,当然不排除以后有更好方式,目前Jdonframework 6.2已经整合了Domain Events + 异步消息机制,我们就可以直接来使用。

这样,Account的messageCount即用即查就可以使用Domain Events + 异步消息实现:


 public int getMessageCount(){
		if (messageCount == -1) {
			if (messageCountAsyncResult == null) {
	               //向技术环境发出查询获得messageCount值的命令,
                       //这个命令是在另外新线程实现,因此结果不一定立即返回			   
		      messageCountAsyncResult = 
                              domainEvents.computeAccountMessageCount(account.getUserIdLong());
			} else {
			   //当客户端再次调用本方法时,可以获得查询结果,
                           //如果查询过程很慢,还是没有完成,会在这里堵塞等待,但概率很小
				messageCount = (Integer) messageCountAsyncResult.getEventResult();
			}
		}
}

messageCount最后获得,需要通过两次调用getMessageCount方法,第一次是激活异步查询,第二次是获得查询结果,在B/S架构中,一般第二次查询是由浏览器再次发出请求,这浏览器服务器一来一回的时间,异步查询一般基本都已经完成,这就是充分利用B/S架构的时间差,实现高效率的并行计算。

所以,并不是一味死用同步就能提高性能,可伸缩性不一定是指单点高性能,而是指整个系统的高效率,利用系统之间传送时间差,实现并行计算也是一种架构思路。这种思考思路在实际生活中也经常会发生。

最后,关于messageCount还有一些有趣结尾,如果浏览器不再发第二次请求,那么浏览器显示Account的messageCount就是-1,我们可以做成不显示,也就看不到Account的发帖总数,如果你的业务可以容忍这个情况,比如目前这个论坛就可以容忍这种情况存在,Account的messageCount第一次查询会看不到,以后每次查询就会出现,因为Account一直在缓存内存中。

如果你的业务不能容忍,那么就在浏览器中使用AJAX再次发出对getMessageCount的二次查询,那么用户就会每次
都会看到用户的发帖总数,JiveJdon这个论坛的标签关注人数就是采取这个技术实现的。这样浏览器异步和服务器端异步完美结合在一起,整个系统向异步高可伸缩性迈进一大步。

更进一步,有了messageCount异步查询,如何更新呢?当用户发帖时,直接对内存缓存中Account更新加一就可以,这样,模型操作和数据表操作在DDD + 异步架构中完全分离了,数据表只起到存储作用(messageCount甚至没有专门的存储数据表字段),这和流行的NoSQL架构是同一个思路。

由于针对messageCount有一些专门操作,我们就不能直接在Account中实现这些操作,可以使用一个专门值对象实现。如下:


public class AccountMessageVO {

	private int messageCount = -1;

	private DomainMessage messageCountAsyncResult;

	private Account account;

	public AccountMessageVO(Account account) {
		super();
		this.account = account;
	}

	public int getMessageCount(DomainEvents domainEvents) {
		if (messageCount == -1) {
			if (messageCountAsyncResult == null) {
				messageCountAsyncResult = domainEvents.computeAccountMessageCount(account.getUserIdLong());
			} else {
				messageCount = (Integer) messageCountAsyncResult.getEventResult();
			}
		}
		return messageCount;
	}

	public void update(int count) {
		if (messageCount != -1) {
			messageCount = messageCount + count;
		}

	}
}

注:以上功能已经在当前论坛实现。

相关文章:
Domain Events – 救世主
CAP原理和BASE思想
开源Jdonframework 6.2全新发布

[该贴被admin于2009-11-22 08:11修改过]
[该贴被admin于2010-03-28 09:00修改过]
[该贴被admin于2010-03-28 09:01修改过]
[该贴被admin于2010-03-28 09:01修改过]

大数据系列相关文章:

最新评论
可可2014-09-10 03:50:54
#C3沙龙#今晚在雅虎北京全球研发中心举办。我们知道Hadoop是Yahoo!的骄傲,据雅虎北研移动互联网平台研发总监曾宏威介绍,Yahoo全球的Hadoop服务器大约6千台,而IDC去年的数据显示,Yahoo的服务器总量超过10万台… @Deepb1ue @李小博_巭熊犭苗 清华同方科技广场
bin2014-09-09 04:21:47
仍然报错
顾晓艳2014-09-09 03:04:11
然后通过hbase的API就可以查询
孤星2014-09-08 03:02:37
FileInputFormat.setInputPaths(conf, new Path(input));
Summer_town2014-09-08 06:52:18
上亿的查询也不是问题吧
秦烈风2014-09-07 06:45:35
在win上的eclipse终于可以连上虚拟机里的hadoop了,之前还以为是版本兼容问题,搞了半天是配置问题
夢ω鷗2014-09-06 05:39:56
我还从没面试过这样的职位
廖廖2014-09-05 03:53:04
【英特尔大数据实战案例:中国移动广东分公司】基于英特尔至强处理器和Apachi Hadoop解决方案,该公司实现了网上缴费,并支持实时提取六个月内的呼叫数据记录,加快了结算流程,提高了服务质量。目前,广东分公司的详细账单查询系统每秒可检索30万条记录,相当于每月高达30 TB的用户计费数据。
石头2014-09-04 10:33:05
简洁明了『8 SQL-on-Hadoop frameworks worth checking out | Matthew Rathbone』http://t.cn/RvCgVWU
马尧2014-09-04 03:45:41
【视频演讲: Hadoop2.0应用 - 基于Yarn的淘宝海量数据服务平台】 http://t.cn/8FjJA7G (分享自@无觅阅读)
 
  • Hadoop生态系统资料推荐