正 文

EJB的七年之痒


www.7dspace.com  更新日期:2006-2-19 17:49:07  七度空间


水平可伸缩性的真正限制通常在于数据访问。大多数entity bean实现在集群环境要求每次对持久对象的访问都必须访问数据库,这会对性能造成影响,并且数据库负载也会升高(因为限制了可伸缩性)。如果采用一个专门的持久化解决方案(例如Hibernate或者一个JDO实现),再加上一个支持集群的缓存,我们通常可以获得更高的吞吐量。通常我们没必要在业务层管理状态,也就是说专门用于业务层的集群服务并不是很重要。

线程管理

EJB的线程管理所能提供的价值往往不像它所吹嘘的那么确切。EJB让开发者们能够以编写单线程程序的方式编写业务对象,同时又使这些业务对象能够适用于多线程环境,这当然是大家都愿意看到的。然而,实际情况是:EJB的线程支持无法彻底解决“对EJB facade之后的对象的并发访问”造成的问题,而且它也不是解决并发问题的唯一选择。另外,不论调用entity bean的任何方法,整个entity bean实例都会被加锁,这是一种相当幼稚的做法,而且并不总是很合理。

对于类似于SLSB的服务对象,存在比EJB线程管理更好的替代方案,包括:

Ø 实现不读/写实例变量的多线程服务对象。这种方法在servlet、Struts Action之类的对象中工作得非常完美。大多数无状态服务完全不需要复杂的线程管理。对于这类服务对象,只维护一个单独的实例(而不是维护一个实例池)在很多场合下都是有好处的。举例来说,如果我们因为效率的原因需要在一个无状态session bean中维护一个缓存(例如缓存一个开销庞大的计算得到的结果),EJB缓冲池将导致很多缓存同时存在。单独一个实例也许是更合理的办法。

Ø 使用Command模式:可以在收到每个请求时为每个服务对象创建一个新的实例,在对象内部消除并发的问题。WebWork/XWork很成功地采用了这个办法,在Spring中也同样可行——只要将bean定义为“prototype”类型即可。现代JVM很好地处理了对象的创建和销毁,服务对象通常可以很廉价地被实例化。

Ø 使用一个多线程服务对象,在其中使用普通Java语言的同步或并发类库以便保护任何读/写状态。如果需要控制的方法不多,同步实现起来很简单,工作起来也会很完美。当然同步不能阻止集群中另一台服务器上的同一段代码并发执行,但是EJB线程管理也同样做不到。

EJB实例池

与线程管理关系最为紧密的便是EJB的实例池。在各种EJB实例池中,最有价值的是无状态session bean缓冲池(这也是最简单的EJB实例池),因为无状态对象是缓冲池技术的理想用户。

在我看来,SLSB缓冲池的价值被高估了,尽管某些时候它确实有其价值。就像我曾经说过的,比起构思EJB规范时的Java 1.1 JVM,现代的JVM执行通常的垃圾收集要敏捷的多。如果时间回到1998年,我们的确需要实例池以避免垃圾收集器死掉,但现在真的还有这个必要吗?

某些应用服务器特有的EJB部署描述文件允许为每一个SLSB部署配置缓冲池大小,然而这种配置的价值是很可争议的。如果创建一个典型的SLSB只有相对较低的代价,那么配置一个比较小的缓冲池会产生不必要的竞争,而过大的线程池也不能改善吞吐量,因为吞吐量的决定因素是应用服务器所允许并发执行的线程的最大数量(线程池是一个应用服务器至关重要的服务,我将简短地加以讨论)。如果SLSB缓冲池的大小小于可以使用某个特定SLSB的最大线程数量,后来的调用将被阻塞,直到有一个EJB实例可以使用为止;如果SLSB缓冲池的大小大于线程的最大数量,那么吞吐量不会有任何提升。有人认为:不论任何场合,理想的缓冲池大小就是“希望访问一个特定SLSB的最大线程数量”,这种观点也同样是很可争议的。

设计EJB线程池的主要动机是避免垃圾收集和节省内存。比起Java 1.1 VM,现代JVM的垃圾收集效率要高得多;如今的内存也便宜得多。也就是说,比起当初,这两个动机如今都不是很重要了。

7页,页码:[1] [2] [3] [4] [5] [6] [7] 

上一篇:轻松使用Swing的树
下一篇:打造自己的个性化邮件服务器
标题:EJB的七年之痒 作者:熊节 来源:csdn
收藏此页】【打印】【关闭
站 内 搜 索
 

热 点 导 读
特 别 推 荐