这几天新项目每次发布,都发现load在jetty重启过程中突然load会从0.1突然升高到15以上,3分钟后慢慢降到正常非常,cpu使用率也升高了一些,但是jvm内存线程,gc都比较正常,所以怀疑应用已启动,执行了一些耗CPU的处理过程,查看了代码之后,应用已启动,执行最多的方法是dowork,而这个方法里面会有解析xml的过程:
public OfferInfo parseXml(String content) throws NumberFormatException, XMLStreamException {
if (content == null || content.isEmpty()) {
return null;
}
XMLInputFactory factory = XMLInputFactory.newInstance();
XMLStreamReader reader = null;
try {
reader = factory.createXMLStreamReader(new StringReader(content));
} catch (XMLStreamException e1) {
return null;
}
if (reader == null) {
return null;
}
OfferInfo offerInfo = new OfferInfo();
while (reader.hasNext()) {
int event = 0;
try {
event = reader.nextTag();
} catch (Exception e) {
}
switch (event) {
case XMLStreamConstants.START_ELEMENT:
if (reader.getLocalName().equalsIgnoreCase(OFFER_ID)) {
offerInfo.setOfferId(Long.parseLong(reader.getElementText()));
} else if (reader.getLocalName().equalsIgnoreCase(MEMBER_ID)) {
offerInfo.setMemberId(reader.getElementText());
} else if (reader.getLocalName().equalsIgnoreCase(ACTION)) {
offerInfo.setAction(reader.getElementText());
}
break;
case XMLStreamConstants.END_ELEMENT:
break;
}
}
return offerInfo;
}
这段代码会解析整个xml文档,只取出里面三个字段,这里的应用场景是异步消息处理,因为应用在重启过程中,消息堆积,应用启动完后会处理比较多的堆积消息,导致load和cpu升高,开始怀疑这段解析xml的过程耗性能,因为xml内容很大,达到1m以上,而且消息堆积量一下子也可能上万,然后就开始进行优化,
在while循环中加入以下代码:
//如果已经解析完需要的字段,则跳过剩余xml内容的解析,提高性能
if(offerInfo.getOfferId() != null && offerInfo.getMemberId() != null && offerInfo.getAction() != null){
return offerInfo;
}
只要解析出我们需要的三个字段,剩余的xml内容就不需要解析了,返回。
加上这段代码后,线上果然正常了。
因为在发布过程中来不及用jstack dump线程信息,用jstack dump线程信息,查看下当前线程处理状况,也应该很快能诊断出问题。
解析xml时解析完需要的数据就需要返回了,剩下的xml内容不需要解析,xml解析很耗性能。
我们看下修改这段代码前后的load和cpu的图
其他jvm指标都比较正常。