在客户那部署 Springboot项目,启动非常慢要2-3分钟. 因为开发的时候本地windows启只要7s,测试环境也是centos只要7s.
因为客户那是虚拟化了3台机器, 安装同样的操作系统,但其中1台很快7s,其他两台很慢.这就非常奇怪了.
网上大部份都说random的原因, 我们全都照着改了依然很慢.
通过strace确切知道改成功了,没改之前全是random,改了之后有urandom.
但是可以发现还是会调random, 而且机器的随机数值一直在3000左右,所以可以排除random原因.
奇怪的是系统也没有报错,就是启动慢,启动成功后接口页面都没有问题.关键是有1台机器又很快,所以让我们只能考虑是机器原因或虚拟化的原因.然后我们复制了一台那个没有问题的机器, 在这一台上重新部署,结果依然是很慢.查看cpu 内存 io 都没有什么问题.
通过starce也只能看出是 futex 花费了大量时间,下图上11254这个进程id,这个futex花费了1.89s,然后往上找到11254的源头也看不出什么原因导致.
然后怀疑应该不是我们项目问题,我拿一个最简单的springboot项目测试也是很慢.
然后把springboot日志级别调成debug, 刚开始查问题的时候就已经试过了调日志,因为发现出现Spring那个logo之前很慢而且也没有日志, 然后后面的日志又太长,以为找不出什么有用的信息,试过一次后就又调成info级别了.
我们启动慢的情况是这样的,启动后, 等几十秒出现Spring logo, 然后跑了一会儿,又等几十秒,然后系统启动成功.
所以这一次想到,虽然启动前没有日志,但是中间的慢,应该可以知道它停在哪里.然后google那个停在那里的日志.
点进去后有一句话看的我心头一愣 , 这个用户说,似乎这20s的等待是由于NetworkInterface.getAll
方法
我突然眼前一亮,赶紧看一下我用jstack输出的文件,我用jstack输出了三个文件
1刚启动的时候,2第二次卡顿的时候,3启动成功的时候
果然在第一个和第二个文件里都有因为调用网络相关的接口,而第三个则没有.
那么也就是说根本原因就是 InetAddress.getLocalHost 导致很慢的原因了.
然后用那个最简单的Springboot项目调用一下这个方法,果然不出所料花了20s的时间.
找到根本原因随便一搜就知道,是因为在/etc/hosts 里并没有加入当前主机的名字,.
在正式环境下加入了主机名后果然快了.
那为什么有一台很快了,因为那一台是另一个同事装了mq,他修改了这个hosts文件加了主机名.
然后复制这台机器的时候会填一个新主机名,所以复制的那一台机器也很慢.
最终解决掉了这个奇怪的问题,通过这一次经历,也学会了使用strace,jstack等调试工具,也有不少的收获.