屡遭下线的系统

紧急任务

近期,接到一个紧急的任务:某个客户的某业务系统已经上线两次了,但由于性能的原因和潜在的风险都被退了回来,亟需找到根源并且解决。嗯,这的确是一个棘手的问题,关键是已经没有再犯错的空间了。

第一时间赶到客户方,项目相关人员立即开会给讲解当天在生产环境的情形:系统是周五晚上上线的,周六日并没有出现什么异常,但是到周一早上10点左右,运维人员监控到系统的某个服务器的单个CPU核心使用率达到100%,并持续了好一段时间,考虑到之前已经挂过一次,从风险控制的角度先回滚、线下找原因是更稳妥的策略,于是只能紧急回滚到老系统。因此问题的表象,就是某个服务器的单个CPU核心使用率达到100%。

寻找真相

马上,我们着手了解该系统主要的业务流程,并准备好了基础的测试脚本。压测期间,密切监控着各服务器的网络、内存、CPU、磁盘读写等资源的使用情况,尤其是CPU资源使用情况。经过多轮测试,终于发现有一个进程会一直占用较高内存,导致单个CPU核心使用率达到100%,与那天在生产环境的情况非常类似。

于是,仔细观察并分析这个进程,发现在高并发下,该进程会频繁进行Full GC (Garbage Collection,垃圾回收),几乎是每秒进行一次。我们猜测就是因为频繁进行Full GC导致单个CPU核心使用率达到100%。通过查看该进程的相关参数配置,发现内存配置是过低了,导致在高并发下出现内存资源分配不足需要频繁进行Full GC的情况。

既然定位了问题,那么直截了当的做法就是把进程的JVM内存配置相关参数调大。果不其然,配置更新后,就再也没有出现单个CPU核心使用率达到100%的现象了,该问题迎刃而解。

知识补充

说到垃圾回收(Garbage Collection, GC),很多人就会自然而然地把它和Java联系起来。在Java中,程序员不需要去关心内存动态分配和垃圾回收的问题,这一切都交给了JVM来处理。

VM内存区域总体分两类,heap区和非heap 区。

heap区:堆区分为Young Gen(新生代),Tenured Gen(老年代-养老区)。其中新生代又分为Eden Space(伊甸园)、Survivor Space(幸存者区)。

非heap区: Code Cache(代码缓存区)、Perm Gen(永久代)、Jvm Stack(java虚拟机栈)、Local Method Stack(本地方法栈)。

备注:-Xmx(堆的最大值)、-Xms(堆的最小值)、-Xmn(堆年轻代大小)

GC有两种类型:Minor GC(新生代回收)和Full GC(老年代回收)。

一般情况下,当新对象生成,并且在Eden申请空间失败时,就好触发Minor GC,对Eden区域进行GC,清除非存活对象,并且把尚且存活的对象移动到Survivor区。然后整理Survivor的两个区。这种方式的GC是对年轻代的Eden区进行,不会影响到年老代。因为大部分对象都是从Eden区开始的,同时Eden区不会分配的很大,所以Eden区的GC会频繁进行。

Full GC对整个堆进行整理,包括Young, Tenured和Perm。Full GC一般伴随一次Minor GC,有几种触发条件:

老年代(Tenured)空间不足

永久代(PermSpace)空间不足

统计得到的Minor GC晋升到老年代的平均大小大于老年代的剩余空间

System.gc()被显示调用

Full GC因为需要对整个堆进行回收,所以比Minor GC要慢,因此应该尽可能减少Full GC的次数。

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180228B0KSYL00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券