JdonFramework 6.4(Disruptor)版发布

2009年JdonFramework 6.2版本推出基于内存的异步领域事件版本,其关键点是Domain Model + In-memory + Domain Events.常驻内存In-memory的领域模型Domain Model通过领域事件Domain Events驱动技术实现各种功能,正如基因DNA是生命各种活动功能的核心一样,实现了以领域模型而不是数据表为核心的新的模型驱动开发架构MDD。

2011年Martin Fowler肯定了LMAX架构的领域模型in-memory事件架构.

JdonFramework原先Domain Events是使用JDK FutureTask实现的, 但是最快并发开源框架Disruptor的创建者LMAX团队测试发现JDK所谓带锁并发包性能不优异,他们也发现函数式语言的Actor模型是有瓶颈的,所以他们采取Disruptor这样配合多核CPU高速缓冲策略的新框架,破除了Java多核并发隐患了JVM伪共享

JdonFramework 6.4版本引入了Disruptor作为其Domain Events实现机制,如下图:

JF的领域事件是一种异步模式 + 生产者-消费者模式。分为主题topic和Queue队列两种。领域模型是生产者;JF的消费者有两种:
(1).@Send => @Consumer;可以实现1:N多个,内部机制使用号称最快的并发框架Disruptor实现。适合轻量;小任务;原子性;无状态。
(2).@Send => @Componet;只能1:1,直接使用普通组件类作为消费者,使用jdk future机制,适合大而繁重的任务,有状态,单例。

有关新的JF领域事件见该文档:JdonFramework模型驱动快速开发

JiveJdon 4.4版本是基于JdonFramework 6.4版本的Disruptor新版本,基本使用Disruptor的DomainEventHandler替代了原来的MessageListener。其最新测试结果如下,由于将数据库等操作使用异步事件实现,回帖和帖子修改等写入性操作都是基于内存领域对象实现,性能大大提高:

领域事件是一种CQRS架构,也是一种Event Sourcing模式,可扩展性极强,通过以事件函数为核心,与面向函数思维一致,符合蒯因的引用透明原则和懒惰加载特性。

JdonFramework 6.4(Disruptor)版下载地址:SourceForge code.google.com下载

English: http://www.jdon.org/
JdonFramework on GitHub: https://github.com/banq/jdonframework

使用JF可以轻松实现DCI架构。事件的生产者实际是DCI中的角色,JF运行时通过将角色注入到模型中实现其角色扮演功能。

DCI:数据Data, 场景Context, 交互Interactions是由MVC发明者Trygve Reenskaug发明的。 见 DCI架构是什么? DCI让我们的核心模型更加简单,只有数据和基本行为。业务逻辑等交互行为在角色模型中 在运行时的场景,将角色的交互行为注射到数据中。

JdonFramework的Domain Events是DCI的交互行为,在实现领域事件的同时也实现了DCI。为更清楚说明DCI,下面以JdonFramework案例说明。源码见: SimpleJdonFrameworkTest.rar

领域模型是DCI的Data,只有数据和基本行为,更简单,但注意不是只有setter/getter的贫血模型。如下:


