WebLogic Server中CMP实体bean的性能调优[5] 软件测试
使用read-mostly模式
WebLogic Server通过将一个只读CMP bean和一个读写CMP bean映射到同一数据中为您提供了一个实现read-mostly模式的机制。您的应用程序应该用只读bean来读取数据,用读写bean来修改数据。只读bean按照上述部署描述符中read-timeout-seconds元素所指定的间隔从数据库中加载数据。为了保证只读bean总是返回当前数据,应该在读写bean更改数据时使只读bean无效。您可以通过在weblogic-ejb-jar.xml中的entity-descriptor小节的invalidation-target元素中指定该bean,来配置服务器,使其自动让相应的只读bean无效。这只能用于CMP 2.0实体bean。虽然该模式提供了缓存方面的好处,但是也有严重的不足。当使用该模式时,您应用程序中的大量实体bean将被有效地加倍,对应用程序的启动时间和内存造成影响。同样,开发人员需要记住,只读和读写操作应该使用不同的bean,这经常会令人混淆。
值得一提的是,在旧版本的WebLogic Server中(没有对只读模式的通过invalidation-target的内在支持),仍可以使用它。回忆一下前面讲过的,根据EJB规范,如果EJB抛出一个RuntimeException或者它的子类物,容器就应该销毁bean实例。因此,可以在实体bean的只读版本上暴露这样的destroyMe()方法,并从读写bean的ejbStore()方法中调用它。这就是著名的sepukku模式。
在读/写CMP bean的事务间缓存
另一种更先进的长期缓存的方法是通过将weblogic-ejb-jar.xml中的cache-between-transactions元素设置为true来配置bean。这种情况下,只有客户端首先引用该bean或者事务被回滚时WebLogic Server才会调用ejbLoad()来从数据库中加载数据。
尽管从理论上说,您可以对除数据库并发之外的所有并发策略使用该方法,但是在实践中,只有对乐观并发使用该方法才有意义。当应用于只读并发时,该设置被忽略,因为bean数据已经被缓存;当应用于排他性并发时,只有EJB具有对底层数据库的排他性访问时才起作用,而这是极少出现的情况。此外,当具有排他性并发的bean被部署在集群中时,WebLogic Server自动禁用事务间的缓存,因为集群中的任何服务器都可能更新bean数据,并且没有用来在节点间同步或禁用缓存值的机制。这使得我们在进行长期缓存时只有一种可行的并发策略:乐观并发。
如前所述,对于利用乐观并发策略部署的bean,WebLogic Server有一种内在机制,用来通过verify-columns检测底层数据变更。虽然乐观并发本身只能为数据库并发带来少量性能改善,但可利用事务功能间的缓存提供更大的改善。如果在EJB缓存中bean实例已经可用的话,将cache-between-transactions设置为true将使WebLogic Server忽略对数据库的调用。对于某些类型的应用程序(其中同一对象在短期内被不同事务多次访问),这可能导致显著的性能改善(在某些环境下,最多百分之30到40)。自然地,既然我们使用的是乐观并发,您的应用程序必须做好在检测到并发冲突时处理OptimisticConcurrencyException的准备。当OptimisticConcurrencyException(RuntimeException的子类型)被抛出时,WebLogic Server 从缓存中丢弃一个EJB实例。注意,如果您将delay-updates-until-end-of-tx设置为true(默认),除非事务承诺否则就得不到乐观异常,并且如果使用的是容器受控事务这将在应用程序代码之外。
与read-mostly模式(不提供通知集群中其他节点其中一个节点的数据发生变更的机制)相比,当具有乐观并发的bean被更新时,一个通知将被广播给其他集群成员,并且缓存bean实例将被丢弃,以避免乐观冲突。由于WebLogic Server不广播数据变更本身,而是只广播某些种类的bean标识符,这种跨集群的缓存无效措施在提高性能和网络带宽利用率方面很有效。WebLogic Server自动完成这种缓存无效工作,bean开发人员不需要再做其他配置。当对同一个bean发出下一个请求时,新鲜的数据将被从数据库中加载。