JVM调优实战
JVM调优实战以web项目为例。调优主要从两个方面入手,一是tomcat容器的优化,二是JVM虚拟机的调优。调优的原则是控制变量法,先优化tomcat,再优化JVM虚拟机,二者不要同时进行,否则,可能越调性能越差。 下面我们首先来进行tomcat容器的优化。
tomcat优化
1.禁用AJP服务
#优化一:禁用AJP服务,一般是使用Nginx+tomcat的架构,所以用不着AJP协议,所以把AJP连接器禁用。
#将下面的配置注释掉
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
2.设置tomcat的线程池
#优化二:设置线程池,并且调整最大并发线程数
<!--将注释打开-->
<Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
maxThreads="500" minSpareThreads="50" prestartminSpareThreads="true"
maxQueueSize="500"/>
<!--
参数说明:
maxThreads:最大并发数,默认设置 200,一般建议在 500 ~ 1000,根据硬件设施和业务来判断
minSpareThreads:Tomcat 初始化时创建的线程数,默认设置 25
prestartminSpareThreads: 在 Tomcat 初始化的时候就初始化 minSpareThreads 的参数值,如果不等于 true,minSpareThreads 的值就没啥效果了
maxQueueSize,最大的等待队列数,超过则拒绝请求
-->
<!--在Connector中设置executor属性指向上面的执行器-->
<Connector executor="tomcatThreadPool" port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
3.设置tomcat的运行模式为NIO2模式
#优化三:设置tomcat运行模式为nio2,tomcat的运行模式有3种:bio、nio、apr,其中nio2是nio的升级版,在 tomcat8中才支持的,建议采用nio2模式。
<Connector executor="tomcatThreadPool" port="8080"
protocol="org.apache.coyote.http11.Http11Nio2Protocol"
connectionTimeout="20000"
redirectPort="8443" />
压力测试
我们在优化了tomcat之后,先使用压力测试工具测试下,是否已经满足性能指标。如果不满足性能指标,再考虑进行JVM虚拟机调优。这里我们进行压力测试的工具是jmeter。
使用jmeter压测工具钳,需要先对jmeter的参数进行调整。修改jmeter.bat文件。
调整jmeter参数
set HEAP=-Xms1g -Xmx4g -XX:MaxMetaspaceSize=512m
在该文件中可以看到,jmeter默认使用的垃圾收集器是G1.
Defaults to '-XX:+UseG1GC -XX:MaxGCPauseMillis=100 -XX:G1ReservePercent=20'
添加gc日志相关参数
#内存设置较小是为了更频繁的gc,方便观察效果,实际要比此设置的更大
JAVA_OPTS="-XX:+UseParallelGC -XX:+UseParallelOldGC -Xms64m -Xmx128m -
XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC -
Xloggc:../logs/gc.log -Dcom.sun.management.jmxremote -
Dcom.sun.management.jmxremote.port=9999 -
Dcom.sun.management.jmxremote.authenticate=false -
Dcom.sun.management.jmxremote.ssl=false"
GC日志解析
在使用jmeter初始测试后,会生成一个gc日志。GC日志的内容有很多,直接查看GC日志很不方便,也不不好分析GC过程。因此,我们需要借助GC日志分析工具来解析GC日志,生成GC日志的图形化表格。我们这里使用GC Easy。(http://gceasy.io/)
将GC 日志上传到GC Easy,可以得到如下GC 过程的图形化表格。
JVM内容大小:

吞吐量:

堆内存:

JVM虚拟机优化
从上面的GC 日志分析工具中可以看到,在程序运行过程中多次触发了Full GC。因此,我们在做JVM调优的思路如下:
- 先考虑增大堆内存,增大年轻代大小,再进行压测。
- 如果多次增大堆内存后,性能没有明显提升时,在保存最优堆内存情况下,考虑需要更换垃圾收集器,然后再进行压测。
- 更换垃圾收集器需要考虑到业务场景,我们的业务是以吞吐量为主要目标,还是以低延迟是目标,根据性能目标的不同来选择垃圾收集器。例如:选择Parallel 垃圾收集器,G1垃圾收集器,还是ZGC。我们最后选择什么垃圾收集器还是要依赖于压测结果。
调优建议
- 生产环境的JVM一定要进行参数设定;
- 参数设定不能拍脑袋,需要从实际出发,根据压测结果来定;
- 内存中临时对象较多,将年轻代调大一些。如果是G1或者ZGC就不需要特别指定;
- 调优过程依赖于GC 日志的分析结果,来找到问题;
- 低延迟的应用建议使用G1或者ZGC;
- 不要完全只考虑JVM参数,当JVM参数调到无法再调之后,需要考虑影响性能的其他因素,比如:容器,硬件性能等。
超大流量电商大促高并发系统下JVM调优思路
这种场景下的JVM调优,千万不要被标题吓到。我们要将问题按实际场景分解,分解成一个个小问题,然后针对一个个小问题来解决。例如,百亿流量的电商网站的调优,可以按照如下的思路进行分解。

- 从上面的分析图,可以看出最后我们只需要解决每台机器能抗住208单/s即可;
- 在这些请求中,再找到重点关注的业务区域;
- 对于重点关注的业务区域分析,估计每个每个对象的大小,然后将每个订单对象大小进行扩大,比如扩大100倍。假设每个对象为1K,扩大100倍后就是产生一个订单,就会占用100K内存空间;
- 大促期间,前一小时就是,每秒占用空间就是208 * 100 = 20800K = 20M。
- 根据上面的分析结果来给出JVM主要参数。
- 然后依据初始参数,进行压力测试,不断调整参数,不断进行压测,直至满足性能指标。
上面只是给出了一个大促期间高并发系统的调优思路,具体还需要根据业务场景,环境等具体分析。
本文介绍了JVM调优实战,以web项目为例,主要从Tomcat容器优化和JVM虚拟机调优两方面展开。优化Tomcat包括禁用AJP服务、设置线程池和调整运行模式为NIO2。在进行压力测试后,通过分析GC日志,针对FullGC频繁的问题,提出了增大堆内存、调整垃圾收集器等JVM调优建议。调优过程中强调依据压测结果和业务需求进行参数设定,并关注容器和硬件性能等因素。
634

被折叠的 条评论
为什么被折叠?



