这几天新项目每次发布,都发现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指标都比较正常。