HBCZT信息中心Weblogic Server性能调优建议

l        调优背景

HBCZT信息中心使用IBM X366服务器Windows2003运行其基于J2EE1.4技术的应用系统。另外运行一个基于COM技术的数据采集应用程序。该程序客户端读入用户填写的xls格式表格文件信息,并通过该程序将XLS内容封装成为XML并打包ZIP后发送到数据采集程序的服务器端,服务器端接受到文件后,对该ZIP包进行解包、并对解包后的XML信息进行解析、使用SQL逐条将记录插入到Oracle数据库中。数据库连接池已经设置为20,但批量数据插入数据库的时候(数据量至少500000条记录,一般情况5000000条记录)导致数据库异常缓慢。客户希望找到系统瓶颈,并提出相应性能调优建议。

l        总体思路

硬件调优、操作系统调优,数据库调优 略!我们假设都已经是最佳状态。由于本人负责WebLogic部分的调优,所以以下思路与内容均为WebLogic方面。特此说明

J2EE应用架构环境下的系统调优,首先我们一般会从应用程序出发,去审核代码,做到代码级的优化,然后再调整应用服务器(BEA WebLogic8.1)和数据库 (Oracle9i)的参数,最后当然是调整操作系统和网络的性能(包括硬件升级)。这是一种MDA的先进做法。诚然,在这样一个政务项目中,不可能完全按照这个思路来做,我们把目标首先定位在应用系统所在的应用服务器(BEA WebLogic8.1)上,通过对BEA WebLogic8.1的参数进行设置,使WebLogic8.1能够在最优化的环境中去运行其系统,然后对ORACLE数据的参数进行优化设置,最后进行性能测试再找出导致性能瓶颈所在的SQL代码或JAVA程序,考量其修改的可行性,并进行最终问题优先级认定,与瓶颈模块进行协商解决性能问题。当然,一般情况下我见过的案例都是出现了性能问题后才想到调优,而且一般都是先进行系统参数调整,实在解决不了才会对代码进行检查.实际上,我们应当将代码级的调优放在应用设计时来做,测试生产时修改代码将是一件极其痛苦的事情。

下表为一般性J2EE性能调优的参照情况一览表,供参考。

毛病

描述

症状

原因或治法

线性内存泄漏

每单位(每事务、每用户等)泄漏造成内存随着时间或负载线性增长。这会随着时间或负载增长降低系统性能。只有重启才有可能恢复。

随着时间越来越慢
随着负载越来越慢

虽然可能有多种外部原因,但最典型的是与资源泄漏有关(例如,每单位数据的链表存储,或者没有回收的回收/增长缓冲区)

指数方式内存泄漏

双倍增长策略的泄漏造成系统内存消耗表现为时间的指数曲线

随着时间越来越慢
随着负载越来越慢

通常是由于向集合(VectorHashMap) 中加入永远不删除的元素造成的。

糟糕的编码:无限循环

线程在 while(true) 语句以及类似的语句里阻塞。

可以预见的锁定

您需要对循环进行大刀阔斧的删剪。

资源泄漏

JDBC 语句,CICS 事务网关连接,以及类似的东西被泄漏了,造成对 Java 桥接层和后端系统的影响。

随着时间越来越慢
可以预见的锁定
突然混乱

通常情况下,这是由于遗漏了 finally 块,或者更简单点,就是忘记用 close() 关闭代表外部资源的对象所造成的。

外部瓶颈问题

后端或者其他外部系统(如鉴权)越来越慢,同样减缓了 J2EE 应用服务器和应用程序

持续缓慢
随着负载越来越慢

咨询专家(负责的第三方或者系统管理员),获取解决外部瓶颈问题的方法。

外部系统

J2EE 应用程序通过太大或太多的请求滥用后端系统。

持续缓慢
随着负载越来越慢

清除冗余的工作请求 ,成批处理相似的工作请求,把大的请求分解成若干个更小的请求,调整工作请求或后端系统(例如,公共查询关键字的索引)等。

糟糕的编码:CPU密集的组件

这是 J2EE 世界中常见的感冒。一些糟糕的代码或大量代码之间一次糟糕的交互,就挂起了 CPU,把吞吐速度减慢到爬行的速度。

