H5W3
当前位置:H5W3 > 其他技术问题 > 正文

优化 Java 垃圾收集器改进系统性能

2006 年 11 月 30 日

    在系统的性能测试过程中,当系统的处理能力有某种变化趋势时, 除了关于等待队列、执行线程,EJB 池以及数据库连接池和 Statement Cache 方面的调优外,还要考虑到 Java 垃圾收集器(Garbage Collection,本文简称 GC)对系统性能的影响。本文介绍了如何分析系统的处理能力和 GC 之间的关系,以及如何通过改进 JVM 的配置来优化 GC,以提高系统的性能。

项目背景

    某个大型项目的 CPU100% 的压力性能测试, 用以检查在系统运行环境不正常的情况下,系统可以运行到何种程度。测试过程是: 请求测试的模拟器向系统不断发出大量请求, 系统接受由模拟器发出的请求,然后将请求置于一个任务池中,如果当前有空闲的线程,则该线程会从任务池中取出一个任务进行处理,如果没有空闲的线程,则该任务一直会待在任务池中,直到有空闲的线程来处理它。因此,任务池的队列的长度从某种意义上可以代表整个系统的处理能力,任务池队列的长度用 Q 值来表示,如果 Q 值超出了一定限额,将会有流量控制的线程将超出限额的待处理任务丢弃,以保证系统的稳定性。

    整个测试要求得到系统所在服务器的负载达到将近 100% 时,系统的吞吐量,相应时间以及在超负荷下业务请求成功率。

问题现象描述

    在测试过程中,任务池中累积的任务数起伏很大,正常时累积的任务数很小,但是每隔一段时间会累积大量的任务。由于累积的任务数超出任务池流量控制所定义的限额,所以每隔一段时间,大量的待处理任务被清除。因此测试结束后得到的在超负荷下业务请求成功率也不是很理想。

应用服务器的物理部署

    一台AIX服务器(4CPU,4GMemory)来部署本Web应用程序;Web应用程序部署在中间件应用服务器上;部署了一个节点(Node),只配置一个应用服务器实例(Instance),没有做Cluster部署。

分析

    检测WebSphere Application Server上的Web Container,EJB Container , ORB Service,数据库连接池等设置均合理,然后怀疑问题的现象是不是与系统GC有关。当前Java Virtual Machine的配置为: Initial Heap Size:256 , Maximum Heap Size: 3072。

    为了验证任务池中累积的任务数的大幅度变化和系统GC是否存在一定的关系,通过对任务池的累积任务数和系统GC进行采样, 将采样后的数据进行分析,用以得出二者的关系。采样时遵循Nyquist采样定例: 采样频率要大于被采集对象的频率的2倍。 否则,采样点很可能每次位于被采集对象的波形的某个点上,从而不能正确反映被采集对象的变化规律。

采样

    通过观察,发现任务池的任务数目(以下用Q值代替)的变化周期大概是5到6秒,因此根据Nyquist采样定例,采样的时间间隔不能超过2-3秒,所以按照每秒来采样。 测试时间是3分钟,采样180次,系统的当前负载率是99%。采样图如下所示:

图一 任务池Q值的采样图

    由于系流量控制要求的限额是450个任务,也就是任务池中最多能累积450个任务,当任务池中累积的任务数超过450时,多余的任务会被流量控制直接丢弃,从上图可以看出,系统的Q值在很多时刻都大于450,因此多次被丢弃任务,从而导致了任务请求成功率不高。

系统GC的采样

1: 在WebSphere Administrative Console上, 点击进入:Servers, 然后Application servers > server1 > Process Definition > Java Virtual Machine, 在Configuration面板上,选上Verbose garbage collection选项。

图二 WebSphere Application Server的JVM配置示图

2:进入<%WebSphere Application Server的安装目录%>/profiles/<%所在的profiles%>/logs/ <%所在的Server%>, 可以看到native_stderr.log文件,将其清空

3:在高负载的条件下,进行高压测试3分钟

4:将native_stderr.log文件拷贝出来,用GCCollector工具进行分析,其中native_stderr.log文件上记录了系统GC的数据。

