服务响应时间慢:Java SecureRandom& / dev /随机 [英] Slow service response Times : Java SecureRandom & /dev/random
问题描述
我正在尝试调试Tomcat上部署的应用程序提供的一些慢速响应。
现在,我主要关注 SecureRandom
和 / dev / random
(其他一些可能的原因有已被调查并排除)。
模式如下:
I am trying to debug a few slow responses served by an app deployed on Tomcat.
Right now I am focussing on SecureRandom
and /dev/random
(some of the other probable causes have been investigated and ruled out).
The pattern is as follows:
- 在Tomcat重新启动后,第一次调用恰好在 30.0 xy秒内(即使请求在启动后4分钟到达)
- 稍后,某些呼叫恰好需要 15.0 pq秒(我无法建立具体的模式, pq 是大约在TP99中花费的时间)
- The first call takes exactly 30.0xy seconds after Tomcat restart (even if the request arrives 4 minutes after the Startup)
- Later, some calls take exactly 15.0pq seconds (there was no specific pattern that I could establish, pq being the time approximate time taken in TP99)
服务调用涉及加密和解密( AES / ECB / PKCS5Padding )。
The service call involves encryption and decryption (AES/ECB/PKCS5Padding).
是否可能通过SecureRandom初始化/重新填充导致了此错误?
(尽管在catalina.log中写了一个日志,其中显示 使用[SHA1PRNG]创建用于生成会话ID的SecureRandom实例花费了[28,760]毫秒。 c
(Although, there is a log written in catalina.log that says "Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [28,760] milliseconds."
)
此外,为了检查 / dev / random
还是正在使用 / dev / urandom
,我从这个问题。令我惊讶的是,与链接问题中发生的情况不同,我没有看到它们中的任何一个。
这是 strace
日志的最后几行:
Also, in order to check whether /dev/random
or /dev/urandom
is being used, I used the test from this question. To my surprise, I didn't see reads from either of them unlike the way it happens in the linked question.
These are the last few lines from the strace
log:
3561 lstat("/usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0.x86_64/jre/lib/jsse.jar", {st_mode=S_IFREG|0644, st_size=258525, ...}) = 0
3561 open("/usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0.x86_64/jre/lib/jsse.jar", O_RDONLY) = 6
3561 stat("/dev/random", {st_mode=S_IFCHR|0666, st_rdev=makedev(1, 8), ...}) = 0
3561 stat("/dev/urandom", {st_mode=S_IFCHR|0666, st_rdev=makedev(1, 9), ...}) = 0
3561 open("/dev/random", O_RDONLY) = 7
3561 open("/dev/urandom", O_RDONLY) = 8
3561 unlink("/tmp/hsperfdata_xxxx/3560") = 0
然后使用什么作为SecureRandom的种子?
What is then being used for seeding SecureRandom?
fyi, java -version
java version "1.6.0_32"
OpenJDK Runtime Environment (IcedTea6 1.13.4) (rhel-7.1.13.4.el6_5-x86_64)
OpenJDK 64-Bit Server VM (build 23.25-b01, mixed mode)
推荐答案
我无法检查您的OpenJDK具体版本,但可以检查 jdk6-b33 。
I could not check your OpenJDK concrete version, but I could check jdk6-b33.
SecureRandom 使用 SeedGenerator 获取种子字节
public byte[] engineGenerateSeed(int numBytes) {
byte[] b = new byte[numBytes];
SeedGenerator.generateSeed(b);
return b;
}
SeedGenerator获取 seedSource
(字符串)来自 SunEntries
SeedGenerator gets the seedSource
(String) from SunEntries
String egdSource = SunEntries.getSeedSource();
SunEntries
试图从首先,找到系统属性 java.security.egd
,然后尝试从系统属性中获取属性 securerandom.source
。 java.security
属性文件,如果找不到该属性,则返回空白字符串。
SunEntries
tries to get the source from the system property java.security.egd
first, if is not found then tries to get the property securerandom.source
from the java.security
properties file, if the property is not found returns a blank string.
// name of the *System* property, takes precedence over PROP_RNDSOURCE
private final static String PROP_EGD = "java.security.egd";
// name of the *Security* property
private final static String PROP_RNDSOURCE = "securerandom.source";
final static String URL_DEV_RANDOM = "file:/dev/random";
final static String URL_DEV_URANDOM = "file:/dev/urandom";
private static final String seedSource;
static {
seedSource = AccessController.doPrivileged(
new PrivilegedAction<String>() {
public String run() {
String egdSource = System.getProperty(PROP_EGD, "");
if (egdSource.length() != 0) {
return egdSource;
}
egdSource = Security.getProperty(PROP_RNDSOURCE);
if (egdSource == null) {
return "";
}
return egdSource;
}
});
}
SeedGenerator
支票该值用于初始化实例
the SeedGenerator
check this value to initialize the instance
// Static instance is created at link time
private static SeedGenerator instance;
private static final Debug debug = Debug.getInstance("provider");
final static String URL_DEV_RANDOM = SunEntries.URL_DEV_RANDOM;
final static String URL_DEV_URANDOM = SunEntries.URL_DEV_URANDOM;
// Static initializer to hook in selected or best performing generator
static {
String egdSource = SunEntries.getSeedSource();
// Try the URL specifying the source
// e.g. file:/dev/random
//
// The URL file:/dev/random or file:/dev/urandom is used to indicate
// the SeedGenerator using OS support, if available.
// On Windows, the causes MS CryptoAPI to be used.
// On Solaris and Linux, this is the identical to using
// URLSeedGenerator to read from /dev/random
if (egdSource.equals(URL_DEV_RANDOM) || egdSource.equals(URL_DEV_URANDOM)) {
try {
instance = new NativeSeedGenerator();
if (debug != null) {
debug.println("Using operating system seed generator");
}
} catch (IOException e) {
if (debug != null) {
debug.println("Failed to use operating system seed "
+ "generator: " + e.toString());
}
}
} else if (egdSource.length() != 0) {
try {
instance = new URLSeedGenerator(egdSource);
if (debug != null) {
debug.println("Using URL seed generator reading from "
+ egdSource);
}
} catch (IOException e) {
if (debug != null)
debug.println("Failed to create seed generator with "
+ egdSource + ": " + e.toString());
}
}
// Fall back to ThreadedSeedGenerator
if (instance == null) {
if (debug != null) {
debug.println("Using default threaded seed generator");
}
instance = new ThreadedSeedGenerator();
}
}
如果来源是
final static String URL_DEV_RANDOM = "file:/dev/random";
或
final static String URL_DEV_URANDOM = "file:/dev/urandom"
使用<$ Windows上的c $ c> NativeSeedGenerator 尝试在Linux上使用本机 CryptoAPI
,该类只是扩展了 SeedGenerator.URLSeedGenerator
uses the NativeSeedGenerator
, on Windows tries to use the native CryptoAPI
on Linux the class simply extends the SeedGenerator.URLSeedGenerator
package sun.security.provider;
import java.io.IOException;
/**
* Native seed generator for Unix systems. Inherit everything from
* URLSeedGenerator.
*
*/
class NativeSeedGenerator extends SeedGenerator.URLSeedGenerator {
NativeSeedGenerator() throws IOException {
super();
}
}
并调用超类构造函数默认情况下加载 / dev / random
and call to the superclass constructor who loads /dev/random
by default
URLSeedGenerator() throws IOException {
this(SeedGenerator.URL_DEV_RANDOM);
}
因此,OpenJDK使用 / dev / random 默认情况下为code>,直到您未在系统属性
java.security.egd
或属性 securerandom.source
安全属性文件。
so, OpenJDK uses /dev/random
by default until you do not set another value in the system property java.security.egd
or in the property securerandom.source
of security properties file.
如果要使用 strace
查看读取结果,则可以更改命令行并添加 trace = open,read
表达式
If you want to see the read results using strace
you can change the command line and add the trace=open,read
expression
sudo strace -o a.strace -f -e trace=open,read java class
可以看到这样的内容(我使用Oracle JDK 6进行了测试)
the you can see something like this (I did the test with Oracle JDK 6)
13225 open("/dev/random", O_RDONLY) = 8
13225 read(8, "@", 1) = 1
13225 read(3, "PK\3\4\n\0\0\0\0\0RyzB\36\320\267\325u\4\0\0u\4\0\0 \0\0\0", 30) = 30
....
....
Tomcat Wiki部分启动速度更快,建议使用非阻塞熵源,例如/ dev / u如果您在启动过程中遇到延迟,则为随机
The Tomcat Wiki section for faster startup suggest using a non-blocking entropy source like /dev/urandom if you are experiencing delays during startup
更多信息: https://wiki.apache.org/tomcat/HowTo/FasterStartUp#Entropy_Source
希望这会有所帮助。
这篇关于服务响应时间慢:Java SecureRandom& / dev /随机的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!