1.4 集群实体EJBs
在 JBoss AS 群集系统里,entity bean 实例需要跨节点的复制。如果某个 entity bean 提供远程服务,那么服务方法(service methods)也需要进行负载平衡。
为了使用群集的 entity bean,应用程序不需要做任何特殊的事情,除了从群集的 HA-JNDI 里查找 bean 的引用。
1.4.1 EJB 2.x里的Entity Bean
首先,值得注意的是群集 2.x 的 entity beans 不是件好事。它向群集的远程对象开放(exposes)通常过于细颗粒度的元素(elements),导致了严重的数据同步问题。除非你遇到特殊的情况,如只读或者只写的节点和使用缓存失效服务(cache invalidation services)的只读节点同步,否则不要使用 EJB 2.x entity bean 的群集
要群集 EJB 2.x entity beans,你需要把<clustered>元素加入到应用程序的jboss.xml 描述符文件里。下面是一个典型的jboss.xml 文件。
<
jboss
>
< enterprise-beans >
< entity >
< ejb-name >nextgen.EnterpriseEntity </ ejb-name >
< jndi-name >nextgen.EnterpriseEntity </ jndi-name >
< clustered >True </ clustered >
< cluster-config >
< partition-name >DefaultPartition </ partition-name >
< home-load-balance-policy >
org.jboss.ha.framework.interfaces.RoundRobin
</ home-load-balance-policy >
< bean-load-balance-policy >
org.jboss.ha.framework.interfaces.FirstAvailable
</ bean-load-balance-policy >
</ cluster-config >
</ entity >
</ enterprise-beans >
</ jboss >
< enterprise-beans >
< entity >
< ejb-name >nextgen.EnterpriseEntity </ ejb-name >
< jndi-name >nextgen.EnterpriseEntity </ jndi-name >
< clustered >True </ clustered >
< cluster-config >
< partition-name >DefaultPartition </ partition-name >
< home-load-balance-policy >
org.jboss.ha.framework.interfaces.RoundRobin
</ home-load-balance-policy >
< bean-load-balance-policy >
org.jboss.ha.framework.interfaces.FirstAvailable
</ bean-load-balance-policy >
</ cluster-config >
</ entity >
</ enterprise-beans >
</ jboss >
为了平衡远程调用的负载,我们群集 EJB 2.x entity beans。所有的 bean 实例都实现同步,具有所有节点上的相同内容。
然而,群集的 EJB 2.x Entity Beans 没有分布式的锁定机制或是缓存。它们只能用数据库层面的行级锁定(请参考 CMP 规范的<row-lock>)或是把 JDBC 驱动的事务隔离(Transaction Isolation)级别设为TRANSACTION_SERIALIZABLE来实现同步。因为缺乏分布式的锁定机制或是缓存支持,Entity Beans 缺省使用提交选项 "B"(请参考standardjboss.xml 和 the container configurations Clustered CMP 2.x EntityBean,Clustered CMP EntityBean,或 Clustered BMP EntityBean)。我们不推荐你使用提交选项 "A",除非你的 Entity Bean 是只读的。(有些设计模式允许你把提交选项"A" 用于 read-mostly beans。你也可以看看 Seppuku 模式[url]http://dima.dhs.org/misc/readOnlyUpdates.html.[/url] JBoss may incorporate this pattern into。JBoss 有可能把这个模式集成到以后的版本里。)
注意:
如果你正在使用 Bean Managed Persistence (BMP),你将不得不实现自己的同步机制。MVCSoft CMP 2.0 持久化引擎(persistence engine)(请参考[url]http://www.jboss.org/jbossgroup/partners.jsp[/url]) provides different)提供可以在 JBoss 群集里使用的各种优化锁定策略。
如果你正在使用 Bean Managed Persistence (BMP),你将不得不实现自己的同步机制。MVCSoft CMP 2.0 持久化引擎(persistence engine)(请参考[url]http://www.jboss.org/jbossgroup/partners.jsp[/url]) provides different)提供可以在 JBoss 群集里使用的各种优化锁定策略。
1.4.2 EJB 3.0里的Entity Bean
在 EJB 3.0 里,entity beans 主要以持久化数据模型出现。它们不提供远程服务。因此,EJB 3.0 里的 entity bean群集服务主要处理分布式缓存和复制,而不是负载平衡。
1.4.2.1 配置分布式缓存
为了避免多次访问数据库,你可以为你的 entities 使用缓存。JBoss EJB 3.0 是用 Hibernate 实现的,它支持两级缓存。用于 JBoss EJB 3.0 实现的 Hibernate setup 把 JBoss Cache 当作底层缓存实现使用。这个缓存提供了下面的功能:
u
如果你通过 entity manager 来使应用缓存的 entity bean 的实例持久化,这个 entity 会被储存到缓存里。
u
如果你通过 entity manager 更新 entity bean 实例并把更改保存到数据库里,缓存里的这个 entity 将被更新。
u
如果你通过 entity manager 把 entity bean 实例从数据库里删除,这个 entity 也将从缓存里删除。
u
如果你通过 entity manager 从数据库里载入缓存的 entity,而这个这个 entity 并不在缓存里,这个 entity 会被插入到缓存里。
EJB 3.0 entity beans
采用的 Boss Cache 服务在deploy/ejb3-entity-cache-service.xml文件里的 TreeCache MBean(请参考章节 2, “JBossCache 配置”) 里被配置。缓存 MBean 服务名是jboss.cache:service=EJB3EntityTreeCache。下面是标准 JBoss 发行版本里的ejb3-entity-cache-service.xml文件的内容。我们再次忽略了 JGroups 的配置元素ClusterConfig。
<
server
>
< mbean code ="org.jboss.cache.TreeCache"
name ="jboss.cache:service=EJB3EntityTreeCache" >
< depends >jboss:service=Naming </ depends >
< depends >jboss:service=TransactionManager </ depends >
<!-- Configure the TransactionManager -->
< attribute name ="TransactionManagerLookupClass" >
org.jboss.cache.JBossTransactionManagerLookup
</ attribute >
< attribute name ="IsolationLevel" >REPEATABLE_READ </ attribute >
< attribute name ="CacheMode" >REPL_SYNC </ attribute >
<!-- Name of cluster. Needs to be the same for all clusters, in order to find each other -->
< attribute name ="ClusterName" >EJB3-entity-cache </ attribute >
< attribute name ="ClusterConfig" >
... …
</ attribute >
< attribute name ="InitialStateRetrievalTimeout" >5000 </ attribute >
< attribute name ="SyncReplTimeout" >10000 </ attribute >
< attribute name ="LockAcquisitionTimeout" >15000 </ attribute >
< attribute name ="EvictionPolicyClass" >
org.jboss.cache.eviction.LRUPolicy
</ attribute >
<!-- Specific eviction policy configurations. This is LRU -->
< attribute name ="EvictionPolicyConfig" >
< config >
< attribute name ="wakeUpIntervalSeconds" >5 </ attribute >
<!-- Cache wide default -->
< region name ="/_default_" >
< attribute name ="maxNodes" >5000 </ attribute >
< attribute name ="timeToLiveSeconds" >1000 </ attribute >
</ region >
</ config >
</ attribute >
</ mbean >
</ server >
< mbean code ="org.jboss.cache.TreeCache"
name ="jboss.cache:service=EJB3EntityTreeCache" >
< depends >jboss:service=Naming </ depends >
< depends >jboss:service=TransactionManager </ depends >
<!-- Configure the TransactionManager -->
< attribute name ="TransactionManagerLookupClass" >
org.jboss.cache.JBossTransactionManagerLookup
</ attribute >
< attribute name ="IsolationLevel" >REPEATABLE_READ </ attribute >
< attribute name ="CacheMode" >REPL_SYNC </ attribute >
<!-- Name of cluster. Needs to be the same for all clusters, in order to find each other -->
< attribute name ="ClusterName" >EJB3-entity-cache </ attribute >
< attribute name ="ClusterConfig" >
... …
</ attribute >
< attribute name ="InitialStateRetrievalTimeout" >5000 </ attribute >
< attribute name ="SyncReplTimeout" >10000 </ attribute >
< attribute name ="LockAcquisitionTimeout" >15000 </ attribute >
< attribute name ="EvictionPolicyClass" >
org.jboss.cache.eviction.LRUPolicy
</ attribute >
<!-- Specific eviction policy configurations. This is LRU -->
< attribute name ="EvictionPolicyConfig" >
< config >
< attribute name ="wakeUpIntervalSeconds" >5 </ attribute >
<!-- Cache wide default -->
< region name ="/_default_" >
< attribute name ="maxNodes" >5000 </ attribute >
< attribute name ="timeToLiveSeconds" >1000 </ attribute >
</ region >
</ config >
</ attribute >
</ mbean >
</ server >
正如我们在章节 2, “JBossCache 配置” 所讨论的,JBoss Cache 允许你指定缓存的 entities 的超时时间。在某个时段内没有被访问的 entities 将从缓存里删除,这样可以节省内存。如果这个缓存是在群集里运行,那么它会被更新。对某个节点的 entries 的改动都会复制到群集里其他节点的相应条目里。
现在,我们配置了 JBoss Cache 来支持 EJB 3.0 entity beans 的分布式缓存。我们仍不得不配置单个的 entity bean 来使用这个缓存服务。
1.4.2.2 配置Entity beans为缓存
你用正常方式定义你的 entity bean 类。JBoss EJB 3.0 将来的版本将支持 annotating entities 和所缓存的它们的关系的集合,但是现在你不得不直接配置底层的 hibernate 引擎。让我们看看通过可选的property元素配置 hibernate 缓存选项的persistence.xml文件。下面persistence.xml 里的定义缓存的元素应该被启用:
<!--
Clustered cache with TreeCache -->
< property name ="cache.provider_class" >
org.jboss.ejb3.entity.TreeCacheProviderHook
</ property >
< property name ="cache.provider_class" >
org.jboss.ejb3.entity.TreeCacheProviderHook
</ property >
下面的属性元素定义了所使用的缓存对象名和 MBean 名。
<
property
name
="treecache.mbean.object_name"
>
jboss.cache:service=EJB3EntityTreeCache
</ property >
jboss.cache:service=EJB3EntityTreeCache
</ property >
下一步我们需要配置 entities 被缓存的内容。就像上面所展示的样,缺省是什么都不缓存。我们使用@Cache 注解来标记需要缓存的entity beans。
@Entity
@Cache(usage=CacheConcurrencyStrategy.TRANSACTIONAL)
public class Customer implements Serializable {
// ... ...
}
@Cache(usage=CacheConcurrencyStrategy.TRANSACTIONAL)
public class Customer implements Serializable {
// ... ...
}
一个简单的原则就是,你应该对很少变动和频繁使用的对象进行缓存.你可以在ejb3-entity-cache-service.xml配置文件里为每个 entity bean 微调缓存设置。例如,你可以指定缓存的大小。如果缓存里的对象太多,缓存有可能挤掉最老的对象(或者最少用的对象,依你的配置而定)来给新对象留出空间。mycompany.Customer entity bean 的缓存区(cache region)是/mycompany/Customer。
<
server
>
< mbean code ="org.jboss.cache.TreeCache"
name ="jboss.cache:service=EJB3EntityTreeCache" >
< depends >jboss:service=Naming
< depends >jboss:service=TransactionManager
... ...
< attribute name ="EvictionPolicyConfig" >
< config >
< attribute name ="wakeUpIntervalSeconds" >5 </ attribute >
< region name ="/_default_" >
< attribute name ="maxNodes" >5000 </ attribute >
< attribute name ="timeToLiveSeconds" >1000 </ attribute >
</ region >
< region name ="/mycompany/Customer" >
< attribute name ="maxNodes" >10 </ attribute >
< attribute name ="timeToLiveSeconds" >5000 </ attribute >
</ region >
... ...
</ config >
</ attribute >
</ mbean >
</ server >
< mbean code ="org.jboss.cache.TreeCache"
name ="jboss.cache:service=EJB3EntityTreeCache" >
< depends >jboss:service=Naming
< depends >jboss:service=TransactionManager
... ...
< attribute name ="EvictionPolicyConfig" >
< config >
< attribute name ="wakeUpIntervalSeconds" >5 </ attribute >
< region name ="/_default_" >
< attribute name ="maxNodes" >5000 </ attribute >
< attribute name ="timeToLiveSeconds" >1000 </ attribute >
</ region >
< region name ="/mycompany/Customer" >
< attribute name ="maxNodes" >10 </ attribute >
< attribute name ="timeToLiveSeconds" >5000 </ attribute >
</ region >
... ...
</ config >
</ attribute >
</ mbean >
</ server >
如果你没有为 entity bean 类指定缓存区(cache region),这个类的所有实例将象上面定义的一样缓存在/_default区里。EJB3 Query API 提供了让你在指定的缓存区里保存或载入查询结果(就是 entity beans 的集合)的方法。
本文转自xudayu 51CTO博客,原文链接:http://blog.51cto.com/xudayu/66938,如需转载请自行联系原作者