现象

今天在启动tomcat的过程中遇到启动时间特别长的问题,经过分析发现new SecureRandom().engineGenerateSeed(16)执行时间特别慢。

分析

通过查询发现,jdk本身有一个bug:JDK-6521844 : SecureRandom hangs on Linux Systems。这个bug产生的原因在另一篇文章里有说明[1]:

Q: Why the SecureRandom generateSeed is so slow or even hang on Linux OS?
A: When you login, it hangs or takes more than a minute to get the response.
If your server is on a Linux OS, the culprit here is SecureRandom generateSeed()
which uses /dev/random to generate the seed. However, /dev/random is a blocking 
number generator and if it doesn't have enough random data to provide, it will 
simply wait until it does, which forces the JVM to wait. Keyboard and mouse input
as well as disk activity can generate the randomness or entropy needed. But on a
server that lacks such activies, the problem may arise.

To verify this, run command:

cat /proc/sys/kernel/random/entropy_avail

it could be 150 or less, instead of the normal 3000-4000.

There are two options to workaround this problem:

1) Use jvm param:  -Djava.security.egd=file:/dev/./urandom

or even better

2) run daemon: /sbin/rngd -r /dev/urandom -o /dev/random -t 5
you can add this in rc.local or you can use
/etc/init.d/rngd, but make sure /etc/sysconfig/rngd has
EXTRAOPTIONS="-r /dev/urandom -o /dev/random -t 5"

Or, if you are on systemd, then you might already have rngd.service,
just enable and start it.

run ps -aux|grep rngd to see it is running.

大概意思就是说在linux环境下,SecureRandom会用/dev/random来生成随机种子,而/dev/random是一种阻塞的数据生成器。如果没有足够的数据它会一直等待。这些数据是由键盘、鼠标、磁盘等硬件产生的。如果这些操作比较少,就会导致阻塞。一般服务器是不会连接键盘和鼠标外设的。

问题的解决方式:

  1. 增加jvm启动参数 -Djava.security.egd=file:/dev/./urandom dev/urandom(“unlocked”,非阻塞的随机数发生器)。这表示对/dev/urandom的读取操作不会产生阻塞,但其输出的熵可能小于/dev/random的。它产生的随机数的效果不如random

  2. 打开 $JAVA_PATH/jre/lib/security/java.security 这个文件,找到下面的内容:securerandom.source=file:/dev/random替换成:securerandom.source=file:/dev/./urandom

关于urandom的文章 可参考:myths-about-urandom