1. 程式人生 > >tomcat啟動異常緩慢

tomcat啟動異常緩慢

引言

最近弄了個伺服器再部署了個javaweb專案,但是再啟動時候 發現Tomcat啟動非常非常的慢,導致再部署完成以後 覺得專案像 沒有起來一樣, 這就很鬱悶了,因為每次不熟需要等10多分鐘,這是不能 忍受的,在檢視通Tomcat啟動日誌的時候發現:

org.apache.catalina.util.SessionIdGeneratorBase.createSecureRandom Creation of 
SecureRandom instance for session ID generation using [SHA1PRNG] took [253,251] milliseconds.

,通過檢視日誌,發現時間主要花在例項化 SecureRandom 物件上了。

原理解釋

根本原因是 SecureRandom 這個 jre 的工具類的問題。那為什麼 SecureRandom generateSeed 這麼慢,甚至掛在 Linux 作業系統呢?

Tomcat 7/8 都使用 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 等待。鍵盤和滑鼠輸入以及磁碟活動可以產生所需的隨機性或熵。但在一個伺服器缺乏這樣的活動,可能會出現問題。

有2種解決方案:

1. 在Tomcat環境中解決:

可以通過配置 JRE 使用非阻塞的 Entropy Source:

在 catalina.sh 中加入這麼一行:-Djava.security.egd=file:/dev/./urandom 即可。

2. 在 JVM 環境中解決:

開啟 $JAVA_PATH/jre/lib/security/java.security 這個檔案117行的位置,找到下面的內容:

securerandom.source=file:/dev/random

替換成:

securerandom.source=file:/dev/./urandom

這裡值為何要在 dev 和 random 之間加一個點呢?是因為一個 JDK 的 bug,有人反饋即使對 securerandom.source 設定為 /dev/urandom 它也仍然使用的 /dev/random,有人提供了變通的解決方法,其中一個變通的做法是對 securerandom.source 設定為 /dev/./urandom 才行。也有人評論說這個不是 bug,是有意為之。這種方法親測可用!

在 JDK 7 的 java.security 檔案裡,配置裡的是:

# attempt is made to use the entropy gathering device specified by
# the securerandom.source property. If an exception occurs when
# accessing the URL then the traditional system/thread activity
# algorithm is used.
#
# On Solaris and Linux systems, if file:/dev/urandom is specified and it
# exists, a special SecureRandom implementation is activated by default.
# This "NativePRNG" reads random bytes directly from /dev/urandom.
#
# On Windows systems, the URLs file:/dev/random and file:/dev/urandom
# enables use of the Microsoft CryptoAPI seed functionality.
#
securerandom.source=file:/dev/urandom

但這個 /dev/urandom 也同那個 bug 報告裡所說的等同於 /dev/random;要使用非阻塞的熵池,這裡還是要修改為 /dev/./urandom。經測試,貌似 JDK 7 並沒有同註釋裡的意思修復了這個問題。