Java优化策略在铁路互联网售票系统中的应用研究

2016-02-16 05:15杨立鹏刘卓华
铁路计算机应用 2016年8期
关键词:收集器线程内存

杨立鹏,王 拓,刘卓华,李 雯

(1.北京经纬信息技术公司,北京 100081;2.中国铁道科学研究院,北京 100081;3.中国铁道科学研究院 电子计算技术研究所,北京 100081;4.中铁程科技有限责任公司,北京 100081)

Java优化策略在铁路互联网售票系统中的应用研究

杨立鹏1,2,王 拓2,3,刘卓华2,3,李 雯4

(1.北京经纬信息技术公司,北京 100081;2.中国铁道科学研究院,北京 100081;3.中国铁道科学研究院 电子计算技术研究所,北京 100081;4.中铁程科技有限责任公司,北京 100081)

为了使铁路互联网售票系统稳定性和高效性能够得到更好的保证,结合分布式内存数据库的系统特性和铁路互联网售票系统的业务特性,对各种Java虚拟机(JVM)内存管理策略和垃圾回收机制进行了分析和研究,以余票查询业务系统模块为例对JVM参数调优过程进行了简要测试和分析,测试结果表明,优化后的系统具有更好的稳定性和高效性。

铁路互联网售票系统;分布式内存数据库;Java虚拟机; Java调优策略

在铁路互联网售票系统中,分布式内存数据库承担着一些并发请求多、实时性要求高的业务,比如余票查询、订单查询、常用联系人查询等。它的构成包括以下2个重要角色:(1)2个Locator作为控制节点,主要负责作业调度、负载均衡。一般部署在2台服务器上,双活机制,互为备份,分配少量资源即可。(2)多个DataStore作为服务节点,主要负责数据存储、逻辑运算。一般部署在多台服务器上,每台服务器上的DataStore大小和数量保持一致。物理上数据分散存储在不同的DataStore上;逻辑上,所有数据仍是统一的整体。

本质上来说,组成分布式内存数据库的每一个Locator和DataStore都是一个Java虚拟机(JVM,Java Virtual Machine)。JVM专门为Java应用的运行提供环境,用于分配执行任务和执行内存操作。

JVM中频繁的全量垃圾回收(FGC,Full Garbage Collection)导致的短暂停顿将会造成糟糕的用户体验。更严重的情况下,如果发生JVM崩溃,导致售票系统某一模块无法正常提供服务,甚至会引发停售的事故。因此,JVM的稳定性和高效性必须得到最大的保证,JVM的调优显得尤为重要。

本文将对JVM的各种调优参数进行研究,结合分布式内存数据库的系统特性和铁路互联网售票系统的业务特性,对各种JVM内存管理策略、垃圾回收机制进行分析和研究,最终找出适合特定业务模块的JVM参数。

1 JVM调优策略

自Java诞生以来,市场上涌现出多款优秀的具有特色的JVM产品,比如HotSpot VM,JRockit,J9等。在生产环境中,我们使用了相对比较稳定的HotSpot VM作为分布式内存数据库所使用的JVM。

JVM将它所管理的内存空间划分为若干个不同的区域,这些区域各司其职,维护着对象或者线程的生命周期。如果分配给某个对象的内存地址空间不再被任何对象引用所指向时,那么这块内存地址空间就成了“垃圾”,占用着宝贵的内存。此时JVM会启动垃圾回收器,释放垃圾内存空间,并进行内存整理。

1.1 JVM内存分配策略

Java虚拟机的基本结构如图1所示。

图1 Java虚拟机的基本结构示意图

从线程角度来看,Java运行时数据区域分为全部线程共享数据区域(图1中绿色部分)和各个线程私有数据区域(图1中蓝色部分)。

(1)程序计数器:Java程序运行时,通过改变这个计数器的值来选取下一条需要执行的字节码指令。包括程序中的分支、循环、异常处理等基础功能。

(2)虚拟机栈:执行Java方法时,主要用于存储栈帧(Stack Frame),栈帧内保存有局部变量表(基本数据类型和对象引用等)、动态链接、方法出口等信息。

(3)本地方法栈:与虚拟机栈的功能类似,但本地方法栈是虚拟机执行本地方法时所使用的内存区域。

(4)方法区:可将其称为Non-Heap,即非堆内存区域。虚拟机加载成功的类信息、常量、静态变量等数据存储在这里。

