| BEA WebLogic Server™ 8.1 EJB 容器提供了可用于调整 EJB 应用程序的丰富参数集。这些参数暴露在特定于 WebLogic 的部署描述符中,即 weblogic-ejb-jar.xml 和 weblogic-cmp-rdbms-jar.xml 中。 WebLogic 文档和部署描述符 DTD 提供了这些调整参数、有效值以及如何设置它们的全面描述。
调整 EJB 应用程序需要掌握这些参数,而正确地设置这些参数是一项富有挑战性的任务。从我与 J2EE 开发人员、客户和支持工程师合作时获得的经验来看,我认为从应用程序的角度解释这些参数是非常重要的。在本文中,我将使用基于用例的方法来解释这些参数,并描述如何在不同的场景中调整参数。 EJB 容器的一些内部工作方式,以及它们如何受到这些调整参数的影响,将会逐一解释。这将为开发人员和管理员提供一些重要信息,以帮助他们调整 EJB 和更加高效地使用服务器资源,从而获得 EJB 应用程序的最优性能。
本文是两篇系列文章中的第一篇,讲述了针对无状态会话 bean 和有状态会话 bean 来调整 EJB 应用程序。第二篇文章将重点讲述实体 bean 、 CMP bean 。本文根据 WebLogic Server version 8.1 , Service Pack 3 中的 EJB 容器编写。
调整无状态会话 Bean
无状态会话 bean 是不维护任何代表客户端会话状态的会话 bean 。因为没有调用方维护的任何状态,无状态会话 bean 的每个实例与其他每个实例都是等价的。实例没有区分,任何实例都可以用于满足大量的客户端。这些 bean 主要用于提供或者暴露某些类型的服务。
如果您需要把银行帐户( Bank Account )设计为无状态会话 bean ,则可以将存款( deposit )、提款( withdraw )和余额操作暴露为服务。状态(这里意味着帐户)保存在数据库中,而不是 bean 实例中,因为任何 bean 实例都可用于处理请求。在该情况中,您可以在每次进行存款或提款操作,或者检查余额的时候传送帐号。
WebLogic Server 提供了不同的参数,可以用于调整无状态会话 bean 。这些参数在 weblogic-ejb-jar.xml 描述符文件中提供。以下内容考察了池( pooling )参数,有助于调整这些参数的统计信息,最后介绍了集群( clustering )参数。
池参数
WebLogic Server 中的 EJB 容器使用池( pooling ) 来管理无状态会话 bean 实例。容器维护一个可用实例的池。这些是一些实例,一旦它们进入到服务器中,它们就可以用于维护方法调用。
当发出无状态会话 bean 方法调用的时候, EJB 容器从池中捕获一个可用的实例,并使用该实例来执行调用。实例在方法调用完成之后返回到池中。池策略帮助容器使用少量的 bean 实例来维护大量的客户端,同时缩短无状态 EJB 的响应时间。
EJB 容器为部署的每一种无状态会话 bean 维护不同的池。服务器提供两种参数来配置无状态会话池: initial-beans-in-free-pool 和 max-beans-in-free-pool 。
- initial-beans-in-free-pool
该参数指定池的初始大小。当部署无状态会话 bean 时, bean 实例的这个编号由 EJB 容器实例化。容器实例化 bean ,调用 setSessionContext() 和 ejbCreate() 方法,然后将 bean 放在可用实例的池中。这允许 EJB 容器立即响应有关 bean 的方法调用,而不用初始化 bean 。
设置该参数的典型用例是无状态会话 bean 的 ejbCreate() 或者 setSessionContext() 方法初始化一些大型对象,例如连接到数据库或者遗留系统。在这种场景中,设置参数会初始化 bean ,并使它们可以立即用于维护请求,从而缩短响应时间。
- max-beans-in-free-pool
该参数确定池的最大容量。如果池中的所有实例都处于忙碌状态,也就是说响应方法调用,此时一个新的请求进入池中,那么容器就会创建另一个 bean 实例来响应请求。然而,服务器仅可以在它达到 max-beans-in-free-pool 限制的时候才可以创建新的实例。因此,参数是无状态 EJB 可以创建 bean 实例数的上限。
如果已经达到上限,而所有的实例处于忙碌状态,则新的请求必须等待,直到再次出现可用实例。等待周期等于请求的事务超时。如果 bean 在该期间内仍不可用,事务将被回滚,请求将不被响应。
在大多数情况中, EJB 开发人员不应该配置该参数。这将使 EJB 容器按照需要创建一个 bean 实例,并消除将要返回到池的 bean 的等待时间。池中可用 bean 实例的数量改进了处理无状态 EJB 请求的并发性,但不是全部。无状态 EJB 可以达到的并发程度取决于 WebLogic Server 中执行线程的数量,或者取决于执行线程池( Execute Thread Pool ),如果您已经配置为 EJB 配置了执行线程池的话。
使用该参数在空闲池( free pool )中限制实例数量的典型用例是无状态 EJB 可以保持与后端系统的连接,并且可用连接的数量是有限的。举例来说,假设后端 / 遗留系统允许最多 20 个连接。如果这些连接在无状态 EJB ( setSessionContext() 或者 ejbCreate() )中实例化,那么可以配置 max-beans-in-free-pool 参数为 20 。因此,如果所有 bean 实例都处于忙碌状态,同时第 21 个请求进入池中,那么空闲池 20 个 bean 的硬性限制将不允许创建新的 bean 实例,从而阻止了新的后端连接。该参数可用于在达到极限时阻止后端连接。
运行时统计信息
EJB 容器提供了大量的运行时统计信息,用于监控 EJB 应用程序。 WebLogic Server 管理控制台使用这些统计信息来计算特定的比率,然后用于调整池参数。
在此,我们将考虑应当调整池参数的某些条件:
- 池失败率高
池失败率高( Pool Miss Ratio )按照(失败总数 / 访问总数) *100 进行计算。其结果说明了当无 bean 可用时,从池中获得一个 bean 所需发出请求的次数。
原因: 所有 bean 实例都在使用中,因为请求的数量很多。在这种情况中,空闲池中没有可用实例来响应新的请求。这就导致产生一次请求池失败。
措施: 执行负载测试,通过监控 Beans In Use Current Count 参数查找峰值负载。调整 max-beans-in-free-pool 大小为负载测试期间该参数可以达到的最大值。空闲池中的 Bean 占用内存,因此在调整该参数的时候也应考虑内存的可用性。
原因: Bean 正在被销毁。如果 bean 代码中抛出非应用程序异常,则 bean 实例就会被销毁。如果 bean 实例被销毁,当方法执行完成的时候,它就不会返回到空闲池中。空闲池中的 bean 就会减少,这就会导致池失败。这样就会导致产生额外的创建 bean 实例并初始化它的开销,从而影响性能。
措施: 避免 bean 代码中出现非应用程序异常。
- Bean 销毁率高
Bean 销毁率( Destroyed Bean Ratio )按照 (销毁总数 / 访问总数) *100 来 计算。
其原因和措施与上一条讨论的一样。
- 池超时率高
池超时率( Pool Timeout Ratio )按照 (池超时总数 / 访问总数) *100 来计算。
原因: 池超时率过高意味着池没有根据调用数量恰当调整。随着请求数量不断增加, EJB 容器创建更多的实例,直到其达到 maximum-beans-in-free-pool 值。如果所有的实例都处于活动状态,并且已经达到最大空闲池大小,则新的方法请求必须等待,直到实例返回到池中。等待期间就是池的超时值,它与为无状态 EJB 配置的事务超时值相同。
措施: 在 weblogic-ejb-jar.xml 描述符中增加事务超时值。但是,这是应用程序级设置,还有其他方法可以使用。如果超时值增大,就会降低吞吐量,因为响应时间也会随之延长。作为一种选择,可以使用提高 max-beans-in-free-pool 这一更安全的方式。
集群参数
无状态编程模型使得少量 bean 实例响应大量客户端成为可能。当该模型应用到 WebLogic Servers 集群中时,事情就会变得更麻烦。 WebLogic 集群可以充分利用更大的空闲实例池,这个池包含集群中所有服务器上的池。它与执行调用的服务器无关,因为代表客户端的 bean 没有维护任何状态。这还归因于无状态会话 bean 所提供服务的可扩展架构。
WebLogic Server 充分利用这种无状态模型来创建智能存根( smart stub ),称之为副本感知存根( replica-aware stub )。副本感知存根保存了集群中所有可用服务器的清单。它可以监听所有故障,并在集群中另一台可用服务器中重试该调用。
服务器提供了一些配置参数,用于配置集群中的无状态会话 bean。
- home-is-clusterable
该参数在设置为 true 时允许本地存根负载平衡集群中服务器之间本地接口上的调用,该集群中部署了无状态 EJB 。如果集群中有任何一台服务器不可用,调用将转移到集群中驻留无状态 EJB 的其他服务器中。将该参数设置为 true ,仅为本地接口中的调用提供了负载平衡和故障转移的集群功能,也就是创建方法。
home-load-algorithm 参数可以和 home-is-clusterable 参数一起使用,指定本地存根用于平衡无状态本地 EJB 副本所使用的负载平衡算法。
- stateless-bean-is-clusterable
该参数允许副本感知存根( replica-aware stub )负载平衡集群中服务器之间远程接口中的调用,该集群部署了无状态 EJB 。如果客户端通过副本感知存根发出的调用失败,存根可以监听这种故障,并在另一个副本中重试调用,也就是说,在集群中驻留在其他服务器的无状态 EJB 中重试。将该参数设置为 true ,仅为远程接口中的调用提供了负载平衡和故障转移的集群功能。自动故障转移仅出现在方法被声明为幂等的时候。这将在下面进行描述。
stateless-bean-load-algorithm 参数可以和 stateless-bean-is-clusterable parameter 一起使用,以指定远程存根用于负载平衡无状态 bean 副本所需的负载平衡算法。
- idempotent-methods
一种可以幂等调用的方法,调用多次和调用一次产生的结果是一样的。通常情况下,在服务器端不转换任何状态的方法是幂等的,举例来说,任何只读方法。所有无状态会话 home 方法都是幂等的。对于远程界面中的方法,您必须使用上述参数显式声明哪些方法是幂等的。如果前一台服务器出现故障的话,方法幂等允许在集群中的另一台服务器中重试方法调用。
您可以从声明无状态 EJB 方法幂等中获得这种优势,方法暴露的服务更加可用,因为调用在失败的时候可以进行重试。例如,集群配置为一个集群中包含三台服务器: serverA 、 serverB 、 serverC 和部署在集群中的无状态 EJB 。当客户端在 EJB 上调用一个方法时,让我们假定 smart stub 在 serverA 上发出第一个调用。如果 serverA 在此时出现故障,则调用失败。但是,如果方法是幂等的, smart stub 就会解释故障,并在 serverB 上重试方法。如果 serverB 上的调用由于一些原因也失败了,则调用就会在 serverC 上重试。
使用 cluster-aware 无状态 EJB 可以帮助您开发可扩展的和可靠的服务。
但是,当指出无状态 方法幂等的时候需要注意。仅有在服务器端不更改任何状态或者生成相同结果(不考虑它们被调用的次数)的方法才可以设置为幂等。
调整有状态会话 Bean
有状态会话 bean 是代表客户端维护会话状态的会话 bean 。会话状态需要在方法和处理之间保留。由于每一个 bean 实例维护特定客户端的状态,所以每一个 bean 都有其自有的独特身份。状态在 bean 的 member 字段中维护,当 bean 在服务器上创建的时候,由特定的客户端初始化。这些 bean 主要用于维护特定客户端的服务器端状态。
有状态 EJB 在代码上非常类似于无状态 EJB ;但是谨记每一种 bean 的编程模型是不同的。
如果您需要将银行帐号设计为有状态会话 bean ,则每一个客户端将把其状态存储在服务器上的 bean 中。状态(即帐号和余额)在客户端创建 bean 时进行初始化,而后这个 bean 实例将用于该客户端调用的任何方法。因此,当执行有关该帐户的任何操作时,客户端不需要像无状态情况下那样每次都传送帐号。
WebLogic Server 提供了各种参数,来调整有状态会话 bean 。这些参数可以在 weblogic-ejb-jar.xml 描述符文件中设置。让我们看一看如何设置这些参数,以及相关的用例。
缓存参数
在无状态编程模型中,每一个 bean 实例与其他实例都是一样的,这就使维护可用实例池成为可能。池中的任何 bean 实例都可用于代表客户端维护方法。
但是,在有状态模型中,每一个 bean 实例都有惟一的身份。每一个客户端在服务器端都有其自有的 bean 实例,并且容器总是将调用路由到与特定客户端相关的特定实例中。该模型不允许使用任何类型的池化策略。因此, WebLogic Server 使用优化的内存中缓存来提高有状态 EJB 的性能。有状态 EJB 缓存存储活动的 bean 实例和不活动的 bean 实例。活动的 bean 实例是当前正在执行客户端所调用的方法的实例或者作为正在进行中的事务的一部分的那些实例。不活动 bean 是那些已经完成执行客户端调用的方法的实例,或者不属于正在进行中的事务的那些实例。一些已经空闲了 idle-timeout-seconds 这么长时间 的不活动 bean 称为空闲 bean ,适合于钝化( passivation )。
WebLogic Server 中的有状态 EJB 缓存可以通过配置来控制大小、缓存算法和钝化的超时设定。以下部分讲述了用于配置缓存的参数。
- max-beans-in-cache
该参数指定缓存的最大容量。它是可以存放在内存中缓存中的活动 bean 实例的数量上限,如果没有设置,缺省值是 1000 。当缓存中需要更多空间而缓存已经达到 max-beans-in-cache 容限时, EJB 容器就钝化空闲 bean 和最近最少使用的 bean 。如果缓存已满,并且容器无法钝化任何 bean 实例(因为所有的 bean 都处于活动状态),就会抛出 CacheFullException 。
缓存的内存资源占用与缓存中 bean 实例的数量和每一个 bean 实例中保存的数据成正比。
适当地调整有状态 EJB 缓存的大小非常重要。小于必需缓存大小的内容容量会导致磁盘之间过多的钝化和激活,从而导致性能降低。最大缓存容量可以根据服务器内存的容量、给定时间内活动客户端的数量或者每一个 bean 实例中保存的数据进行调整。
WebLogic Server EJB 容器提供了帮助调整该参数的监控统计数字。具体来说, Cache-Miss 比率和 Passivation/Activation 计数在此扮演了重要的角色。该比率定义为 (Cache Miss Count / Cache Access Count) * 100 。高缓存不中比率或者高钝化和激活计数说明您的缓存需要调整。
原因: 有状态内存中高速缓存 保存 bean 实例的有限工作集。当需求随着客户端数量的增长而达到峰值的时候,容器就会钝化最近仍没有使用的 bean 。如果一个客户端调用已经钝化的实例中的方法,就会导致一次缓存不中。容器需要从磁盘中激活 bean ,并将其放回到缓存中,以调用方法。因为有状态 EJB 空闲了太长时间,因此,其被从缓存和磁盘中删除,这样也会导致缓存不中。
措施: 如果您的应用程序包含有状态 EJB 客户端,这样,一些客户端就会比其他客户端积极,增加 max-beans-in-cache 可以帮助您维护缓存中经常被调用的 bean 。您可以最大程度地减少这些经常使用的 bean 的缓存不中。如果所有的客户端以固定的间隔访问有状态 EJB ,那么, EJB 的工作集就会经常变化,在这种情况中,提高 max-beans-in-cache 不会带来很大的帮助。
总的来说,增加 max-beans-in-cache 和 idle-timeout-seconds 应当会降低缓存不中比率。但是,这也将占用更多的内存资源。
- idle-timeout-seconds
该参数用于钝化有状态 EJB 。一个已经空闲了 idle-timeout-seconds 这么长时间 的不活动 bean 被认为是空闲的,适合于钝化。一个适合于钝化的 bean 实际上是否被钝化到磁盘还取决于其他因素,如最大缓存容量、缓存中的可用空间和缓存策略。缓存策略将在随后进行解释。
该参数应当设置为您需要 bean 在缓存中保留的时间。如果您拥有这样一个用例,客户端在一段较长时间内主动访问有状态 EJB ,则应增加 idle-timeout-seconds 。这将会使 bean 在缓存中停留更长的时间,从而可以用于响应方法请求。这将减少钝化和激活,缩短响应时间。
同时,更大的 idle-timeout-seconds 值意味着更大的缓存,继而意味着更多的内存资源。
- session-timeout-seconds
该参数控制磁盘上钝化 bean 的生命周期。钝化到磁盘的 bean 会占用磁盘资源。为了最大限度地降低磁盘资源使用率, WebLogic EJB 容器包含了一种清洁机制:定期运行的触发器可以从磁盘中删除钝化的实例。保存时间超过 session-timeout-seconds 的 bean 实例将定期从磁盘中删除。根据缺省值,该参数的值等于 idle-timeout-seconds 的值。对于某些应用程序来说,您可能需要将该参数调整为一个与 idle-timeout-seconds 不同的值。
让我们考虑一个将购物车实现为有状态 EJB 的用例。用户一般选择货物,并添加到购物车中。并不是所有的用户都会继续,并购买放在购物车中的货物。如果用户中断连接或者关闭浏览器,那么状态(货物已选择)将仍然为用户维护在特定的 bean 实例中。用户很可能会在一两天之后登录,并访问他或者她的购物车,以购买以前选择的货物。不是让用户再次浏览和选择货物,而是需要显示用户以前选择的所有货物。做到这一点的方法是,通过使特定于用户的 bean 实例在该期间内保存在缓存中,即通过配置较长空闲超时。但是将特定用户的购物车 bean 在内存中保存一天会不必要地消耗服务器资源,从而降低性能。
有效的策略是配置 session-timeout-seconds 参数为较长一段时间(几天),以便 bean 实例长期在磁盘上保持活动状态。通过在用户重新登录的时候激活 bean ,该状态可以在内存中恢复。在这种场景中,设置 idle-timeout-seconds 为一个较低的值(以小时为单位),而 session-timeout-seconds 为一个较高的值(以天为单位),使您可以使用有限的内存更长时间地维护更多的客户端状态。
- cache-type
WebLogic Server EJB 容器提供了两种缓存策略,最近未使用( Not Recently Used , NRU )和最近最少使用( Least Recently Used , LRU ),用于控制有状态会话 bean 到磁盘的钝化。让我们详细研究一下这两种策略:
最近最少使用
这个 热切的 钝化策略定期将空闲 bean 钝化到磁盘上。如果 bean 实例已经不活动了 idle-timeout-seconds 这么长时间 ,即在这段时间段内它没有维护任何方法,就认为该 bean 实例是空闲的。利用这个策略,钝化将定期作用于空闲 bean ,即使缓存没有任何压力,这个期间是由 idle-timeout-seconds 参数的值来决定的。但是,如果缓存有压力,那么空闲了 idle-timeout-seconds 这么长时间 的不活动 bean 也将被钝化。在这种情况中,最近最少使用的不活动 bean 将被选择进行钝化。活动的 bean (即,执行方法的 bean 实例或者是事务的一部分的 bean 实例)将永远不被钝化。
图 1. LRU 缓存策略
最近未使用
这个 懒惰的 钝化策略仅在缓存有压力的时候将 bean 钝化到磁盘,这意味着仅当缓存达到 max-beans-in-cache 容量,并且有很多需求时才使用该策略。当缓存没有压力的时候,避免空闲的 bean 的钝化可以减少序列化的开销。
但是,当缓存有压力的时候,容器就会从缓存中删除任何空闲 bean 实例(至少针对 idle-timeout-seconds 来说是 空闲的 bean ),而不是将他们钝化。这样,空闲实例就不会消耗内存或者磁盘资源。当缓存有压力的时候,容器还将钝化最近未使用的其他不活动的 bean 实例。
图 .2. NRU 缓存策略
选择哪种策略,在什么场景中选择
钝化是 bean 状态序列化并写入磁盘的过程。相反的过程(即激活)使 bean 状态取消序列化,即从磁盘中读取。钝化和激活是昂贵的操作,而如果能将这些操作减少到最低限度,有状态 EJB 可以执行得更好。
为应用程序选择正确的缓存策略有助于提高吞吐量和节约服务器的内存资源。在配置缓存策略时需要考虑的主要因素有:
1. 服务器内存
2. 方法的响应时间
3. 客户端的长期和短期活动性。
当服务器内存非常紧张而调用有状态 EJB 的客户端又处于短期活动时, LRU 策略是理想之选:客户端在特定的时间段中调用 EJB ,而在其后的时间段释放了。在这种情况下, bean 在空闲时(在 idle-timeout-seconds 之后)被钝化是可以接受的,因为后续将不会再访问 EJB (或者很少访问)。由于 bean 实例不会再次激活,我们可以让其在空闲时钝化,从而保持内存资源。
当内存资源不足的时候,使用 LRU 策略,这样空闲 bean 就会被钝化,而有状态 EJB 缓存就可以适当地使用服务器内存。
当吞吐量非常大而内存资源又相当丰富时, NRU 缓存策略是一个较好的选择。使用该策略,可以通过最大限度地减少有状态 bean 实例的钝化和激活来缩短响应时间。钝化仅在缓存有压力的时候才会发生,这意味着一旦需要更多的空间,那么缓存就会达到 max-beans-in-cache 。如果您碰到长期在有状态 EJB 上调用方法的客户端,那么您可能需要 bean 实例在缓存中可用,以便立即响应客户端请求。在这种场景中,可以选择 NRU 策略来缩短有状态 EJB 的响应时间。
总的来说, 当方法响应时间非常关键,而您又有足够的内存资源时, NRU 策略是理想之选。在这些情况中,拥有足够大的缓存可以确保 bean 随时立即响应请求。
不使用特定缓存策略的情况
如果配置了最大缓存容量,足以处理给定时间内活动客户端的数量,则不要使用 LRU 策略,因为它将导致不必要的钝化和激活系统开销。
在有状态 EJB 包含大量数据的应用程序中,钝化和激活可能会花费较长的时间,并影响响应时间。如果您期望更高的吞吐量,请避免使用 LRU 策略。不过,需要注意的是,较少的钝化说明 bean 和引用对象将在内存中保存更长的时间。
在内存资源很少的情况中,避免使用 NRU 策略。
始终在有状态 EJB 上调用 ejbRemove()
尽管它不是一个调整参数,但这也是高效使用服务器资源和提高性能一个最佳实践,因此在这里很有必要提一下。 J2EE 开发人员常常会犯这样的错误,在有状态 bean 上不调用 remove() 。考虑这样一种常见情况, web 层中的 servlet/JSP 创建有状态 bean ,并将 bean 句柄存储在 HTTP 会话中。当 HTTP 会话超时(由于用户不活动状态产生)时, bean 在服务器的有状态缓存中仍处于活动状态。这一不再使用的 bean 所带来的代价是:
- 服务器内存未高效使用——不再使用的 bean 仍然在内存中,直到其被钝化。由于创建 bean 的客户端已经不存在, bean 就会不必要地占用内存。如果有状态 EJB 已经建立集群,非调用删除将 bean 保存在主服务器的缓存中,而其复制的副本保存在第二台服务器上。除了 bean 之外,两台服务器中的复制机制都会占用内存。
- 性能下降——不再使用的 bean 将会通过钝化到磁盘中,从内存中删除。这会影响性能,因为钝化是一项昂贵的操作,它涉及到将 bean 序列化到磁盘中。
在这种情况下,使用 HttpSessionListener 接口对 bean 调用 remove() 。当 HTTP 会话即将失效的时候,实现上述接口的 class 通过调用 sessionDestroyed() 方法来接收事件通知。可以在该 callback 方法中删除与 HTTP 会话相关的有状态 bean 。这种设计有助于高效使用服务器内存,同时提高性能。
Clustering 参数
对于无状态 bean , WebLogic Server 中的 EJB 容器提供了配置参数,用于配置集群化的有状态会话 bean 。负载平衡可以用于本地存根,故障转移特性可以用于远程存根。
- home-is-clusterable
该参数设置为 true 的时候,允许本地存根在部署有状态 EJB 的集群中跨多台服务器负载平衡本地接口上的调用。它类似于无状态 EJB 的 home-is-clusterable 参数:有状态 EJB 本地接口中的创建方法是负载平衡的。
home-load-algorithm 参数可以与该参数一起使用,以指定本地存根用来在有状态 EJB 本地副本之间实现负载平衡所需的负载平衡算法。
- replication-type
该参数确定有状态 EJBObject 的集群行为。它可以设置一两个值: inMemory 或者 None . 。当该参数设置为 InMemory 时,有状态 EJB 是集群化的。复制类似于 HTTP 会话,因为状态是在一对服务器上维护的。当本地接口在一台服务器上创建有状态 EJB 时,集群中的另一台服务器在复制 EJB 状态的地方被选中。因此,状态可以用于两台服务器,第一台是创建 EJB 的服务器,第二台是被选择用于复制的服务器。 EJBObject 存根返回给包含了该有状态 EJB 的第一台和第二台服务器的位置的客户端中。第一台服务器上状态的任何改变都会传递给第二台服务器。 WebLogic Server 提供了优化,因为只有状态差异被传递给第二台服务器。对于该事务中涉及的有状态 EJB ,复制发生在事务提交之后。对于非事务性 EJB ,复制发生在每一次方法调用的末尾。
对于有状态 EJB 来说,在远程接口中没有针对方法的负载平衡。客户端将始终被路由到第一台服务器上的 EJB 中,直到它不可用。支持故障转移。如果第一台服务器出现故障,远程存根自动在第二台服务器上重试调用。那么,第二台服务器就变成了第一台服务器,并选择一台新服务器作为第二台服务器。客户端的所有未来调用都将路由到新的第一台服务器中。存根基于新的服务器对进行更新。
注意,此处有些一些例外。
1. 如果第一台和第二台服务器同时出现故障,则状态将丢失。
2. 如果第一台服务器在复制到第二台服务器之前出现故障,则状态将失效。谨记复制发生在事务末尾。
设置复制类型为 InMemory ,以充分利用集群化有状态 EJB 提供的可靠性。
其他参数
WebLogic Server EJB 容器提供了一些参数,这些参数允许 EJB 偏离在 EJB 规范中描述的行为。在本节中,这些参数根据它们可以应用的场景一起描述。
- allow-concurrent-calls
EJB 规范不允许客户端向有状态会话对象发出并发调用。如果有状态会话 bean 实例主动处理调用客户端的调用,同时从相同或者不同的客户端针对同一 bean 实例发出另一个调用,则假定容器抛出 RemoteException 。
将该参数设置为 true ,允许您忽略该行为。 EJB 容器可以阻止这种并发调用直到前一个调用完成,并使其仅在前一个调用已经完成的情况下进行。因此,容器序列化针对有状态 bean 实例的访问。
缺省情况下,该参数设置为 false ,以符合规范行为。然而,如果拥有一个调用有状态 EJB 的多线程客户端,这种情况是可能的:并发调用从同一 bean 实例中发出。在这种情况中,将该参数设置为 true 将允许并发调用。
在有些情况下,由于在有状态 bean 上发出并发调用,您会看到一个 LockTimeoutException ,设置该参数为 true 可以有助于避免这一异常。
- allow-remove-during-transaction
EJB 规范禁止 bean 开发人员在参与事务的有状态会话 bean 上调用删除方法( remove )。它会导致产生 RemoveException 。 allow-remove-during-transaction 参数让您忽略这种行为。
如果您碰到这样一种情况,有状态 EJB 作为长期运行事务的一部分调用,它的部分操作完成之后,从事务中删除有状态 bean 非常有用。等待在 bean 上调用 remove 方法直到事务结束,这会导致 bean 长期占用内存。在这种情况中,在事务中调用 remove 方法有助于高效使用服务器内存资源。
但是,您需要小心地设置该参数,除非您确定事务中的 remove 方法不会导致任何不必要的副作用。例如,如果有状态 EJB 实现了 SessionSynchronization 接口,并且在更改应用程序状态或者解除后端连接时期待 beforeCompletion() / afterCompletion() 回叫,则不要设置该参数为 true 。设置该参数为 true ,允许 EJB 在事务提交之前删除,而 bean 不会收到容器的同步回叫。这会产生无法预料的结果 。
结束语
本文给出了 BEA WebLogic EJB 容器中可用于会话 bean 的各种调优参数,以及如何在不同情况下高效使用这些参数的建议。这应该有助于您调优 EJB 应用程序,使其更加高效地运行。本系列的下一篇文章将讨论如何调优实体 bean 。 |