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 解决
- 尽量少用不合格的正则去匹配,如果要应用正则,且数据量大的状况下,进行尽量减少回溯
- 尽量少用一些底层是正则表达式实现的字符串拼接形式,例如
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…
-
抉择
plguins
-
找到
Plugins Centers
-
点击后抉择对应的
jdk
版本插件,我的jdk
版本为java8_u40
版本
5. 关上 jvisualvm
,找到 工具 - 插件 ,抉择编辑,填上对应的jdk
插件地址
-
找到对应插件装置即可
-
装置好后能够点击
Visual GC
查看实时 GC 状况
4.4 近程
失常状况下,都是将 jar
部署在近程机器上,因而想要查看实时 GC
就能够通过近程连贯进行查问
个别近程连贯有两种形式:
-
JMX
连贯这种形式连贯个别只能监控一个 java 服务
-
Jstatd
连贯这种形式连贯能够监控多个 java 服务
4.4.1 JMX
-
在近程 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
-
在
Jvisualvm
上新建一个近程连贯填写对应的主机名
填写好了如下:
-
在连贯名上右键抉择增加一个
JMX
连贯端口号要与服务端配置的一样,接下来点击连贯即可,当然界面与之前本地是一样的,如下:
然而当点开
VisualGC
时,却显示如下后果:不受此 JVM 反对
,因而能够应用Jstatd
进行连贯
4.4.2 Jstatd
-
在
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";
在文件中退出上述内容,如下:
-
再次执行命令,即可胜利
jstatd -J-Djava.security.policy=/opt/jstatd.all.policy -p 端口 -J-Djava.rmi.server.logCalls=true -J-Djava.rmi.server.hostname= 近程服务器 ip
-
连贯
jstatd
, 右键新建jstatd
连贯-
最初能够看到所有的组件信息
最初轻易点开一个组件便可看到对应的
GC
状况
-