@Model
public class User Model {

private String userId;
private String name;

@Inject
private ComputerRole computerRole;

Domain Events事件或消息的生产者也就是DCI中的角色Role,比如我们有一个专门进行计数计算的角色,实际上真正计算核心因为要使用关系数据库等底层技术架构,并不真正在此实现,而是依托消息消费者@Consumer实现,那么消息生产者可以看出是一个接口,消费者看成是接口的实现:


@Introduce("message")
public class ComputerRole {

@Send(
"computeCount")
public DomainMessage computeCount(User[author]Model[/author] user) {
return new DomainMessage(user);
}

@Send(
"saveUser")
public DomainMessage save(User[author]Model[/author] user) {
return new DomainMessage(user);
}

}

DCI第三个元素是场景上下文Context,在这个场景下,ComputeRole将被注入到模型UserModel中,实现计数计算的业务功能:


public class ComputeContext {

private DomainMessage ageAsyncResult;

public void preloadData(User[author]Model[/author] user) {
if (ageAsyncResult == null)
ageAsyncResult = user.getUserDomainEvents().computeCount(user);
}

public int loadCountNow(User[author]Model[/author] user) {
preloadData(user);
return (Integer) ageAsyncResult.getEventResult();
}

public int loadCountByAsync(User[author]Model[/author] user) {
if (ageAsyncResult == null)
ageAsyncResult = user.getUserDomainEvents().computeCount(user);
else if (ageAsyncResult != null)
return (Integer) ageAsyncResult.getEventResult();
return -1;

}
}


DCI应用源码下载:SimpleJdonFrameworkTest.rar

开发文档:JdonFramework模型驱动快速开发
更多文档:http://www.jdon.com/jdonframework/manual.htm

关于领域事件和DCI纠结讨论见:
DCI,领域模型,领域事件的一些想法,该文讨论场景和事件到底应该如何结合?怎么结合?

DCI并不反对继承 一文认为DCI目前最大的不确定性或者说问题是何时以及如何定义一个Context上下文场景?我个人认为通过领域事件实际上巧妙回避了这个问题,因为事件隐含了场景。

[该贴被banq于2011-09-10 17:09修改过]
[该贴被banq于2011-09-13 12:14修改过]

感谢banq的不懈努力。
  对于DCI,banq的提供思路在大多数场景下没问题。不过在我遇到的实际应用发现,在更复杂的场景中,领域对象的事件响应可能还会因场景不同而不同。这也就是说,大多数情况下主要由场景触发不同的领域对象事件,但领域对象的事件响应还可能进一步细分为不同的场景。
  所以领域对象事件和场景可能是相互交织的。不知道banq有没有更好的思路。

不知道jdon还记得我不,很久以前发你一个邮件,现在我也在java的领域中遨游了!最近的几篇主题LMAX和disrutor,让我非常刚兴趣。貌似我在多线程并发领域总是很有兴趣。
废话不多说。我看了disruptor的主题文章,如果真如文章所说,这个是目前最快的并非处理,那么在我一直在想,这个技术是否可以用到我们公司的系统中去。因为我们公司目前的系统虽然完整,但是咋性能上没有下很多时间,因为需要追求稳定。(插播下广告:我在职的公司是深圳的安捷信联,深圳的手机深圳通就是我们的产品)。而我们公司的系统驱动就是使用open mq的队列消息。我对disruptor的唯一担心是,他稳定吗?可以在并发情况下,保证数据的完整性等一系列问题(问题提的不好,见谅!)。
希望可以有更多的相关的文章,我很希望能够学习下这个技术。

2011年09月12日 01:06 "@flyzb "的内容
领域对象事件和场景可能是相互交织的。不知道banq有没有更好的思路。 ...

目前我也比较纠结..这个问题需要详细讨论才可能有好的思路,如果说场景或上下文是一个“面”,那么事件是“面”里那个点。场景在技术还要实现混合Assigned注入等作用。

2011年09月12日 01:06 "@xuyifeng "的内容

我对disruptor的唯一担心是,他稳定吗?可以在并发情况下,保证数据的完整性等一系列问题(问题提的不好,见谅!)。

这个问题Martin Fowler的LMAX架构已经回答了,LMAX团队在2010的Qcon大会汇报了他们这个技术,直至2011年老马写这篇文章,至少已经已经稳定运行一年,LMAX他们有专门的博客http://blogs.lmax.com/

想学习一下源码,可是弄了半天下载不下来,下载的时候提示 没有权限,用putty key generator生成了一个key还是不行,banq知道一下吧。
这个工具有点复杂,为什么不直接用SVN呢。

不错

对"场景, 角色"我理解得不是很好.
http://www.jdon.com/jivejdon/thread/37976 看了这个帖子后, 我理解为把Context放在了角色之中?

看到DCI的定义, 我首先想到的是自己曾尝试过的一种做法: 通过Context的改变, 来改变Interaction的语义. (语义中可能有不变性和可变性, 这里改变其可变性)

以Strategy模式为例: 对算法的调用是不变的, 而通过替换封装了算法的对象, 可以替换所使用的算法实现. Context就隐式存在于这个封装了算法的对象中. 把Context替换了, 同样的Interaction就会有不一样的具体行为.

[该贴被sorra于2012-03-03 11:34修改过]

楼主您好,最近我一直在研究Disruptor。有些地方还是不太明白,想请教一下楼主:
1、首先是ringbuffer。虽然我们可以以异步的方式,先将事件放入ringbuffer,可是最终还是要写入到数据库的。当多个handler同时操作数据库时,不是一样还是存在性能的问题吗?
2、您说到:
“JiveJdon 4.4版本是基于Jdonframework 6.4版本的Disruptor新版本,基本使用Disruptor的DomainEventHandler替代了原来的MessageListener。其最新测试结果如下,由于将数据库等操作使用异步事件实现,回帖和帖子修改等写入性操作都是基于内存领域对象实现,性能大大提高”
想知道,您是如何实现将内存中的对象最终写入数据库的?另外,对于服务器发生意外,内存数据丢失的问题您又是如何解决的?
谢谢!
[该贴被abel1978于2012-04-17 09:41修改过]

2012-04-17 09:39 "@abel1978"的内容
有些地方还是不太明白,想请教一下楼主 ...

这涉及全新的架构,不是一两句说清楚的,异步=并发,也就是两个线程以上同时做事:
第一个线程是处理内存中的数据。
handler操作数据库是在第二个线程。

这两个线程互相不影响。

其它问题参考这个文章:LMAX架构

banq老师你好,
对于异步处理,我有一个疑问。
看论坛里的讨论,似乎jdon即使是很小的操作,也采用异步方式去做的。
但并不是对什么都做异步就会始速度更快。因为那会造成额外的线程上下文切换。

msdn上也指出了过度并行化的缺陷
《数据并行和任务并行中的潜在缺陷》
http://msdn.microsoft.com/zh-cn/library/dd997392.aspx

所以为,异步只是在某些特定情况下是适用并且确实能提升网站吞吐量的。但异步不是主要,它只是一个辅助。
[该贴被beethoven于2012-07-26 04:26修改过]
[该贴被beethoven于2012-07-26 04:27修改过]

2012-07-26 04:22 "@beethoven"的内容
但异步不是主要,它只是一个辅助 ...

那篇文章看了,是标题党,主要还是谈如何使用并行,关键是从业务设计上区分可变和不变性出来。见:不变性设计,我们采取异步并发,主要是为了回避堵塞,见无堵塞的并发编程,另开线程的开销比锁堵塞等开销要小于得多。

另外异步也能够从设计上松耦合系统,能够实现灵活扩展等等,这个话题可见异步编程模型这个主题标签的讨论。