持续缓慢
随着负载越来越慢

典型的解决方案就是数据高速缓存或者性能计数。

中间层问题

实现得很糟糕的桥接层(JDBC 驱动程序,到传统系统的 CORBA 连接),由于对数据和请求不断的排列、解除排列,从而把所有通过它的流量减慢到爬行速度。这个毛病在早期阶段很容易与外部瓶颈混淆。

持续缓慢
随着负载越来越慢

检查桥接层和外部系统的版本兼容性。如果有可能,评估不同的桥接供应商。如果重新规划架构,有可能完全不需要桥接。

内部资源瓶颈:过度使用或分配不足

内部资源(线程、放入池的对象)变得稀缺。是在正确使用的情况下加大负载时出现过度使用还是因为泄漏?

随着负载越来越慢
零星的挂起或异常错误

分配不足:根据预期的最大负载提高池的最大尺寸。过度使用:请参阅外部系统的过度使用。

不停止的重试

这包括对失败请求连续的(或者在极端情况下无休止的)重试。

可以预见的锁定
突然混乱

可能就是后端系统完全宕机。在这里,可用性监控会有帮助,或者就是把尝试与成功分开。

线程:阻塞点

线程在过于积极的同步点上备份,造成交通阻塞。

随着负载越来越慢
零星的挂起或异常错误
可以预见的锁定
突然混乱

可能同步是不必要的(只要重新设计),或者比较外在的锁定策略(例如,读/写锁)也许会有帮助。

线程:死锁/活动锁

最普遍,这是您基本的“获得顺序”的问题。

突然混乱

处理选项包括:主锁,确定的获得顺序,以及银行家算法。

 

l        调优建议

通过分析其配置。我们发现JDBC连接池存在性能问题。

WebLogic中就大量使用了池:JDBC Connection PoolSocket PoolObject PoolThread PoolI/O操作中,buffer是必须的,特别是对大文件的操作,不然容易造成内存溢出。字节操作最快,所以尽可能采用write(byte[])Buffered FileOutputStreamBuffered FileWriter要快,因为FileWriter需要UnicodeByte的转换。JDBC建议使用buffercache。为HttpServletResponse设置buffersize,使用wl-cache,缓存在JNDI树上获取的对象等等。
  此外,使用JDK 1.4的非阻塞I/O对性能也有很大提高。
  JDBC代码调优最大的原则就是使用WebLogic的连接池,而不是自己直连数据库。在我接触的很多自己实现连接池的项目中,大部分遇到死锁和连接泄漏的问题,最后得不得修改代码。而WebLogic提供了功能强大,性能良好的数据库连接池,我们要做的只是封装一个连接管理类,从JNDI树上获取数据源并缓存,得到连接,并提供一系列关闭数据库资源的方法。

对任何资源使用的原则是用完即关,不管是数据库资源、上下文环境,还是文件。数据库资源的泄漏极易造成内存泄漏,乃至系统崩溃。在使用完数据库资源后依次关闭ResultSetStatementConnection,而在一个数据库连接多次进行数据库操作时要特别注意ResultSetStatement依次关闭。

由于获取连接时默认自动提交方式,使用connection.setAutoCommit(false)关闭自动提交,使用PreparedStatement,批量更新,业务复杂或者大数据量操作时使用存储过程,尽量使用RowSet,此外设置记录集读取缓存FetchSize和设置记录集读取方向FetchDirection对性能也有一定的提高。

Servlet代码调优比较简单:在Servlet之间跳转时,forwardsendRedirect更有效;设置HttpServletResponse 缓冲区,如:response.setBufferSize(20000);init()方法里缓存静态数据,而在destroy()中释放它;建议在Servlet里使用ServletOutputStream输出图片等对象;避免在ServletJsp中定界事务等。

