背景
最近在本地启动项目,发现启动时间变得超级慢,以前一会就启动完的项目,现在启动十来分钟还迟迟没能响应。刚开始怀疑是不是最近应用做了哪些改动,增加了耗时的操作,导致启动变得奇慢无比。但是看了测试环境跟生产环境应用的启动时间,发现两个环境的启动时间跟之前无差。合着只有在本地启动才慢(可能想让我接着启动时间好好休息下),但是因实在忍受不了这个启动时间,所以决定看看是啥问题导致的。
项目: springboot + dubbo
本地系统:mac
开发环境:idea + jdk1.8
寻找突破点
应用启动的时候,在初始化各种bean的时候,会在控制台打印日志,但是对着密密麻麻的日志一顿找,看下来也没找到突破口。有点像无头苍蝇一样,没有分析的着力点。想着在springboot启动的各个扩展点加上一些自定义的实现,来看看具体耗时在哪里,但是扩展点多,又不想在应用上做改动(主要是懒),于是便没有用这种方式来定位。
想起之前在优化另一个项目的启动时间时,用了一款挺好用的工具,于是便再去github上把该项目找出来用(顺丰哪有顺手快)。这里也给大家安利一下:github.com/linyimin081...
这个开源项目,主要是用于分析springboot项目的启动耗时的,非常对口。于是按照说明,把release包下载下来解压备用。按项目说明,在idea启动应用时,添加jvm参数:
java
-javaagent:解压路径/spring-startup-analyzer/lib/spring-profiler-agent.jar
其他的保持默认,没再单独设置其他启动参数。接着将项目启动,经过漫长的等待,项目启动完成之后控制台会打印:
======= spring-startup-analyzer finished, click http://localhost:8065 to visit details. ======
点击链接访问,就可以看到应用启动耗时及各个bean的初始化时间。
优化前
真是不看不知道,一看就知道。在本地启动应用的时候,耗时居然近1000S
点进去Spring Bean Initialization查看bean初始化耗时,可以看到有些bean耗时很高
然而去到对应的类的代码去看,也没有特殊的耗时操作。为了更加直观的看出哪里有耗时瓶颈,于是打开最下面的火焰图:
通过火焰图可以看到,java.net.InetAddress.getLocalHost耗时比较高。想着会不会跟本地的一些host配置有关导致getLocalHost耗时高。于是快速写个demo验证下:
java
public class Test {
public static void main(String[] args) throws UnknownHostException {
long start = System.currentTimeMillis();
InetAddress localHost = InetAddress.getLocalHost();
long end = System.currentTimeMillis();
System.out.println("getLocalHost time cost: " + (end - start));
start = System.currentTimeMillis();
String hostName = localHost.getHostName();
end = System.currentTimeMillis();
System.out.println("getHostName time cost: " + (end - start));
System.out.println(hostName);
}
}
程序打印结果:
getLocalHost time cost: 5030
getHostName time cost: 12
wiggindeMacBook-Pro.local
尝试解决
单是getLocalHost就用了5S,那程序里各种网络连接或多或少都会用到getLocalHost,那这样算下来整个耗时就会被拉的很长。于是上网查了下,修改了本地host配置,将我电脑的hostName配置进去
java
127.0.0.1 localhost wiggindeMacBook-Pro.local
然后刷新下dns
java
sudo killall -HUP mDNSResponder
完成上述操作之后再运行demo程序,得到的输出结果如下
getLocalHost time cost: 23
getHostName time cost: 0
wiggindeMacBook-Pro.local
可以看到 getLocalHost由原来的5s锐减成23毫米,看了配置是生效了。于是重新启动项目:
可以看到优化后,启动时间变为97秒
再次打开火焰图可看到,java.net.InetAddress.getLocalHost造成的瓶颈已经消失。
至此,应用本地启动时间恢复正常,我的战术性休息时间也没了