1. 前言

最近产品在一般压测下并没有理论问题,然而在理论环境的大数据(日数据量在1.3亿左右)状况下便呈现了一些列的性能问题,因而进行一系列的状况调优

当然每种问题解决的计划不一样,这里只是记录集体解决问题的计划与步骤

2. cpu标高

cpu标高问题是由一系列问题导致的,具体能够通过以下两种计划去进行解决:

  • 通过jdk提供的工具去进行解决
  • 通过arthas工具去进行解决

当然这种状况的前提时java过程的日志无报错,只是CPU使用率较高的状况,如果有显著的报错

那么就能够通过谬误日志去进行诊断

2.1 arthas

arthas是由阿里巴巴开源的一个性能诊断工具,这里就不再赘述,间接上演示步骤,具体如下:

a. 定位过程

当CPU标高时,能够通过top指令去查看,如下图:

从图中能够看出CPU的总使用率在2.8%左右,然而从具体的过程来看有的java过程在31%左右

当然这必定是失常的,这里只是举了个例子,每个状况不一样,须要具体分析

当然装置了`htop命令,通过htop命令去查看CPU每个核具体的应用状况,如下:

b. 通过top指令定位当前,则能够通过具体的jps命令去查看占用较多的是哪个过程,如下:

能够发现是log-service目前占用较高,那么就能够查看这个过程的问题

c.启动arthas工具,具体怎么应用这里就不再赘述,如下:

这里抉择3-log-service过程,输出dashboard命令便能够看到这个过程的监控信息如下:

输出thread -n 8命令能够查看到cpu使用率最高的八个线程日志,cpu利用率从高到低排列,如下:

最初找到本人程序的代码行数,剖析这行代码占用性能的起因

2.2 影响

从目前优化的过程来看,次要有两大因素(针对的是本人的零碎)比拟耗费资源,如下:

  • 正则表达式匹配
  • 数据库操作

2.2.1 正则

A.问题

在JAVA中,正则表达式匹配采纳的是NFA(Non deterministic Finite Automaton)去进行匹配,该机制在遇到像 +,*等不确定字符串时,会进行 回溯

在一些数据量大,且写的正则表达式不是那么合格时,就会进行一直回溯,从而会特地耗费CPU资源

在这里对于具体详情能够举荐一遍别人的博客

B 解决

  1. 尽量少用不合格的正则去匹配,如果要应用正则,且数据量大的状况下,进行尽量减少回溯
  2. 尽量少用一些底层是正则表达式实现的字符串拼接形式,例如String.format

所有的前提都是基于数据量大的状况,数据量小请疏忽,

能够用Jmeter 等工具去进行性能压测,验证上述后果


2.2.2 数据库

这种实践较为简单,即在一个循环外面频繁操作数据库,如下:

for(String ss : aa) {    database_opertor()}

这种形式每循环一次,那么就会操作发送一次数据库连贯,在数据量较大的状况下就会特地耗费CPU资源

因而倡议将多个数据库连贯改为一个或者升高数据库连贯形式,如下:

  • 查问一次,具体后果能够通过Stream流解决
  • 批量新增
  • 批量更新
  • 批量删除

所有的前提都是基于数据量大的状况,数据量小请疏忽,

能够用Jmeter 等工具去进行性能压测,验证上述后果

3. GC

对于GC问题,次要是针对JVM始终Full GC问题,在这里也记录一下FullGC过程,具体过程如下:

A.问题

测试人员通过Grafana监控到Java组件内存始终成回升趋势,那么可能就会存在内存泄露危险,如下图:

起初通过一系列剖析,可能是JVM始终在FullGC导致,因而为了验证这个想法,在这里借助了jvisualvm工具去进行剖析(在附文中会具体论述应用该工具),剖析后果如下:

发现老年代间接拉满,当老年代拉满后,就会频繁FullGC,然而通过几轮GC后,发现还是拉满,这个时候就须要剖析为什么会存在拉满起因

当我把对应的组件重启后,堆外面old很快爆满,而后频繁FullGC

因而能够用过jmap命令把堆内存中的信息dump下来,如下:

jmap -dump:file=filename.dump pid

命令执行后会产生一个filename.dump文件,通过jvisualvm工具剖析这个文件,就晓得对堆外面对象信息是什么了

B.起因

通过jmap产生的dump文件剖析外面都是生产kafka的音讯,也就是说old外面都是生产kafka的音讯

之所以old爆满,是因为生产kafka音讯太多,当第一次启动时,Eden区爆满,通过第一轮YGC,大部分对象还没解决完,因而间接进入了s0

然而因为进入了s0区的对象超过了s0区容量的一半,因而就不再计算年龄,而是间接从s0进入到老年代,所以通过几次生产old始终处于爆满状态,而后始终FullGC,导致内存始终增长,最初存在内存泄露

C.解决

其实上述问题能够看出,其实还是老年代空间较小,我的组件配置为-Xms6G -Xmx6G -Xmn5G,也就是说我的配置老年代也就只有1G的空间,因而解决方案如下:

  • 调小生产kafka的数量,这样数据量升高了也就不存在频繁FullGC状况

    这种计划最初放弃了,因为调小了生产的数据量,性能就达不到要求
  • 调大堆内存,减少old空间大小

    这种也放弃了,资源无限,不太好做调整了
  • 切换G1垃圾回收器

    最终采纳的该计划,G1(JAVA 9默认的垃圾回收器就是这,目前我应用的时JAVA 8),该垃圾回收器与默认的垃圾回收器不同,这个并没有物理上的分代,而是将一整块内存,划分成一个个的小内存,并且给内存打上old,eden,s0,s1标记(具体能够本人理解),切换后整体如下:

    完满解决了我的困扰

4.附文

这一章次要是论述Jvisualvm工具的应用

4.1启动

JAVA_HOME/bin/目录下

双击即启动,启动界面如下:

4.2.介绍

在本地中抉择VisualVM在左边即可看到对应的JVM信息,同时能够在监督中看到对应的区域信息,如下:

也能够在线程中看到所有的线程状况,如下:

当然也能够装置一个Visual GC插件查问实时GC状况,装置步骤如4.3所述

4.3 插件

介绍如何装置插件

1.拜访插件更新地址:https://visualvm.github.io/in...

  1. 抉择plguins

  2. 找到Plugins Centers

  3. 点击后抉择对应的jdk版本插件,我的jdk版本为java8_u40版本

5.关上jvisualvm,找到 工具-插件,抉择编辑,填上对应的jdk插件地址

  1. 找到对应插件装置即可

  2. 装置好后能够点击Visual GC查看实时GC状况

4.4 近程

失常状况下,都是将jar部署在近程机器上,因而想要查看实时GC就能够通过近程连贯进行查问

个别近程连贯有两种形式:

  • JMX连贯

    这种形式连贯个别只能监控一个java服务

  • Jstatd连贯

    这种形式连贯能够监控多个java服务

4.4.1 JMX

  1. 在近程Java服务上配置JMX连贯,如下:

    -Djava.rmi.server.hostname=服务器ip -Dcom.sun.management.jmxremote.port=jmx端口 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false
  2. Jvisualvm上新建一个近程连贯

    填写对应的主机名

    填写好了如下:

  1. 在连贯名上右键抉择增加一个JMX连贯

    端口号要与服务端配置的一样,接下来点击连贯即可,当然界面与之前本地是一样的,如下:

    然而当点开VisualGC时,却显示如下后果:不受此JVM反对,因而能够应用Jstatd进行连贯

4.4.2 Jstatd

  1. java服务新建jstatd-all.policy,文件能够放在任意地位,内容如下

    // 留神:这里倡议写JAVA_HOME的绝对路径grant codebase "file:${JAVA_HOME}/lib/tools.jar" {  permission java.security.AllPermission;};

    最初执行jstatd -J-Djava.security.policy=/opt/jstatd.all.policy -p 12345命令,如果呈现以下问题,装置上面配置即可

    最初发现权限有余,因而去进行受权,批改${JAVA_HOME}/jre/lib/security/java.policy文件

    permission java.io.FilePermission "/tmp/-", "read";permission java.util.PropertyPermission "*", "read";permission java.net.SocketPermission "*", "connect,resolve,accept,listen";permission java.util.PropertyPermission "*", "read";

    在文件中退出上述内容,如下:

  2. 再次执行命令,即可胜利

    jstatd -J-Djava.security.policy=/opt/jstatd.all.policy -p 端口 -J-Djava.rmi.server.logCalls=true -J-Djava.rmi.server.hostname=近程服务器ip
  3. 连贯jstatd,右键新建jstatd连贯

    1. 最初能够看到所有的组件信息

      最初轻易点开一个组件便可看到对应的GC状况