Springboot tomcat 启动慢 响应时间超长 问题解决

之前允许都正常的springboot jar,今天突然启动后反应非常慢,尤其是调用微信接口的方法,页面request一直处于pending状态。
经过长时间(5分钟)的等待后,日志打出下面warn:
o.a.c.util.SessionIdGeneratorBase : Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [170,241] milliseconds.


之前在ssm+tomcat里遇到过类似问题,今天第一次在springboot里遇到,搜了下网上也有各种解决方法,总结一下:

原因

(引自https://www.jianshu.com/p/30aa8e43a396)
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/jdk<版本号>/jre/lib/security/java.security
securerandom.source=file:/dev/random
可以看到默认值是:/dev/random。
所以程序启动后SecureRandom类会读取/dev/random以获取随机序列,这是一个同步操作。当熵池(entropy pool) 中没有足够的熵时,读取/dev/random就会造成阻塞,直到收集到了足够的熵,程序才会继续往下进行。
(关于什么是/dev/random,可以查看 wiki的介绍

解决办法

java -jar xxx.jar -Djava.security.egd=file:/dev/./urandom
在启动的时候加上 -Djava.security.egd=file:/dev/./urandom

但是,偶尔会发现失效了,遂找到以下方法:
打开/usr/java/jdk<版本号>/jre/lib/security/java.security这个文件,找到下面的内容:
securerandom.source=file:/dev/urandom

securerandom.source=file:/dev/random
替换成
securerandom.source=file:/dev/./urandom

Bingo!

原理

SHA1PRNG算法是基于SHA-1算法实现且保密性较强的伪随机数生成器。
在SHA1PRNG中,有一个种子产生器,它根据配置执行各种操作。
1)如果Java.security.egd属性或securerandom.source属性指定的是”file:/dev/random”或”file:/dev/urandom”,那么JVM会使用本地种子产生器NativeSeedGenerator,它会调用super()方法,即调用SeedGenerator.URLSeedGenerator(/dev/random)方法进行初始化。
2)如果java.security.egd属性或securerandom.source属性指定的是其它已存在的URL,那么会调用SeedGenerator.URLSeedGenerator(url)方法进行初始化。
这就是为什么我们设置值为”file:///dev/urandom”或者值为”file:/./dev/random”都会起作用的原因。
在这个实现中,产生器会评估熵池(entropy pool)中的噪声数量。随机数是从熵池中进行创建的。当读操作时,/dev/random设备会只返回熵池中噪声的随机字节。/dev/random非常适合那些需要非常高质量随机性的场景,比如一次性的支付或生成密钥的场景。
当熵池为空时,来自/dev/random的读操作将被阻塞,直到熵池收集到足够的环境噪声数据。这么做的目的是成为一个密码安全的伪随机数发生器,熵池要有尽可能大的输出。对于生成高质量的加密密钥或者是需要长期保护的场景,一定要这么做。
那么什么是环境噪声?
随机数产生器会手机来自设备驱动器和其它源的环境噪声数据,并放入熵池中。产生器会评估熵池中的噪声数据的数量。当熵池为空时,这个噪声数据的收集是比较花时间的。这就意味着,Tomcat在生产环境中使用熵池时,会被阻塞较长的时间。

Springboot启动慢SecureRandomSHA1PRNG熵源/dev/random/dev/./urandom