基于JVM服务器的性能优化方法转让专利

申请号 : CN201110462156.8

文献号 : CN103186412B

文献日 :

基本信息:

PDF:

法律信息:

相似专利:

发明人 : 高赫

申请人 : 北京新媒传信科技有限公司

摘要 :

本发明公开了一种基于JVM服务器的性能优化方法,涉及Java虚拟机技术领域,包括:S1:根据服务器的当前配置对服务器进行压力测试,得到压力测试结果;S2:判断所述压力测试结果是否满足预先设定的阈值,若不满足,则执行步骤S3;若满足,则使用当前配置作为优化配置的结果;S3:调整服务器的当前配置参数,调整后执行步骤S1。本发明使得线上服务器压力减小,以及部分服务器中资源得到充分利用。

权利要求 :

1.一种基于JVM服务器的性能优化方法,其特征在于,包括:

S1:根据服务器的当前配置对服务器进行压力测试,得到压力测试结果;所述压力测试结果用于与线上配置进行比对,来检查是否通过优化而对项目本身的GC回收情况、网络吞吐情况、单位时间点击率、以及系统实时压力情况有所提升,所述单位时间为秒;

S2:判断所述压力测试结果是否满足预先设定的阈值,其中,阈值根据实际线上服务器的运行情况及用户数量不同而不同,阈值的设定根据服务器能承受性能压力的情况下,资源利用率达到最高;若不满足,则执行步骤S3;若满足,则使用当前配置作为优化配置的结果;

S3:调整服务器的当前配置参数,调整后执行步骤S1;所述压力测试为在一段时间内实时监测配置参数的参数值,利用Tomcat对JVM进行实时监控,所述配置参数包括:垃圾回收参数。

2.如权利要求1所述的基于JVM服务器的性能优化方法,其特征在于,所述步骤S3中调整服务器的当前配置参数包括:设置内存大小、垃圾回收线程数及线程堆栈大小。

3.如权利要求2所述的基于JVM服务器的性能优化方法,其特征在于,所述设置的垃圾回收线程数为CPU核的个数。

4.如权利要求1所述的基于JVM服务器的性能优化方法,其特征在于,所述步骤S3中包括:设置JVM中的年轻代对象的Survivor区与Eden区比例。

5.如权利要求1所述的基于JVM服务器的性能优化方法,其特征在于,所述步骤S3中调整服务器的当前配置参数包括:设置参数n,n为JVM中转移到年老代的对象在年轻代中经过垃圾回收的次数。

6.如权利要求1所述的基于JVM服务器的性能优化方法,其特征在于,所述步骤S3中调整服务器的当前配置参数包括:设置JVM中年老代区的垃圾回收的次数。

7.如权利要求1所述的基于JVM服务器的性能优化方法,其特征在于,所述步骤S3中调整服务器的当前配置参数包括:设置JVM中持久代区的存储空间大小。

8.如权利要求1~7中任一项所述的基于JVM服务器的性能优化方法,其特征在于,在压力测试的过程中还包括并发执行内存碎片整理的过程。

9.如权利要求8所述的基于JVM服务器的性能优化方法,其特征在于,所述步骤S3中调整服务器的当前配置参数还包括:设置在进行m次年老代区的垃圾回收后进行所述内存碎片整理。

说明书 :

基于JVM服务器的性能优化方法

技术领域

[0001] 本发明涉及Java虚拟机(Java Virtual Machine,JVM)技术领域,特别涉及一种基于JVM服务器的性能优化方法。

背景技术

