問題描述
線上環境中很容易出現一個java應用啟動非常耗時的情況,在日誌中可以發現是session引起的隨機數問題導致的
o.a.c.util.SessionIdGeneratorBase : Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [170,241] milliseconds.
分析
在Springboot程式中有內建的tomcat,在tomcat給的優化文件中,有一項是關於隨機數生成時,採用的“熵源”(entropy source)的策略。
他提到tomcat7的session id的生成主要通過java.security.SecureRandom生成隨機數來實現,隨機數演算法使用的是”SHA1PRNG”
private String secureRandomAlgorithm = "SHA1PRNG";
在sun/oracle的jdk裡,這個演算法的提供者在底層依賴到作業系統提供的隨機資料,在linux上,與之相關的是/dev/random和/dev/urandom。區別為:
/dev/random是阻塞的發生器
在讀取時,/dev/random裝置會返回小於熵池噪聲總數的隨機位元組。/dev/random可生成高隨機性的公鑰或一次性密碼本。若熵池空了,對/dev/random的讀操作將會被阻塞,直到收集到了足夠的環境噪聲為止
而 /dev/urandom 則是一個非阻塞的發生器:
dev/random的一個副本是/dev/urandom (”unlocked”,非阻塞的隨機數發生器),它會重複使用熵池中的資料以產生偽隨機資料。這表示對/dev/urandom的讀取操作不會產生阻塞,但其輸出的熵可能小於/dev/random的。它可以作為生成較低強度密碼的偽隨機數生成器,不建議用於生成高強度長期密碼。
這也並不是說明/dev/urandom不是做高強度的偽隨機數生成器,這個討論可以看這個討論:/dev/urandom 不得不說的故事
解決方法
方法一
在 jre/lib/security/java.security
這個檔案裡面把
securerandom.source=file:/dev/random
改為
securerandom.source=file:/dev/./urandom
方法二
在啟動引數中新增以下系統屬性
-Djava.security.egd=file:/dev/./urandom
這個系統屬性egd表示熵收集守護程式(entropy gathering daemon),但這裡值為何要在dev和random之間加一個點呢?是因為一個jdk的bug,在這個bug的連線裡有人反饋及時對 securerandom.source 設定為 /dev/urandom 它也仍然使用的 /dev/random,有人提供了變通的解決方法,其中一個變通的做法是對securerandom.source設定為 /dev/./urandom 才行
多說一嘴
在Docker中如何新增系統引數呢
首先在build映象時 要使用ENTRYPOINT
舉個例子
FROM jdk:alpine-security8
WORKDIR /
#解決中文亂碼問題
ENV LANG en_US.UTF-8
ENV LANGUAGE en_US:en
ENV LC_ALL en_US.UTF-8
ADD sms-server.jar sms-server.jar
ADD application.properties application.properties
ADD bootstrap.properties bootstrap.properties
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
##使用如下的命令 新增-e JAVA_OPT是不起作用的
#ENTRYPOINT ["java","-jar","sms-server.jar"]
##要使用這條命令才行
ENTRYPOINT java ${JAVA_OPTS} -jar sms-server.jar
然後在啟動命令中新增對應的-e引數就可以了 舉個例子
docker run --name sms-server-security \
## 如下即可
-e JAVA_OPTS='-Djava.security.egd=file:/dev/./urandom' \
-e spring.cloud.nacos.discovery.server-addr=192.169.1.82:8848 \
-e spring.cloud.nacos.config.server-addr=192.169.1.82:8848 \
-e spring.cloud.nacos.config.ext-config[0].data-id=sms-server-node1.properties \
-p 8070:8090 \
-v /opt/sms_server/log:/log \
-v /opt/sms_server/nacos:/root/nacos \
-d \
3a1c93c34756