(5)堆:Java堆(Heap)是Java虚拟机管理的内存区域中最大的一块,用于存放所有对象实例和数组。

对JVM的调优主要集中在Java堆上,它的构成主要包括以下3部分[1]:

(1)年轻代区域:包括Eden空间、FromSurvivor空间、ToSurvivor空间。所有新生成的对象首先都是放在年轻代。年轻代的目标就是尽可能快速地对生命周期短的对象进行垃圾回收。

(2)年老代区域:主要是指Tenured空间。在年轻代中经历了N次垃圾回收后仍然存活的对象,就会被放到年老代中。因此,可以认为年老代中存放的都是一些生命周期较长的对象。

(3)持久代区域:主要是指Perm空间。用于存放静态文件,如Java类、方法等。持久代对垃圾回收没有显著影响。

1.2 垃圾收集算法

(1)Mark-Sweep标记清除算法:该算法是其他算法的理论基础。可分为“标记”和“清除”两个阶段,首先从根节点开始,标记上所有可达对象,那么剩余的就是未被引用的垃圾对象,这些是要清除的对象。该算法最大的缺陷是会产生大量的内存空间碎片,导致以后在程序运行过程中需要分配较大对象时,无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作[2~3]。

(2)Copying复制算法:该算法的核心思想是将内存控件划分为大小相等的两块,每次只使用其中一块。在进行垃圾回收时,将存活对象复制到另外一块中,再把已使用过的内存空间全部清空。虽然这种算法效率很高,也避免了内存空间碎片,但将系统内存折半使用的代价太大了,所以不能单纯使用这种算法[2~3]。

(3)Mark-Compact标记压缩算法:该算法垃圾回收的目标主要是年老代的未被引用对象。它是对Mark-Sweep算法的优化,标记可达对象之后,并不是直接清理未被标记对象,而是将所有存活对象压缩移动到内存的另一端,之后清理边界之外的所有内存空间。最终效果与Mark-Sweep相同,但进行了一次内存碎片整理[2~3]。

(4)Generation Collection分代收集算法:该算法根据对象生命周期的不同将内存空间划分为几块不同的区域,使用上述不同的算法。例如,年轻代适合使用复制算法,年老代适合使用标记压缩算法[2~3]。

1.3 垃圾收集器

垃圾收集器是垃圾收集算法的具体实现[4~5]。

(1)Serial串行收集器:这是最早的垃圾收集器,是单线程的,独占式的,运行时需要暂停所有线程,直到它运行结束。

(2)ParNew并行收集器:该垃圾收集器适用于年轻代,将串行收集器多线程化。在收集过程中,引用程序会全部暂停,但是在处理能力较强的CPU上,由于使用了多线程,它的停顿时间较短。

(3)CMS(Concurrent-Mark-Sweep)收集器:该收集器是基于Mark-Sweep标记清除算法的使用多线程并发回收的垃圾收集器。CMS收集器的内存回收过程是与用户线程一起并发执行的,包括4个阶段:初始标记(CMS initial mark)、并发标记(CMS concurrent mark)、重新标记(CMS remark)、并发清除(CMS concurrent sweep)。可以通过调整-XX:CM SInitiatingOccupancyFraction参数的值来改变触发收集动作时年老代空间使用的百分比,这样就使垃圾回收次数变得可控,应用性能也在一定程度上得到了保证。它的优点是并发收集,停顿较低。但是,在并发收集过程中,会占用一部分CPU资源,导致应用程序变慢,系统吞吐量下降。

(4)G1(Gabbage-First)收集器:该收集器出现在JDK 1.7中,主要就是为了替代1.6时代的CMS。G1收集器也是分代垃圾收集器的一种,但它不要求年轻代和年老代都连续。G1和CMS都可以降低应用停顿时间,但G1建立了可预测时间模型,可以指定最大停顿时间,如果停顿超过这个时间,则G1会尝试调整年轻代、年老代的比例,调整堆大小等手段进行优化。G1可以避免在整个Java堆中进行全区域的垃圾收集,它在后台维护一个垃圾收集价值优先列表,保证了G1收集器在有限的时间内可以获取尽可能高的收集效率。

2 优化过程分析

2.1 JVM监控工具

2.1.1 JDK性能监控工具

在JDK的开发包中,有一些辅助工具可以帮助我们查看JVM进程的运行状态、Java线程的详细信息、垃圾回收(GC,Garbage Collection)情况的详细信息等。