[0002] Java虚拟机中的对象共划分为三个代:年轻代(Young Generation)、年老代(Old Generation)和持久代(Permanent Generation)。其中持久代主要存放的是Java类的类信息,与垃圾回收(Garbage Collection,GC)要收集的Java对象关系不大。年轻代和年老代的划分是对垃圾回收影响比较大的。
[0003] 年轻代:
[0004] 所有新生成的对象首先都是放在年轻代的。年轻代的目标就是尽可能快速的收集掉那些生命周期短的对象。年轻代分三个区。一个Eden区,两个Survivor区(一般而言)。大部分对象在Eden区中生成。当Eden区满时,还存活的对象将被复制到Survivor区(两个中的一个),当这个Survivor区满时,此区的存活对象将被复制到另外一个Survivor区,当这个Survivor区也满了的时候,从第一个Survivor区复制过来的并且此时还存活的对象,将被复制到“年老区(Tenured)”。需要注意,Survivor的两个区是对称的,没先后关系,所以同一个区中可能同时存在从Eden复制过来的对象,和从前一个Survivor复制过来的对象,而复制到年老区的只有从第一个Survivor区过来的对象。而且,Survivor区总有一个是空的(因为Survior区分两个区,在复制的时候从s0到s1复制完以后s0区里面的对象将被释放,等待下一次YGC时再进行交换,从s1到s0所以每次总有一个s区是空的)。
同时,根据程序需要,Survivor区是可以配置为多个的(多于两个),这样可以增加对象在年轻代中的存在时间,减少被放到年老代的可能。年轻代的回收称为YGC。
[0005] 年老代:
[0006] 在年轻代中经历了N次垃圾回收后仍然存活的对象,就会被放到年老代中。因此,可以认为年老代中存放的都是一些生命周期较长的对象。年老代的回收称为Full GC。
[0007] 持久代:
[0008] 用于存放静态文件,如今Java类、方法等。持久代对垃圾回收没有显著影响,但是有些应用可能动态生成或者调用一些class,例如:Hibernate等,在这种时候需要设置一个比较大的持久代空间来存放这些运行过程中新增的类。
[0009] 针对线上服务器的系统以及所有应用服务,在部署后没有进行过系统优化,在随着应用服务的增减,用户数量的增减,会造成线上部分服务器压力过大,以及部分服务器利用不充分,尤其是在垃圾回收方面,和内存利用效率息息相关,因此需要优化服务器的配置。

发明内容

[0010] (一)要解决的技术问题
[0011] 本发明要解决的技术问题是:线上部分服务器压力过大,以及部分服务器利用不充分的问题。
[0012] (二)技术方案
[0013] 为解决上述技术问题,本发明提供了一种基于JVM服务器的性能优化方法,包括:
[0014] S1:根据服务器的当前配置对服务器进行压力测试,得到压力测试结果;
[0015] S2:判断所述压力测试结果是否满足预先设定的阈值,若不满足,则执行步骤S3;若满足,则使用当前配置作为优化配置的结果;
[0016] S3:调整服务器的当前配置参数,调整后执行步骤S1。
[0017] 其中,所述压力测试为在一段时间内实时监测配置参数的参数值,所述配置参数包括:垃圾回收参数。
[0018] 其中,所述步骤S3中包括:设置内存大小、垃圾回收线程数及线程堆栈大小。
[0019] 其中,所述设置的垃圾回收线程数为CPU核的个数。
[0020] 其中,所述步骤S3中包括:设置JVM中的年轻代对象的Survivor区与Eden区比例。
[0021] 其中,所述步骤S3中包括:设置参数n,n为JVM中转移到年老代的对象在年轻代中经过垃圾回收的次数。
[0022] 其中,所述步骤S3中包括:设置JVM中年老代区的垃圾回收的次数。
[0023] 其中,所述步骤S3中包括:设置JVM中持久代区的存储空间大小。
[0024] 其中,在压力测试的过程中还包括并发执行内存碎片整理的过程。
[0025] 其中,所述步骤S3中包括:设置在进行m次年老代区的垃圾回收后进行所述内存碎片整理。
[0026] (三)有益效果
[0027] 本发明的基于JVM服务器的性能优化方法通过对服务器的性能反复测试优化,使得线上服务器压力减小,以及部分服务器中资源得到充分利用。

附图说明

[0028] 图1是本发明实施例的一种基于JVM服务器的性能优化方法流程图;
[0029] 图2是对JVM服务器的性能优化前的压力测试结果图;
[0030] 图3是对JVM服务器的性能优化前每秒点击次数随时间变化曲线图;
[0031] 图4是对JVM服务器的性能优化后的压力测试结果图;
[0032] 图5是对JVM服务器的性能优化后内存为4G时每秒点击次数随时间变化曲线图;
[0033] 图6是对JVM服务器的性能优化后内存为5G时每秒点击次数随时间变化曲线图;
[0034] 图7是对JVM服务器的性能优化后内存为8G时每秒点击次数随时间变化曲线图。