5:安装GCCollector工具: 下载完GCCollector.zip后,解压缩,将里面Lib里的3个文件 jfreechart-1.0.0-rc1.jar,jcommon-1.0.0-rc1.jar 和GCCollector.jar拷贝至JRE的lib目录下,然后在命令行控制台上进入JRE的安装目录,而后运行: java -classpath jfreechart-1.0.0-rc1.jar;jcommon-1.0.0-rc1.jar -jar GCCollector.jar。

    接着可以看到GCCollector的用户界面,在它的Parser菜单中选择JRE的版本,而后在File菜单中选择并打开刚才拷出的native_stderr.log文件。

下图是在高负载情况下,系统在当前配置下的GC分析图。

图三 系统的GC分析图

    由图三可以看出,系统没有内存泄漏的现象,每次GC所花的时间为220ms左右,从GCCollector的Spreadsheet可以查到,GC的时间周期为5-6 s,每次具体GC发生的时间,每次GC所花的时间。

6:同样遵循Nyquist采样定例,对GC进行采样,采样后的数据同任务池中Q值的采样数据进行比较和分析,得出两者之间存在着密切的关系。下图为任务池Q值和GC数据采样分析图,由图中可以看出,每次任务池的Q值大幅度增长时,系统刚好发生GC。二者的时间和周期几乎可以完全匹配。 因此可以初步下一个结论,由于系统的GC,导致了系统在某些时刻不能有足够的能力来处理请求,因此任务池的Q值在这些时候会因为任务的大量累积而巨幅涨大,即而超出限额的任务被流控所清除,导致了在超负荷下任务请求成功率不是很理想。

图四 任务池Q值和GC数据采样分析图 

解决方法

    当前的GC发生的频率和每次所花的时间还算正常,但是如果每次GC所花的CPU时间能减少,就能空出系统更多的能力处理任务池里的任务,用以降低任务池中的任务数,使得Q值基本上位于任务池的限额以下,这样可以提高在超负荷下业务请求的总的成功率。

    当前Java Virtual Machine的配置为: Initial Heap Size:256 , Maximum Heap Size: 3072。相对而言, Maximum Heap Size设的有点偏大。对于不同的应用程序,最优化堆大小的设置都有可能不同。堆设置变大,GC的频率会降低,应用程序会运行更长的时间后,才会进行GC,带来的就是每次GC也会花更长的时间。从而GC调用占用系统更长的时间,使系统没有足够的能力处理请求,使得此刻任务池中的任务累积很多,Q值很大,形成很高的峰值,超过流量控制的限额,超过限额数的任务被流量控制给直接丢弃,从而导致总的成功率不高。

    因此,必须降低堆大小,使得GC的频率增大,每次GC所花时间降低,从而降低Q的峰值,使之位于系统的流量控制的范围之内,从而提高业务请求的总的成功率。

    当前的流量控制所允许的峰值是450,因此我们需要通过试验来验证,堆大小降低到什么值时,Q值的峰值将低于450,以保证总的成功率。 同时在峰值低于450的条件下,什么样的堆大小设置可以让系统的性能最佳。 因为如果堆设置过小,会使得对象可分配空间变小,从而会频繁的使用垃圾收集机制来释放内存空间,而每次垃圾收集,都会耗用一定的系统资源。所以,我们要通过试验和监控数据,设法使的我们所设置的堆大小能够使得我们的程序运行最优化。

    通过多次试验,我们得出结论:当Java Virtual Machine的配置为: Initial Heap Size:512 , Maximum Heap Size: 1024时,该系统性能最佳。

    从WebSphere Administrative Console上,依次点击Servers->Application Servers,然后选择需要的server,接着点击Process Definition->Java Virtual Machine,而后在那里设置Initial Heap Size:512和Maximum Heap Size: 1024。这时的配置对于该应用系统相对较为合理。这时再次分析3分钟内的GC的数据,从下图可以看出,GC的周期缩短了,每1-2秒就会发生一次GC,但是每次GC所花费的CPU时间降低了,平均130ms左右。

图五 改进JVM配置后的GC分析图

    相应地,在JVM配置改进后,对任务池的Q值再进行一次采样,并且和改进前的采样值进行比价,采样图如下图六所示,改进后任务池的Q值分布在50-450之间,数值的起伏相对改进前要均衡些。不再出现忽然间Q值大小涨到500以上的情况,基本在流控的限制范围之类,进而提高了在超负荷下业务请求的总的成功率。

图六 改进JVM配置后和改进前的Q值采样比较图

本文地址:H5W3 » 优化 Java 垃圾收集器改进系统性能

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址