之前写完一个项目,像平常一样mvn clean install 打成war包,接着放入Tomcat的webapps目录下,最后启动bin目录的startup.sh,最多10几秒后,访问首页,一切正常。
最近有几次,同样的war包,启动Tomcat居然花费这么长的时间。
这么久,我等的花都谢了。一度以为自己的war包有问题,重新打包,放入Tomcat中,依然启动缓慢。接着以为Tomcat的版本有问题,又换了一个高版本的试了下,依然出现同样的问题。
还好,我仔细查看了logs底下的catalina.out文件,看到有一个过程耗时严重。
这段话的意思是,Tomcat使用SessionIdGeneratorBase.createSecureRandom创建一个安全的随机数实例作为会话id,产生随机数的算法为SHA1PRNG。
问题就出在这个随机数生成算法中,查阅资料,发现该算法有两种文件形式的初始化方式:
- /dev/random
- /dev/urandom
它们产生随机数的原理是利用当前系统的熵池来计算出固定一定数量的随机比特,然后将这些比特作为字节流返回。
熵池就是当前系统的环境噪音,熵指的是一个系统的混乱程度,系统噪音可以通过很多参数来评估,如内存的使用,文件的使用量,不同类型的进程数量等等。
他们的区别在于:
/dev/random,是一种高质量的随机数生成器,具有非常高的保护性与安全性,因此需要熵池收集到足够的噪声数据。当熵池为空或者熵池没收集到足够多的的数据时,将会阻塞随机数的生成,也终将阻塞Tomcat的启动,从而造成Tomcat启动耗时严重。/dev/random非 常适合那些需要非常高质量随机性的场景,比如一次性的支付或生成密钥的场景。
而/dev/urandom,不会阻塞,当然生成随机数的效果也不好。在仅仅将随机数作为会话id时,我们没有必要使用安全性与随机性特别高的/dev/random,使用/dev/urandom便可以满足,这将大大缩短Tomcat的启动时间,从几分钟缩短至几秒钟。
解决方案有以下两种:
- 在Tomcat环境中解决
在catalina.sh中加入这么一行:-Djava.security.egd=file:/dev/urandom 即可。如图:
- 在jdk安装目录配置
编辑$JAVA_HOME/jre/lib/security/Java.security文件,将securerandom.source=file:/dev/random 中的random换成urandom即可。
不过,一般不推荐第二种方法。第二种方式虽然可以一劳永逸,但是却限制所有的项目默认使用随机性与安全新较低的urandom。按照哲学观点来看,具体问题具体分析,且解决方案应该具有针对性,我们只需修改Tomcat的catalina.sh脚本即可。
按照第一种方式修改后,Tomcat的启动时间大幅度缩短了,今天又可以早点下班了。