具体实施方式

[0035] 下面结合附图和实施例,对本发明的具体实施方式作进一步详细描述。以下实施例用于说明本发明,但不用来限制本发明的范围。
[0036] 如图1所示,本发明的基于JVM服务器的性能优化方法包括:
[0037] 步骤S101,根据服务器的当前配置对服务器进行压力测试,得到压力测试结果。
[0038] 步骤S102,判断压力测试结果是否满足预先设定的阈值,若不满足,则执行步骤S103;若满足,执行步骤S104。其中,阈值根据实际线上服务器的运行情况及用户数量不同而不同。阈值的设定根据服务器能承受性能压力的情况下,资源利用率达到最高,不浪费。
[0039] 步骤S103,调整服务器的当前配置参数,调整后执行步骤S101。
[0040] 步骤S104,使用当前配置作为优化配置的结果。
[0041] 本发明主要思想是根据压力测试结果优化JVM GC回收的相关参数,然后通过优化后的压力测试结果与线上配置进行比对,来检查是否通过优化而对项目本身的GC回收情况、网络吞吐情况、单位时间(秒)点击率、以及系统实时压力情况(CPU、内存、磁盘)有所提升,本发明主要将单位时间(秒)点击率作为压力测试主要指标,以下通过测试项目来具体说明本发明的方法,其中,
[0042] 机器硬件信息:CPU:Intel(R)Xeon(R)CPU E5620@2.40GHz 4核,8通道,内存:24G。
[0043] 软件信息:系统:CentOS 5.664位
[0044] 内核版本:2.6.18-238.12.1.el5
[0045] Tomcat:Apache Tomcat/6.0.29
[0046] Jdk:java version“1.6.0_16”64位
[0047] 压力测试软件:
[0048] Loadrunner
[0049] 上述步骤中主要测试以下参数,参数值是线上JVM初始化配置:
[0050] JAVA_OPTS=″$JAVA_OPTS-server-Xms6144M-Xmx6144M-Xmn4096M-XX:PermSize=600M-XX:MaxPermSize=300M-XX:SurvivorRatio=65536-XX:MaxTenuringThreshold=0-Xnoclassgc-XX:+DisableExplicitGC-XX:+UseParNewGC-XX:+UseConcMarkSweepGC-XX:+UseCMSCompactAtFullCollection-XX:CMSFullGCsBeforeCompaction= 1-XX:+CMSClassUnloadingEnabled-XX:-CMSParallelRemarkEnabled-XX:CMSInitiatingOccupancyFraction=40-XX:SoftRefLRUPolicyMSPerMB=0-XX:+PrintGCDetails-XX:+PrintGCTimeStamps:/backup/common-logs/gc_8080.log″
[0051] 上述线上配置分析如下:
[0052] 1)-XX:SurvivorRatio:此参数设置为设置年轻代中Eden区与Survivor区的大小比值。通常为6或者4,两个Survivor区与一个Eden区的通常配置为比值为2∶6或者2∶4,也就是说一个Survivor区占整个年轻代的1/8或者1/6,而线上配置为-XX:SurvivorRatio=65536,是比较流行的放弃Survivor区从而增加Eden区内存大小的方式,延长了YGC回收时间。
[0053] 2)-XX:PermSize=600M但是-XX:MaxPermSize=300M才设置300,这里的配置存在问题。
[0054] 3)-XX:MaxTenuringThreshold=0指定一个object在经历了n次YGC后转移到年老代区,设置是0,也就是说每次YGC回收都会把一些长周期的对象丢入年老代区,增加了年老代区累计也就是增加了full GC回收次数。
[0055] 4)-Xnoclassgc关闭针对class的GC功能;
[0056] 5)-XX:+DisableExplicitGC禁止java程序中的Full GC,如System.gc()的调用。设置该参数是禁止由于程序员调用System.gc()引起的手动GC,以防止在代码里误用,对性能造成冲击。
[0057] 6)-XX:+UseParNewGC设置年轻代为并行收集。
[0058] 7)-XX:+UseConcMarkSweepGC设置年老带为多线程并行Full GC。
[0059] 8)-XX:+UseCMSCompactAtFullCollection在使用concurrent gc的情况下,防止memory fragmention,对live object进行整理,使memory碎片减少。
[0060] 9)-XX:CMSFullGCsBeforeCompaction表示执行N次Full GC后执行内存压缩。
[0061] 10)-XX:+CMSParallelRemarkEnabled在使用UseParNewGC的情况下,尽量减少mark的时间。
[0062] 11)-XX:CMSInitiatingOccupancyFraction设置年老代空间达到预定的百分比时进行Full GC。
[0063] 上述压力测试为在一段时间内实时监测配置参数的参数值,利用Tomcat对JVM进行实时监控,如图2所示。
[0064] 线上Survivor区设置为0,没有被占用所以这里很明显,回收过程没有Survivor区交替。
[0065] Eden区设置为4G空间,YGC一共执行了242次共消耗15.466s,平均每次YGC回收时间为0.0640s。
[0066] 年老代区分配2G空间,但是-XX:CMSInitiatingOccupancyFraction设置为40所以年老代区每次都没有被充分利用的情况下就进行了Full GC。
[0067] 年老代区一共执行了26次Full GC,耗时22.060s,平均每次Full GC时间为0.848s。
[0068] Perm区线上设置300M,从整个压力测试过程来看测试项目所利用的持久代区只有64M,可以释放持久代perm区。
[0069] 采用压力测试工具Loadrunner监测每秒事务处理量(TransactionPerSecond,TPS),如图3所示。
[0070] 从图3中可看出服务器很不稳定,秒级并发均值在450左右。随着用户的增加,响应速度逐渐变慢,当达到1060的时候,开始报错。
[0071] 监测系统情况,系统Load值维持在3-4之间相对稳定,随着用户数的增加CPU处理存在等待。(此处的load指的是linux系统cpu负载值loadavg为3-4,前面有提到系统的配置CPU为4核、8通道,这个load值如果超过通道数“8”,则视为系统负载处于临界警告,可能会出现机器负载过高而导致死机)。
[0072] 监测压力过程中应用现象,在用户达到650的时候,响应速度迅速变慢。点击部分页面等待时间较长,当用户数超过1000后会出现报错,点击每个页面,等待时间都在8-10秒。
[0073] 上述配置导致服务器压力过大,需要优化配置如下:
[0074] JAVA_OPTS = ″ $JAVA_OPTS-Dcom.sun.management.jmxremote-Dcom.sun.management.jmxremote.Port = 9004-Dcom.sun.management.jmxremote.authenticate=false-Dcom.sun.management.jm xremote.ssl= false-Djava.rmi.server.hostname= 10.10.110.113-server-Xms4096M-Xmx4096M-Xmn2048M-Xss256k-XX:PermSize =150M-XX:MaxPermSize=150M-XX:ParallelGCThreads=8-XX:SurvivorRatio=18-Xnoclassgc-XX:MaxTenuringThreshold= 10-XX:+DisableExplicitGC-XX:+UseParNewGC-XX:
+UseConcMarkSweepGC-XX:+UseCMSCompactAtFullCollection-XX:CMSFullGCsBeforeCompaction= 5-XX:+CMSClassUnloadingEnabled-XX:+CMSParallelRemarkEnabled-XX:CMSInitiatingOccupancyFraction=80-XX:SoftRefLRUPolicyMSPerMB=0-XX:+PrintGCDetails-XX:+PrintGCTimeStamps-Xloggc:/backup/common-logs/gc_8080.log″[0075] 上述优化配置分析。
[0076] i.-XX:ParallelGCThreads:设置GC回收线程数,根据服务器CPU数来确认。(几核CPU就设置为几)。充分利用cpu资源。
[0077] ii.-XX:SurvivorRatio=18设置Survivor区与Eden区比例,根据对线网配置测试,这里为18则Eden区占18/20,Survivor区占2/20。
[0078] iii.MaxTenuringThreshold指定一个对象在经历了n次YGC后转移到年老代区,明显在测试中Survivor区有足够的空间承载YGC交换,同时降低了年老代区的增长率。
[0079] iv.-XX:+UseCMSCompactAtFullCollection指在使用并发GC的情况下,为防止内存碎片过多,对存活对象进行内存碎片整理一般和-XX:CMSFullGCsBeforeCompaction=5一起使用。而后者指在进行几次Full GC后进行碎片整理。
[0080] v.-XX:CMSInitiatingOccupancyFraction=80将Full GC的阀值调大,从而大大的减少了Full GC的次数。原配置为40。
[0081] vi.-Xss256k设置每个线程的堆栈大小。在相同物理内存下,减小这个值能生成更多的线程。
[0082] vii.-XX:PermSize=150M调整持久代的大小,充分利用内存空间。原配置为300M,内存不能充分利用。
[0083] 优化后实时监测的情况如图4所示:
[0084] 1)开放了Survivor区,减少年老代区增长频率。
[0085] 2)YGC回收次数增多为582次,但是总耗时减少为18.889s,所以每次的YGC回收的平均时间为0.0324s。
[0086] 3)开放Survivor区,年老代区在整个压力过程(1小时内)没有发生Fullgc。
[0087] 4)Perm区调整为200M利用率也有所增长。
[0088] 利用Loadrunner监测TPS值,如图5所示,服务器整个用户(Vuser)增长过程相对线上配置稳定,如阶梯状的曲线所示,秒级点击次数平均在520次,比线上增长了近100。
[0089] 系统情况,系统load也在2-3之间徘徊,当用户数超过1000后CPU处理一样存在等待。
[0090] 压力过程中应用现象,访问相对平稳了很多。当用户数达到1000后,通过页面访问等待时间在3-5秒左右,比之前的线上配置有明显的提升。
[0091] 上述优化测试通过使用jvm监控工具和loadrunner得出:
[0092] 1)在增加内存测试时,对4G,5G,8G,的情况分别测试,在增加内存大小的前提下,JVM GC回收并没有增长,5G和8G内存分配的情况,如图6和7所示,并发数并没有4G的情况下高,从而确定,64位系统下linux2.6内核,JVM最优分配为4G,增大内存后会浪费。
[0093] 2)JVM优化就是减少YGC的时间。经过优化后,YGC时间由每次0.063秒减少到每次0.032秒。
[0094] 3)JVM优化还有就是减少Full GC的次数,增大Full GC的周期。经过优化后,Full GC在一个小时相同时间内,由26次,每次0.848秒,减少到没有发生Full GC。
[0095] 4)服务器整个用户增长过程相对线上配置稳定,秒级点击次数平均在520次,比线上增长了70(并发量由450提高到520)。
[0096] 5)不同的应用需要通过JVM的观察进行优化,基本遵循:更大的年轻代必然导致更小的年老代,大的年轻代会延长普通GC的周期,但会增加每次GC的时间;小的年老代会导致更频繁的Full GC;更小的年轻代必然导致更大年老代,小的年轻代会导致普通GC很频繁,但每次的GC时间会更短;大的年老代会减少Full GC的频率;具体如何选择应该依赖应用程序对象生命周期的分布情况:如果应用存在大量的临时对象,应该选择更大的年轻代;如果存在相对较多的持久对象,年老代应该适当增大。但很多应用都没有这样明显的特性,在抉择时应该根据以下两点:(A)本着Full GC尽量少的原则,让年老代尽量缓存常用对象,JVM的默认比例1∶2也是这个道理(B)通过观察应用一段时间,看其他在峰值时年老代会占多少内存,在不影响FullGC的前提下,根据实际情况加大年轻代,比如可以把比例控制在1∶1。但应该给年老代至少预留增长空间。
[0097] 以上实施方式仅用于说明本发明,而并非对本发明的限制,有关技术领域的普通技术人员,在不脱离本发明的精神和范围的情况下,还可以做出各种变化和变型,因此所有等同的技术方案也属于本发明的范畴,本发明的专利保护范围应由权利要求限定。