JDBC Connection Pool的调优受制于WebLogic Server线程数的设置和数据库进程数,游标的大小。通常我们在一个线程中使用一个连接,所以连接数并不是越多越好,为避免两边的资源消耗,建议设置连接池的最大值等于或者略小于线程数。同时为了减少新建连接的开销,将最小值和最大值设为一致。增加Statement Cache Size对于大量使用PreparedStatement对象的应用程序很有帮助,WebLogic能够为每一个连接缓存这些对象,此值默认为10。在保证数据库游标大小足够的前提下,可以根据需要提高Statement Cache Size。比如当你设置连接数为25Cache Size10时,数据库可能需要打开25*10=250个游标。不幸的是,当遇到与PreparedStatement Cache有关的应用程序错误时,你需要将Cache Size设置为0。尽管JDBC Connection Pool提供了很多高级参数,在开发模式下比较有用,但大部分在生产环境下不需调整。这里建议最好不要设置测试表, 同时Test Reserved ConnectionsTest Released Connections也无需勾上。 当然如果你的数据库不稳定,时断时续,你就可能需要上述的参数打开。

最后分析一下JDBC驱动程序类型的选择,Oracle提供thin驱动和oci驱动,从性能上来讲,oci驱动强于thin驱动,特别是大数据量的操作。但在简单的数据库操作中,性能相差不大。所以我建议对数据量至少500000条记录,一般情况5000000条记录的状况使用oci驱动。

通过分析其日志并使用GC资源查看。我们发现存在内存泄露的垃圾回收失败问题。

垃圾收集(GC)是指JVM释放Java堆中不再使用的对象所占用的内存的过程,而Java(Heap)是指Java应用程序对象生存的空间。堆大小决定了GC的频度和时间。堆越大,GC频度低,速度慢。堆越小,GC频度高,速度快。所以GC和堆大小是一组矛盾。为了获取理想的Heap堆大小,需要使用-verbosegc参数(Sun jdk: -Xloggc:)以打开详细的GC输出。分析GC的频度和时间,结合应用最大负载所需内存情况,得出堆的大小。通常情况下,我们建议使用可用内存(除操作系统和其他应用程序占用之外的内存)70-80%,为避免堆大小调整引起的开销,设置内存堆的最小值等于最大值即:-Xms=-Xmx。而为了防止内存溢出,建议在生产环境堆大小至少为256M(Platform至少512M),实际环境中512M~1G左右性能最佳,2G以上是不可取的,在调整内存时可能需要调整核心参数进程的允许最大内存数。对于sunhpjvm,永久域太小(默认4M)也可能造成内存溢出,应增加参-XX:MaxPermSize=128m。建议设置临时域-Xmn的大小为-Xmx1/4~1/3 SurvivorRatio8

为了获得更好的性能,建议在启动文件设置WebLogic为产品模式,此时sunhp jvm JIT引擎为-server,默认情况下打开JIT编译模式对性能也有帮助。调整Chunk SizeChunk Pool Size也可能对系统的吞吐量有提高。此外还需关闭显示GC: -XX:+DisableExplicitGC

建议Intel平台上使用jRockit(使用参数-jrockit)无疑大大提高WebLogic性能。本系统使用SUN JDK1.4.2_08jRockit支持四种垃圾收集器:分代复制收集器、单空间并发收集器、分代并发收集器和并行收集器。默认状态下,JRockit使用分代并发收集器。要改变收集器,可使用-Xgc:,对应四个收集器分其他为gencopy singlecom gencon以及parallel。为得到更好的响应性能,应该使用并发垃圾回收器:-Xgc:gencon,可使用-Xms-Xmx设置堆栈的初始大小和最大值,要设置护理域-Xns-Xmx10%。而如果要得到更好的性能,应该选用并行垃圾回收器:-Xgc: parallel,由于并行垃圾回收器不使用nursery,不必设置-XnsjRockit 还提供了强大的图形化监控工具Jrockit Management Console。可以查看GC性能问题。

通过实时查看并分析操作系统与ORACLE系统中的I/O信息。我们发现存在I/O读写占用资源率高且频繁问题。

WebLogic Server有两套套接字复用器:Java版和本地库。采用小型本地库更有效,尽量激活Enable Native IO(默认),此时UNIX默认使用CPUs+1个线程,Window下为双倍CPU。如果系统不能加载本地库,将会抛出一个异常:java.lang.UnsatisfiedLinkException,此时只能使用Java套接字复用器,可以调整socket readers 百分比,默认为33%。该参数可以在Console Server Tuning Configuration配置栏里设置。

l        步骤与说明

(略)

 

你可能感兴趣的:(数据库,jdbc,weblogic,servlet,server,数据库连接池)