(1)jstat命令。用于查看虚拟机实时运行信息。常用参数如下:

-gc:显示与GC相关的Heap信息;

-gccapacity:显示各个代的容量和使用情况;

-gccause:显示最近一次或正在进行的垃圾收集的原因;

-gcutil:显示垃圾收集的详细信息。

(2)jmap命令。这个命令有很多功能,可以导出Heap到文件,即生成Heap内存区域的Dump文件,可以查看Heap内对象实例的统计信息,还可以查看类加载器ClassLoader的详细信息等。例如,在Linux环境下,生成PID为12345的JVM进程对象统计信息,将结果输出到文件pid_12345_dump.txt中,可以使用如下命令:

jmap –histo 12345 > pid_12345_dump.txt

(3)jstack命令。用于查看线程堆栈,导出JVM的线程堆栈,经常用来检查程序的死锁问题。在实际运行中,往往一次dump的信息无法全面的定位问题,一般需要进行3次线程dump,结合起来进行分析。

2.1.2 可视化性能监控工具VisulVM

VisulVM是一款适用于Java虚拟机且功能十分强大的故障诊断和性能分析可视化工具。VisulVM具有以下优点:(1)它支持扩展插件,用户可以根据自己Java应用的实际情况进行个性化定制;(2)它同时支持Windows环境下本地启动的JVM进程,也支持远程访问Linux环境下的JVM进程;(3)可进行Thread Dump、内存SnapShot分析、垃圾收集情况分析;(4)界面直观清晰,通常会有多个视图分别实时地显示CPU使用情况、内存使用情况、线程状态以及其他一些有用信息。

2.2 优化过程

不同业务或不同环境都会对Java应用的运行产生不同影响。以余票查询业务为例,该业务具有如下几个主要特点:

(1)全部数据量约有4 000万条记录,每次查询得到的结果集少则几条,多则200~300条;

(2)业务逻辑十分复杂,涉及多个子模块,多个表的数据,余票查询结果中包含车次、席位、预售期等复杂信息;

(3)业务代码运行频繁,售票高峰日期时,单日查询请求数量可达上亿次。

由此可以归纳出:业务运行期间会有大量的对象生成、销毁;对CPU、内存、网络等资源比较敏感;生产环境的应用必须尽可能减少FGC导致的Stop The World的影响,不能影响用户体验,不能影响铁路售票。

下面将结合服务器硬件、软件环境和业务应用情况进行调优分析和研究,对各个参数的选取作出说明。

分布式内存数据库服务器硬件环境如表1所示。

表1 分布式内存数据库服务器硬件环境

JVM启动参数如表2所示。

表2 JVM启动参数列表

在铁路互联网售票系统分布式内存数据库中,根据不同的业务场景,对JVM的启动参数有定制化的配置。通过对业务场景和系统运行环境的深入分析和充分测试,所选用的参数适用于余票查询业务和分布式内存数据库。具体调优思路如下:

(1)-Xmx和-Xms参数:这两个值设置为相同,以避免每次GC之后JVM重新分配内存。目的是为了让Heap区域静态分配,否则Java的堆是动态变化的。经过对余票查询原始数据量以及业务运行过程中产生对象的数量进行精密测算,这里Heap区域的大小固定为102 400 MB。

(2)-Xmn参数:年轻代大小对系统性能影响比较大,这里我们取整个Heap区域的3/8左右,符合Hotspot VM官方推荐的配置。

(3)-Xss参数:由于余票查询业务逻辑十分复杂,涉及数据较多,不同车站间的车次数量不同,最多的可达300多趟列车,再考虑到服务器的CPU情况,为保证这种余票查询请求能够正常进行,这里将每个线程栈设置为1 024 KB。在相同物理内存下,减小这个值能生成更多的线程。

(4)-XX:PermSize参数:余票查询业务并没有相当大量的class需要动态载入或卸载,所以这里设置为128 MB即可。

(5)-XX:+UseParNewGC和-XX:+UseConc-MarkSweepGC参数:使用较为通用的配置。

(6)-XX:CMSInitiatingOccupancyFraction参数:生产环境实际应用中,年老代增长速度并不是很快,而且不允许系统频繁进行CMS垃圾收集,所以这里将参数值设置较高,为80。

(7)-XX:ParallelGCThreads=4参数:允许有4个线程同时进行垃圾回收。生产环境中,一台服务器有32个Core,4个JVM,每个JVM分到8个Core,一般可将这个参数设置为8/2=4,如果设置为8个,可能会产生业务线程和GC线程之间的资源竞争。

