在 ModeShape 4.0 的事件使用循环缓冲区

事件对于ModeShape至关重要。当你的应用保存一些变更到页面,ModeShape就会产生描述那些变更的事件,并且会发送那些事件到你所有的被注册的应用侦听器中。不管哪些集群产生的这些变化或是集群中你的侦听器在哪一部分所监听到的,都要保证每个侦听器尽可能侦听到所有更改的事件。

但是你的应用不能仅仅只是对事件做出反应:ModeShape它自己有相当一些侦听器被允许监听和反馈那些一致的更改。许多ModeShape的侦听器在你的页面内回应那些变更,同时另外的内置侦听器也会通过ModeShape回复那些变更。怎么做到的呢?ModeShape在它的存储区域(命名空间,节点类型的定义,锁,版本,索引定义,联合规划(federated projections)等等)存储了各种类型系统的元数据。当任何的元数据被改变并且存留在集群的一个进程中,它仅会通过事件将这些变更通知到这个集群中的另外一些进程。

例如,当你的应用注册一个新的命名空间prefix/URI对时,ModeShape反射在本地命名空间(NamespaceRegistry)并注册实例至内存中的cache并且立即启动持续信息(的转发)。但是命名空间(NamespaceRegistry)的实例在其他的集群中怎么样呢?他们使用侦听器去查看在命名空间区域内系统元数据的变更,并且他们能立即观察到一个事件描述的新命名空间,(远程)命名空间(NamespaceRegistry)实例能立即更新他们的在内存中的cache,因此所有的会话自始至终与集群所看到的是一个一致的命名空间的注册集合。

ModeShape有相当多的组件,它们通过一致的方式去使用事件:索引,锁,版本,工作空间的添加/移除,全存储区的设定。

ChangeSet 和 ChangeBus

要注册一个监听器,应用程序必须实现javax.jcr.observation.EventListener接口,然后使用工作区的ObservationManager注册一个实例。标准JCR事件可以描述在节点创建,移动或删除的基本信息,而当属性添加,更改或删除时也是。但仅此而已。

在内部,ModeShape 采用了更丰富和更细粒度类型的事件。每次提交一个事务时(不管是单个会话保存还是多个保存),所有该次提交所做的变更的描述被捆绑到单个ChangeSet。这些ChangeSet ,在ModeShape中实际上是在集群中承载的,所有的ModeShape 的内部组件被编写来响应它们,通过实现和注册内部ChangeSetListener接口的方式。有趣的是,每次你的应用程序注册一个新的事件监听器的实例,ModeShape 其实注册一个内部ChangeSetListener的实现,这样不过是将每个ChangeSet(及其所描述的变更)转换成一组标准的JCREvent对象。

在 ModeShape 4.0 的事件使用循环缓冲区

每个Repository实例都有一个ChangeBus组件,这个组件负责追踪所有ChangeSet监听器和将所有ChangeSet引向那些监听器。多个内部组件先将ChangeSet对象发送给ChangeBus,然后ChangeBus再将这些ChangeSet对象输送到每个监听器的。快速准确地完成这些动作至关重要。比如,一个监听器不应该干涉或妨碍其他监听。还有,一个监听器应该监听到同一命令里所有发生的事件。

如果ModeShape被用作集群,ChangeBus需要满足同样的要求,但有一点不一样的:当有一个组件要发送一个ChangeSet,这个ChangeSet会马上通过JGroups被发送到集群的所有成员上,在每个进程上JGroups把这个ChangeSet对象发给ChangeBus,ChangeBus会依次将ChangeSet输送给所有本地监听器。以这种方式,JGroups可以确保所有进程看到ChangeSet对象的同样的命令。

不用说,ChangeBus非常重要,也相对复杂。2.x版本中起初的设计在3.x中占据篇幅很小,但我们将在4.0版本中展示已将之彻底修补完善。

2.x 和 3.x 的 ChangeBus

ModeShape 2.x和3.x 使用一个相当简单的设计实现ChangeBus:每个监听器有一个“消费者”的线程在不断运行,从侦听器特定阻塞先进先出队列弹出ChangeSet  对象 ,并调用实际的侦听器。当一个新的ChangeSet将被添加到总线时,ChangeBus增加该ChangeSet 到队列的前面给每一位侦听器。 

每个侦听器线程 从它自己的阻塞队列消费ChangeSet 对象 

这样的设计有一些很好的优点:

该设计相当简单。

每一个侦听器对ChangeSet中对象的相同顺序可见。

每个侦听器运行一个独立的线程,所以在大多数情况下每个侦听器都是和所有其他的侦听器完全隔离的(见下文)。 

由于阻塞式队列,如果一个侦听器是真的很慢并且队列已满,那么ChangeBus尝试添加changeset到队列时将阻塞。但是这还是拖慢了系统(特别是进行更改的会话),带来了一些后端压力,尽管侦听器能跟得上。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/e8e073843108e0a3907818d83a41215c.html