记一次服务cpu爆高异常

image

这几天进行架构整改,将业务服务话,然后单独部署,但是有一台服务的运行时,cpu特别高,基本都是90%以上,导致服务的消费能力特别差。这种级别bug,简直是一种噩梦,但还是必须得解决。

发现问题:

1.服务部署到linux之后,通过==top==命令观察服务的cpu和内存使用情况

image

我们可以很明显的看到,在java进程中cpu使用率超级高,所以我们需要进一步的排查,是java进程中哪一个线程导致cpu如此高负载的。

2.通过如下命令,我们可以查看java进程是因为哪一个线程引起的。

1
2
3
ps -mp 23615 -o THREAD,tid,time
printf "%x\n" 线程号
jstack 进程号|grep 16进制异常线程号 -A90

image

我们可以很明显的看到,最耗费性能的是gc垃圾回收线程引起的,这说明jvm在垃圾回收可能很频繁。

3.通过命令查看jvm垃圾回收情况

1
jstat -gc 2592 5000

image

通过命令,我们可以很明显的看到YGC都没发生,FGC一直在叠加,说明老年代回收频率特别高,这也是cpu爆高的最终原因。

解决方案:

既然问题已经找到了,那我们应该如何解决呢?

从上面的问题可以得出应该是jvm参数配置有误,导致频繁的full gc,新生代回收基本没用到,所以我们需要调整jvm的参数,让full gc少发生,新生代得到充分使用,从而降低cpu占用率。

下面是博主我针对上面的问题,调优而成的配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
-Xmx3000M
最大堆内存
-Xms3000M
最小堆内存
-Xmn600M
年轻代大小
-XX:PermSize=500M
设置持久代(perm gen)初始值
-XX:MaxPermSize=500M
设置持久代最大值
-Xss256K
每个线程的堆栈大小
-XX:+DisableExplicitGC
关闭System.gc()
-XX:SurvivorRatio=1
Eden区与Survivor区的大小比值
-XX:+UseConcMarkSweepGC
使用CMS内存收集
-XX:+UseParNewGC
设置年轻代为并行收集
-XX:+CMSParallelRemarkEnabled
降低标记停顿
-XX:+UseCMSCompactAtFullCollection
在FULL GC的时候, 对年老代的压缩
-XX:CMSFullGCsBeforeCompaction=0
多少次后进行内存压缩
-XX:+CMSClassUnloadingEnabled
垃圾回收会清理持久代,移除不再使用的classes
-XX:LargePageSizeInBytes=128M
内存页的大小
-XX:+UseFastAccessorMethods
原始类型的快速优化
-XX:+UseCMSInitiatingOccupancyOnly
使用手动定义初始化定义开始CMS收集
-XX:CMSInitiatingOccupancyFraction=70
使用cms作为垃圾回收,使用70%后开始CMS收集
-XX:SoftRefLRUPolicyMSPerMB=0
每兆堆空闲空间中SoftReference的存活时间
-XX:+PrintClassHistogram
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-XX:+PrintHeapAtGC
-Xloggc:log/gc.log

应用上述的配置,服务的cpu和内存占有率下降了一大截,稳定性也得到很大的提高,gc回收频率大大降低了。

备注:

因为上述截图,是配置生效之后的数据,所以可能不准确。
参考地址:https://www.cnblogs.com/zexu-cheng/p/5079826.html

林老师带你学编程https://wolzq.com

林老师带你学编程 wechat
欢迎您扫一扫上面的微信公众号,订阅我的博客!