JVM调优实战—接口成功率下降排查与优化

一、告警通知

在某个上午收到接口成功率下降的告警通知,本着生产优先的原则立马分析:
file

二、锁定慢服务

通过告警信息可以看到监控告警来源于网关,于是登录网关查看日志,发现多条与queryProudct接口相关的日志,因此提取一条日志,具体详情如下所示:
 
file
 
可以看到网关收到请求到响应请求耗时为3.003秒,网关向微服务发起请求到收到响应为3.002秒,因此基本可以排除是网关积压导致,根据找到的traceId到微服务中找到的日志如下:
 
file
 
先介绍一下LogFilter,服务中接口通过dubbo框架向外暴露rest协议,外部通过http向服务发起请求。LogFilter实现Dubbo中Filter接口,通过SPI机制让Dubbo启动时加载LogFilter,通过order将LogFilter设置成首个执行Filter,在里面打印接口请求出入参及耗时。
 
从LogFilter可以看到服务收到请求、处理请求到响应请求耗时仅为17ms。将dubbo与网关之间的传输耗时纳入考虑(考虑传输的包体大小,假设网络传输耗时为20ms),但整体37ms还是与3.002s相差甚远,时间消耗在哪儿了?
 
从以上基本可以排除是网关积压导致。

三、问题排查
1、服务接口流量

检查服务中queryProduct及其他高流量接口,并未发现流量有突变。

2、kafka流量

Kafka消费在09:55有个上升突变到10点达到顶峰,持续到11:15开始下降,11:30时基本触底,因此基本可以排除是kafka消息量突变引起。结合接口流量和kafka消息量,基本可以排除是突增流量导致。
file

3、响应包体大小

根据网关日志提取服务最近访问接口量及包体大小(最后一列为包体大小,单位为byte),未发现包体特别大的响应,此处基本锁定接口慢就是微服务引起,与包体大小无关。

4、http线程

file
可以看到11:30时http线程数存在尖刺,有个陡增,怀疑是服务变慢或暂停导致长时间无法响应请求,需要创建新的线程处理新请求,因此需要查看gc监控。

5、gc监控及日志

file
file
file
服务使用jdk版本为1.8,垃圾回收器用的G1,从日志可以看到进行young gc耗时为8.1秒。根据JVM知识可知年轻代回收会暂停服务(STW),因此锁定接口超时是因young gc长时间暂停造成,找到问题后接下来分析为什么会出现长暂停。

四、问题分析

由G1知识可知在进行young gc时,根据三色标记法会将Eden和So区域中的存活对象复制到S1时,如果S1不够,将会由老年代空间进行担保。日志中出现to-space exhausted、Evaciation Failure等关键字可以看出此次回收中,将Eden和So存活对象复制到S1时,S1空间不够,由担保机制会将存活对象转移到老年代时,老年代空间同样不足,因此出现转移失败(Evaciation Failure)。因老年代不足g1将会增加老年代空间,然后将存活对象转移到老年代,对象复制耗时比较长(Object Copy耗时7s)。

gc前:
老年代已使用量:5395-3672-14=1709
最大的老年代:6144-3672-14=2458
老年代剩余使用空间为:2458-1709=749

gc后:
老年代已使用量:4429-0-462=3967
最大的老年代:6144-624-462=5058

gc前后老年代增量:
老年代增量:3967-1709= 2258>749

可以看出就是因老年代空间不足导致担保失败。

五、优化jvm参数
  • 老年代内存担保失败,因此将-XX:InitiatingHeapOccupancyPercent从45%调到40%,尽早启动mixedGc,尽早回收老年代内存(G1年轻代和老年代都是copy对象,因此回收年轻代、老年代成本差不多);

  • G1内部有很多自适应机制,自适应动态调整年轻代比例(最小和最大比例默认值如下:-XX:G1NewSizePercent=5 -XX:G1MaxNewSizePercent=60),将年轻代比例大小适当降低,调整为50%。jdk1.8中此参数为实验参数,因此需要打开 -XX:+UnlockExperimentalVMOptions;

优化后的JVM参数为:
-server -Xmx6g -Xms6g -XX:MetaspaceSize=512m -XX:MaxMetaspaceSize=512m -Xss256k -XX:+DisableExplicitGC -XX:LargePageSizeInBytes=128m -XX:+UseFastAccessorMethods -XX:+UseG1GC -XX:MaxGCPauseMills=200 -XX:max-XX:+UseStringDeduplication -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/app/deploy/logs/heapDump.hprof -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=10M -Xloggc:/app/deploy/logs/gc-log.log -XX:+UnlockExperimentalVMOptions -XX:G1LogLevel=finest -XX:InitiatingHeapOccupancyPercent=35 -XX:G1MaxNewSizePercent=50 -XX:+PrintHeapAtGC

六、优化效果

在完成问题分析后,当天晚上修改参数重启服务,观察一周多尚未出现to-space exhausted和长时间young gc出现。
file
file

七、总结

当服务出现问题时可以参考以下步骤进行定位分析:

  • 从内存、CPU、线程维度查看监控;

  • 从服务流量、网卡流量维度方面检查,判断是否由流量增加导致;

  • 从gc方面观察,是否存在fullGc、大对象及jvm参数设置是否合理;

  • 如果是内存问题可以提取堆dump,用工具(比如MAT)进行分析,查看是否存在内存泄漏及大对象;

  • 如果是线程问题则打印线程栈,查看线程的状态,分析是否存在死锁;

  • 查看所依赖的三方中间件(比如redis、kakfa、mysql、zk等)是否正常,是否是三方中间件故障导致;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值