记一次CPU飙升排查过程和解决思路

1,520 阅读2分钟

前言

事情发生了很久,再不记就忘记了。

起因

网关服务大概在20点左右发版,到22点开始出现大量超时。很明显是这次发版引起了这个问题。发版内容就是集成了sentinel服务,用于实时监控流量,降级和熔断。

排查

  • 执行top,发现cpu飙升。心想是sentinel大量时间窗口计算加网络传输;
  • 执行top -Hp pid ,找出具体线程
  • 执行jstack pid,打印线程栈
  • 确定具体线程,发现是gc线程。心想是sentinel在内存保留了大量数据吗?

分析

如果是sentinel引起的,怕是要短时间内集成不了了,这是我不想看到的,毕竟这个服务可以让我实时清晰的看到系统的流量变化,心里对系统运行是有个模型的。所以我心里一直怀着侥幸认为不是sentinel,毕竟我又不是第一个吃螃蟹的人,这已经成熟的产品。于是,开始查看机器的历史数据。这一看就发现问题了。

这几台网关服务每天22点cpu和内存都会飙升。如此有规律的事情,一下就让我想起了每天定时加载2g归属地信息的事情。sentinel只是压死骆驼的最后一根稻草。

解决

  • 加载大文件到内存,改用直接内存地址映射,减少一次cpu拷贝,降低cpu使用率
  • 定时时间改为凌晨3点+ 随机时间段,避免在交易量大的时候进行读取,并将集群错峰触发
  • 将原来大新生代和小老年代的配置改为,适当缩小新生代,调大老年代,降低年龄阈值

解释jvm参数调整思路

服务里的数据分三类:交易数据,sentinel数据和极大量的归属地信息。

当前新生代配置过大,年龄阈值偏高,导致大量归属地数据长期停驻在新生代,一次次经历minorjc,有stw。大量的数据到期后晋升老年代却找不到合适的空间。

系统每秒钟大概产生20M的内存数据,这些数据就像一些中药的特性“走而不守”,所以千万不要让他们有机会进入老年代。

所以思路如下:

  • 调大老年代:让归属地信息迅速进入老年代,因为她们要存会24小时,进入老年代等待fullgc
  • 调小新生代:只要前提是幸存区的一半大小要大于20M数据,交易数据就不会进入老年代
  • 调小年龄阈值:减少归属地信息在新生代的留存时间,提前进入老年代