Tomcat 生成 Session 堵塞引發的思考

事故現象:

    public void handle(HttpServletRequest request, HttpServletResponse response) {
        //運行到此處的時候會阻塞,然後查看日誌就爆出瞭如下日誌  Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [14,387] milliseconds.
        if (request.getSession().getAttribute(WebConstants.SESSION.SESSION_USER_INFO) != null) {
            //...
        }
        //...
    }

 

原因是  getSession() 時候 需要生成 SessionId,在生成Id的時候需要生成隨機數,此時由於採用生成隨機數的策略(file:/dev/random)是堵塞的,所以會堵塞很久,解決方案是採用非堵塞(file:/dev/urandom)方式生成隨機數。

 

好了,現在就出現了網上大多數的解決方式,啓動參數添加如下參數,具體的原因可參考最下面幾個連接

-Djava.security.egd=file:/dev/./urandom

 

但是,重點來了,如果你的JDK版本是 JDK8,其實啓動參數添加以下即可,上下的區別在於多了一個 “./”(PS:其實在JDK8中 添加了 “./” 也能避免堵塞,但是是以另一種方式避免的,這個在文章最後會提到)

-Djava.security.egd=file:/dev/urandom

 

爲何在JDK8 中 不需要添加 “./” ?

請看  SeedGenerator.java 代碼,只要你設置了  java.security.egd ,那麼就會使用你所指定的生成器,而 JDK7 則不同,請繼續往下看

 

JDK7的代碼如下

如果 java.security.egd 參數指定的是 file:/dev/random 或者 file:/dev/urandom,則調用了無參的NativeSeedGenerator構造函數,而無參的構造函數將默認使用 file:/dev/random ,所以在JDK7中如果想要使用 file:/dev/urandom  就必須繞開第一個 if 判斷,而使用 file:/dev/./urandom ,這樣子才能使用你自定義的生成器

 

那麼,問題又來了,爲什麼在JDK8中使用 -Djava.security.egd=file:/dev/./urandom 也能解決堵塞的問題呢?

 

 所以,雖然 JDK8 使用 -Djava.security.egd=file:/dev/./urandom 也能達到相同的效果,但是它並不是使用我們給它解決方案來解決問題的

 

附錄:

以下是 getSession()  生成隨機數的關鍵斷點處,有興趣的話,可以動手斷點運行一下

 

 

 

 

 

 

 

 

 

參考:

https://blog.csdn.net/u011687186/article/details/73224733

http://hongjiang.info/jvm-random-and-entropy-source/

http://hongjiang.info/java8-nativeprng-blocking/

https://blog.51cto.com/leo01/1795447

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章