提升EJB性能的方法(下)

发表于:2007-06-11来源:作者:点击数: 标签:
设计和 开发 后期 在一个企业级应用的开发后期阶段我们必须关注与 性能 相关的部分对整个系统进行调整。余下的4点就是针对工程的这个阶段。 9.模拟实际运行环境进行调整 这里的策略是查看整个系统,包括Web服务器,应用服务器和 数据库 服务器。可以考虑执行

设计和开发后期

在一个企业级应用的开发后期阶段我们必须关注与性能相关的部分对整个系统进行调整。余下的4点就是针对工程的这个阶段。

9.模拟实际运行环境进行调整

这里的策略是查看整个系统,包括Web服务器,应用服务器和数据库服务器。可以考虑执行以下任务:

运行整个应用程序

使用厂家推荐的版本和补丁

模拟实际运行的数据

使用实际运行的资源(比如设备)

利用负载测试工具模拟用户负载

10. 利用工具识别性能瓶颈

在这个方法中,我们使系统高负载并监视所有机器的CPU,内存 , I/O和网络的使用情况。识别性能瓶颈的地方后,反复测试,查看具体的问题所在。代码段1列出了各种用于测试程序的各方面性能的工具。表1列出了各种用于测试程序的各方面性能的工具。

应用范围 工具举例
CPU 使用 Unix中的"top"命令 (www.groupsys.com/topinfo)
内存使用 Unix中的"top"命令
I/O 使用 Unix中的"iostat"命令
网络使用 "netstat" 命令
Java 代码分析 堆栈分析工具Heap Analysis Tool (java.sun.com/people/billf/heap)

Optimizeit (www.optimizeit.com)

jProf (http://starship.python.net/crew/garyp/jProf.html)

JProbe(www.sitraka.com/software/jprobe)

PerfAnal (http://developer.java.sun.com/developer/technicalArticles/Programming/perfanal)
负载测试 LoadRunner (www-svca.mercuryinteractive.com/products/loadrunner)

e-LOAD (www.rswsoftware.com/products/eload_index.shtml)

Bean-test (www.testmybeans.com)

Web Bench (www.webbench.com)

Microsoft Web Application Stress tool (http://webtool.rte.microsoft.com)
SQL 跟踪 Oracle 中的Facility 与 TKPROF


 表1方便的工具. 要使EJB 应用程序取得高性能,重要的一点是识别性能瓶颈,可使用以上这些工具。

11.调整系统参数

应用程序中的许多参数是是可调的。例如,在操作系统中,我们可以调整TCP/IP参数,文件限制数,进程限制数和IPC限制数。在应用服务器上则可以调整连接池参数,EJB池大小,线程数,JVM个数以及JVM堆栈大小。在数据库服务器上,我们可以调整连接和进程的个数,共享池的大小,缓冲区大小,索引和SQL查询提示。在Web服务器上,可以调整保持连接的参数,线程/进程的个数和连接的backlog.

12.采用群集来满足高负载或考虑升级硬件

有时达到了某种程度时调整代码乃至整个系统会比增加新硬件的开销更大。这种情况下群集有显著的优势。大多数应用服务器都提供了群集的特性。一个EJB本质上就是在多台机器上运行的一组EJB服务器,用于增加系统的马力。一般群集中的每台应用服务器都含有相同的EJB。服务器群集采用各种不同的算法来实现负载均衡,例如round robin, random, sticky bit, server load等。可以在多个层次上采用群集,如图2所示。



图2: 群集的群集:在不同层次的群集增加了系统的马力


以上12点可以帮助我们设计和实现一个高性能的基于EJB的企业级应用。综合使用这些技巧以使我们的应用程序达到最优化。

代码段 1. 一个设计欠佳的远程接口

若使用以下接口,客户端必须多次调用才能获取数据。我们可以通过使用粗粒度的方法加速这个过程。

public interface Person extends EJBObject

{

public String getFirstName()

throws RemoteException;

public void setFirstName(String firstName)

throws RemoteException;

public String getLastName()

throws RemoteException;

public void setLastName(String lastName)

throws RemoteException;

public int getPersonId()

throws RemoteException;

public void setPersonId(int personId)

throws RemoteException;

}

代码段2. 一个更好的方法

这里我们对代码段1所展示的接口进行改进。只不过这些接口方法一次可以传递更多的数据。

public interface Person extends EJBObject

{

public PersonData getPersonData()

throws RemoteException;

public void setPersonData(

PersonData personData)

throws RemoteException;

}

/* 这是一个value对象. value对象可以取得 细线优化的方法*/

public class PersonData implements Serializable

{

PersonData(String firstName, String lastName,

int personId)

{

this. firstName = firstName;

this. lastName = lastName;

this. personId = personId;

}

public String getFirstName() {

return firstName ; }

public String getLastName() {

return lastName; }

public int getPersonId(){ return personId; }

private String firstName;

private String lastName;

private int personId;

}

代码段3. 建立一个Facade。

服务器端的facade为多个对象提供统一的接口。在这个例子中,ServerFacade为程序要用到的所有EJB的home handle提供缓存。

/* ServerFacade 为服务端的EJB 提供一个统一的接口。

所有客户端的类都通过ServerFacade访问服务器

*/

public class ServerFacadeBean implements SessionBean

{

file://缓存所有需要的EJB的home handle.

/* Person EJB 的home handle*/

PersonHome personHome = null;

/* Bank EJB的home handle*/

BankHome bankHome = null;

...

public ServerFacadeBean()

{

initialize();

}

public void initialize()

{

try

{ /* 初始化所有的Home handle.

We could also do lazy initialization

i.e., initialize as And when a home

handle is needed.

/* get initial context */

Context ctx = ...

if ( personHome == null )

personHome = (PersonHome)

ctx.lookup(“PersonHome”);

if ( bankHome == null )

bankHome = ( BankHome)

ctx.lookup(“BankHome”);

}

catch(Exception e)

{

/* 异常:查找失败*/

}

}

public PersonData getPersonData(int personId)

throws RemoteException

{

/*使用personHome缓存的副本*/

try

{

Person person = personHome.findByPrimaryKey(personId);

return person.getPersonData();

}

catch(Exception e)

{

/*异常处理*/

}

}

public BankData getBankData(int bankId)

throws RemoteException

{

/* 使用bankHome handle 缓存的副本*/

try

{

Bank bank =bankHome.findByPrimaryKey(bankId);

return bank.getBankData();

}

catch(Exception e)

{

/*异常处理*/

}

}

...

}


代码段4.一个调用

为了避免一次远程调用返回数据库的一行,可以用会话EJB对象将所有的数据打包成单个调用。
public class ServerFacadeBean implements SessionBean

{

...

>// 将行向量返回给客户端

public Vector findPersonsWithFirstName(

String firstName) throws RemoteException

{

Vector vector = new Vector();

Enumeration enumeration = null;

try

{

enumeration = personHome.findPersonsWithFirstName (firstName);

PersonData personData = null;

if ( enumeration != null )

{

while ( enumeration.hasMoreElements() )

{

Person person = (Person)enumeration.nextElement();

personData = person.getPersonData();

vector.addElement(personData);

}

}

}

catch(Exception e)

{

>/* 异常处理 */

}

return vector;

} ...

}


原文转自:http://www.ltesting.net

...