【解決】Linux Tomcat啟動慢--Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [236,325] milliseconds


一、背景

今天部署項目到tomcat,執行./startup.sh命令之后,訪問項目遲遲加載不出來,查看日志又沒報錯(其實是我粗心了,當時tomcat日志還沒打印完),一開始懷疑是阿里雲主機出現問題,訪問ip:80發現nginx運行正常。在我百思不得其解時,項目訪問正常了,查看啟動日志,發現如下:

15-Mar-2018 16:41:02.302 WARNING [main] org.apache.catalina.util.SessionIdGeneratorBase.createSecureRandom Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [236,325] milliseconds.

可以看出實例化SecureRandom花了接近4分鍾!

二、調查

網上搜索到的信息如下:

**********************************************************************************************

Tomcat 7/8/9 都使用 org.apache.catalina.util.SessionIdGeneratorBase.createSecureRandom 類產生安全隨機類 SecureRandom 的實例作為會話 ID。

Tomcat 使用 SHA1PRNG 算法是基於 SHA-1 算法實現且保密性較強的偽隨機數生成器。

在 SHA1PRNG 中,有一個種子產生器,它根據配置執行各種操作。

Linux 中的隨機數可以從兩個特殊的文件中產生,一個是 /dev/urandom,另外一個是 /dev/random。他們產生隨機數的原理是利用當前系統的熵池來計算出固定一定數量的隨機比特,然后將這些比特作為字節流返回。熵池就是當前系統的環境噪音,熵指的是一個系統的混亂程度,系統噪音可以通過很多參數來評估,如內存的使用,文件的使用量,不同類型的進程數量等等。如果當前環境噪音變化的不是很劇烈或者當前環境噪音很小,比如剛開機的時候,而當前需要大量的隨機比特,這時產生的隨機數的隨機效果就不是很好了。

這就是為什么會有 /dev/urandom 和 /dev/random 這兩種不同的文件,后者在不能產生新的隨機數時會阻塞程序,而前者不會(ublock),當然產生的隨機數效果就不太好了,這對加密解密這樣的應用來說就不是一種很好的選擇。/dev/random 會阻塞當前的程序,直到根據熵池產生新的隨機字節之后才返回,所以使用 /dev/random 比使用 /dev/urandom 產生大量隨機數的速度要慢。

SecureRandom generateSeed  使用 /dev/random 生成種子。但是 /dev/random 是一個阻塞數字生成器,如果它沒有足夠的隨機數據提供,它就一直等,這迫使 JVM 等待。鍵盤和鼠標輸入以及磁盤活動可以產生所需的隨機性或熵。但在一個服務器缺乏這樣的活動,可能會出現問題。

**********************************************************************************************

說得很清楚,就是隨機數生成問題。上述觀點在jdk中SecureRandom類的注釋得到了印證:

 * Note: Depending on the implementation, the {@code generateSeed} and
 * {@code nextBytes} methods may block as entropy is being gathered,
 * for example, if they need to read from /dev/random on various Unix-like
 * operating systems.

三、解決

方案有3個

方案1:通過rng-tools自動補充熵池(推薦)

yum install rng-tools      #安裝rngd熵服務

systemctl start rngd       #啟動服務
cp /usr/lib/systemd/system/rngd.service /etc/systemd/system cd /etc/systemd/system/

vim rngd.service
ExecStart=/sbin/rngd -f 改為 ExecStart=/sbin/rngd -f -r /dev/urandom
systemctl daemon-reload   #重新載入服務 

systemctl restart rngd #重啟服務

重啟tomcat,查看日志,啟動時間1271 ms

15-Mar-2018 17:28:24.092 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in 1271 ms

方案2:修改jvm參數

通過修改JRE中的java.security文件securerandom.source=file:/dev/urandom

重啟tomcat,查看日志,啟動時間1271 ms

15-Mar-2018 17:22:27.363 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in 84777 ms

可見啟動速度比原來快了一半多,但還是不理想

方案3:修改tomcat參數

通過修改Tomcat啟動文件-Djava.security.egd=file:/dev/urandom(沒嘗試過)

四、小插曲

總算解決,但是這個問題之前沒有的啊,為什么呢?

回想一下,這是我修改代碼之后才出現的。所以我將一個繼承自HttpServlet的類中

private static final long serialVersionUID = 1L;

改為

private static final long serialVersionUID = -9135576688701595777L;

重啟tomcat,查看日志

15-Mar-2018 16:07:02.781 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in 1267 ms

 tomcat恢復了往日的神速!可是serialVersionUID這個對象的序列化值為什么會影響導致這個問題呢,在一篇《弄懂serialVersionUID》文獻中說到

使用默認序列號jvm會使用自身的算法(算法介紹),其中涉及到了SHA1,就我的理解用到了熵值算法,熵池不夠所以實例化慢,實證的話要再去看jvm規范,能力有限,以后再爬坑。

以上!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM