Springboot程式啟動慢及JVM上的隨機數與熵池策略

熟讀並背誦文件發表於2020-12-25

問題描述

線上環境中很容易出現一個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

參考

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

相關文章