spring boot 程序启动缓慢的问题

Posted King-D

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring boot 程序启动缓慢的问题相关的知识,希望对你有一定的参考价值。

今天发现一台服务器上的springboot程序启动特别慢,完全启动起来用了有好几分钟。刚开始以为是代码写的有问题造成了卡死,直到看到这条log:

2017-03-08 10:06:49.600  INFO 6439 --- [main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8888 (http)
2017-03-08 10:06:49.613  INFO 6439 --- [main] o.apache.catalina.core.StandardService   : Starting service Tomcat
2017-03-08 10:06:49.614  INFO 6439 --- [main] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/8.0.37
......
2017-03-08 10:09:10.167  INFO 6439 --- [ost-startStop-1] o.a.c.util.SessionIdGeneratorBase        : Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [140,108] milliseconds.

原来是tomcat的启动耗费了140多秒。而罪魁祸首是这个SecureRandom类。

其实,这个问题我之前就有耳闻,但从没遇到过,也就没太在意。今天终于让我遇上了,墨菲定律又生生应验了一回。。

tomcat的文档里有个概念叫Entropy Source(熵源)

Tomcat 7+ heavily relies on SecureRandom class to provide random values for its session ids and in other places. Depending on your JRE it can cause delays during startup if entropy source that is used to initialize SecureRandom is short of entropy. You will see warning in the logs when this happens, e.g.:

<DATE> org.apache.catalina.util.SessionIdGenerator createSecureRandom
INFO: Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [5172] milliseconds.

意思是tomcat7以上的版本,在启动时会调用SecureRandom类来生成随机数。如果用于初始化SecureRandom熵源是个短熵(熵不够用),那么就会报文章开头说的warning了。

jdk的配置文件中,使用securerandom.source设置了熵源:

cat /usr/java/jdk1.8.0_121/jre/lib/security/java.security
 
securerandom.source=file:/dev/random

可以看到默认值是:/dev/random
所以程序启动后SecureRandom类会读取/dev/random以获取随机序列,这是一个同步操作。当熵池(entropy pool) 中没有足够的熵时,读取/dev/random就会造成阻塞,直到收集到了足够的熵,程序才会继续往下进行。
(关于什么是/dev/random,可以查看 wiki的介绍

解决方法是修改成非阻塞的熵源/dev/urandom
可以修改java.security文件中的securerandom.source值,也可以使用参数java.security.egd

java -jar app.jar -Djava.security.egd=file:/dev/./urandom

至于为什么是/dev/./urandom,而不是/dev/urandom,这源于java的一个bug。大意是/dev/urandom在某些情况下可能还是最终会转换成调用/dev/random。所以为了保险起见,还是使用/dev/./urandom吧!

以上是关于spring boot 程序启动缓慢的问题的主要内容,如果未能解决你的问题,请参考以下文章

重启 Spring Boot 应用程序后第一次调用缓慢

解决spring-boot启动中碰到的问题:Cannot determine embedded database driver class for database type NONE(转)(代码片段

一张图,理顺 Spring Boot应用在启动阶段执行代码的几种方式

一张图帮你记忆,Spring Boot 应用在启动阶段执行代码的几种方式

一张图,理顺 Spring Boot应用在启动阶段执行代码的几种方式

一张图,理顺 Spring Boot应用在启动阶段执行代码的几种方式