2.3 优化结果

为了能够清晰直观地展现优化效果,采用JDK性能监控工具jstat等命令,将JVM关键指标记录到表格,进行分析。采用对分布式内存数据库进行压力测试的方法作为验证手段,选取具有代表性的垃圾回收操作用时作为观察指标。

以此为基础,分别对优化前、优化后的分布式内存数据库进行压力测试,每次持续时长1 h,各进行15次,使用jstat命令记录垃圾回收的频率(即JVM间隔多少秒进行垃圾回收),取1 h之内的平均值,结果如图2所示。

图2 多次压力测试时垃圾回收用时示意图

在进行优化之前,进行了15次相同场景的压力测试,JVM进行垃圾回收的平均时间间隔为1.77 s。而做过优化之后,这一时间间隔提升至7.84 s。系统进行垃圾回收的频率得到大幅降低,系统能够更加稳定、更加高效地提供服务。

3 结束语

分布式内存数据库的主要存储介质是内存,业务数据和代码存储在各个JVM上,同时,为适应铁路互联网售票系统的业务场景和高并发访问需求,我们必须将JVM的调优工作做到精益求精。本文结合生产环境实践经验以及其他类似系统的参考信息,对承载余票查询业务的分布式内存数据库JVM参数调优过程进行了简要测试和分析。以此结论为依据的配置,在生产环境取得了稳定且良好的应用效果。

类似的调优思想在其他系统中也得到了良好应用。例如,在用户行为分析系统中,用户在使用互联网售票系统购票过程中,键盘录入等事件均会产生旅客的行为操作数据,对此类数据的分析要求JVM组成的系统能够承载较大的吞吐量,对实时性要求较低,可以在一定程度上容忍垃圾回收带来的负面影响。

另外,还有一些调优工作值得进行尝试,例如,对JDK 1.7中G1垃圾回收器进行充分测试,以论证其在生产系统中使用的可行性。

[1]杨文超.Java虚拟机内存管理与优化策略[J].电子测试,2013(19):43-44.

[2]嵇智源,潘 巍.面向大数据的内存数据管理研究现状与展望[J].计算机工程与设计,2014(10):3499-3506.

[3]李永远.JAVA虚拟机相关技术研究与实践[J].信息通信,2015(5):120-120.

[4]吴志军,何加铭,曾兴斌,等.基于嵌入式Java虚拟机的垃圾收集优化算法[J].计算机工程,2012,38(7):46-48.

[5]曾天慧,於时才,董荣辉,等.Java垃圾收集机制及性能调节[J].计算机工程与设计,2006,27(17):3242-3244.

责任编辑 付 思

Java tuning strategy in Railway Internet Ticketing and Reservation System

YANG Lipeng1,2,WANG Tuo2,3,LIU Zhuohua2,3,LI Wen4
( 1.Beijing Jingwei Information Technology Co.,Beijing 100081,China;2.China Academy of Railway Sciences,Beijing 100081,China;3.Institute of Computing Technologies,China Academy of Railway Sciences,Beijing 100081,China;4.China Rails Travel Technology,Co.Ltd., Beijing 100081,China)

In order to make the Railway Internet Ticketing and Reservation System be better guaranteed,combining with the system characteristics of the distributed memory database and the operational characteristics of the Railway Internet Ticketing and Reservation System,this article analyzed and studied on the memory management strategy and garbage collection mechanism of various JVM ( Java virtual machine).Taken remaining ticket query service system model as an example,the JVM parameter tuning process was briefy tested and analyzed.The test result showed that the optimized system had better stability and high effciency.

Railway Internet Ticketing and Reservation System;distributed memory data base;Java virtual machine;Java tuning strategy

U293.22:TP39

A

1005-8451(2016)08-0021-05

2015-12-17

杨立鹏,在读博士研究生;王 拓,助理研究员。

猜你喜欢
收集器线程内存
一种病房用24小时尿蛋白培养收集器的说明
基于C#线程实验探究
一种用于内镜干燥的酒精收集器的设计与应用
基于国产化环境的线程池模型研究与实现
线程池调度对服务器性能影响的研究*
笔记本内存已经在涨价了,但幅度不大,升级扩容无须等待
“春夏秋冬”的内存
雷电收集器
内存搭配DDR4、DDR3L还是DDR3?
土壤重金属收集器