SpringBoot項目中SecureRandom導致的Controller訪問非常慢的問題


引子

使用springboot開發一個部署在阿里雲上的項目的時候,用controller+freemarker實現了一個偽js,用於靜態頁面同步獲取服務器上下文、當前登錄用戶等信息使用,結果發現因為這個偽js導致頁面第一次加載十分緩慢。

跟蹤后發現不僅是該偽js,是對所有的controller的第一次訪問會非常的慢,之后的短時間內又會很正常,仔細跟蹤日志發現訪問慢的那一次請求中會出現類似如下這樣的一段或多段日志:

2017-10-17 14:12:03.971 [http-nio-8086-exec-2] INFO  o.a.c.u.SessionIdGeneratorBase.log<179>:
Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [61,115] milliseconds.

重點就在這個時間,重復測試發現這個時間甚至可以長至5~6分鍾,最短也要1分多鍾,

以“SecureRandom”等關鍵字求助搜索引擎,終於找到了巨慢的罪魁禍首。

原因:

StackOverflow上Dan Dyer的回答原文:

On Linux, the default implementation for SecureRandom is NativePRNG (source code here), which tends to be very slow. On Windows, the default is SHA1PRNG, which as others pointed out you can also use on Linux if you specify it explicitly.

NativePRNG differs from SHA1PRNG and Uncommons Maths' AESCounterRNG in that it continuously receives entropy from the operating system (by reading from /dev/urandom). The other PRNGs do not acquire any additional entropy after seeding.

AESCounterRNG is about 10x faster than SHA1PRNG, which IIRC is itself two or three times faster than NativePRNG.

If you need a faster PRNG that acquires entropy after initialization, see if you can find a Java implementation of Fortuna. The core PRNG of a Fortuna implementation is identical to that used by AESCounterRNG, but there is also a sophisticated system of entropy pooling and automatic reseeding.

大意如下:

linux默認的SecureRandom實現方式是非常慢的NativePRNG,而在Windows上的默認實現是SHA1PRNG,正如其他人所說,你也可以在Linux上指定使用該方式。

……NativePRNG會不斷從操作系統獲取熵(從/dev/urandom讀取),其它PRNG則不會獲取這些額外的熵。

AESCounterRNG差不多比SHA1PRNG快的十倍,而如果我沒記錯,SHA1PRNGNativePRNG快兩到三倍

結合其它資料,終於弄明白了,SecureRandom是java用來獲取高級隨機數的實現,++而巨慢則是由在linux上默認使用的實現方式導致的++。

解決:

Linux上Jre中默認SecureRandom讀取熵時會從/dev/urandom中讀取,而從這里讀取熵是阻塞的,下面是已知的兩種解決方式。

方法一,修改jre配置文件(該方式本人實測成功):

以linux用yum安裝的jre為例,打開/usr/lib/jvm/jre/lib/security/java.security

找到securerandom.source=file:/dev/random這一行,

file:/dev/random(阻塞熵源)修改為file:/dev/./urandom(非阻塞熵源)

方法二,為JVM增加如下啟動參數(該方式本人未親自測試):

-Djava.security.egd=file:/dev/./urandom
Thanks To: How to solve slow Java SecureRandom? - StackOverflow

另附本項目環境如下:

Linux version 3.10.0-514.26.2.el7.x86_64 (builder@kbuilder.dev.centos.org) (gcc version 4.8.5 20150623 (Red Hat 4.8.5-11) (GCC) ) #1 SMP Tue Jul 4 15:04:05 UTC 201

java-1.8.0-openjdk-1.8.0.141-1.b16.el7_3.x86_64  jre  jre-1.8.0  jre-1.8.0-openjdk  jre-1.8.0-openjdk-1.8.0.141-1.b16.el7_3.x86_64  jre-openjdk

springboot-1.5.4.RELEASE

據同事測試,同樣的jre、springboot在他的centos虛擬機上並未出現該問題,所以推測有可能是linux版本差異,或是安全策略配置問題,亦或是linux存在這么一個可以配置默認隨機數獲取算法的方式,有待深究。


免責聲明!

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



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