[英]Hash generation using java digest gets slower in time
在使用wildfly 8.2和Java 1.7的生产环境中,我有一个真正好奇的情况。
情况是,当服务器启动超过2周时,登录开始降低性能。 我一直在寻找可能表明问题所在的线索。 然后在做了一些测试之后,我得出结论,问题是当以纯文本插入的密码被加密以与已经插入的密码进行比较时。
当执行加密密码的功能时,大约需要2分钟,但是当服务器重新启动时,相同的执行时间不到30秒。
加密使用java.security.MessageDigest来生成哈希。 特别是使用SHA-256和50000次迭代。 知道为什么这个过程会随着时间变慢吗? 我正在使用/ dev / urandom来生成随机因此不应该是问题。
这是功能代码:
protected byte[] hash(byte[] bytes, byte[] salt, int hashIterations) throws UnknownAlgorithmException {
MessageDigest digest = getDigest(getAlgorithmName());
if (salt != null) {
digest.reset();
digest.update(salt);
}
byte[] hashed = digest.digest(bytes);
int iterations = hashIterations - 1; //already hashed once above
//iterate remaining number:
for (int i = 0; i < iterations; i++) {
digest.reset();
hashed = digest.digest(hashed);
}
return hashed;
}
经过一天的研究,我终于找到了问题的答案。 我想在这里分享它,以防它对其他人有用。
问题是由于代码缓存而导致的。 我专注于堆内存,我没有看到任何问题,但是当我检查非堆内存时,我发现就像登录过程开始减慢一样,代码缓存上有一半以上的下降使用的记忆。
调查这个内存,我发现当这个空间有大量丢弃时,可能会发生JIT编译器停止工作。 总而言之,这就是发生的事情,并且关闭JIT编译器导致我的加密循环的每次迭代都必须在每次执行时被解释,这在逻辑上使得进程慢得多。
在这里,我留下一些我认为对本主题有帮助的链接。
[2] - https://www.atlassian.com/blog/archives/codecache-is-full-compiler-has-been-disabled
感谢那些花时间回答它的人
摆脱语句: int iterations = hashIterations - 1;
并只使用hashIterations
。
在最好的情况下,它将迭代从50000(在所述情况下)减少到49999,并且在最坏的情况下导致整数下溢并且将迭代增加到int
的最大值。
当hashIterations
为零时,至少要防止减1
。
还可以通过记录iterations
的值来考虑用于调试的检测。
为什么有人会关闭这个? 也许是因为没有什么可能导致问题。
虽然digest.digest
通常是耗时的部分,但它是一个纯粹的计算,没有什么可以减慢它的速度。 剩下的就是getAlgorithmName()
和getDigest(String)
。 前者可能是一个微不足道的getter,但后者可能使用MessageDigest.getInstance
来定位摘要。 只是猜测:有一个查找所有安全提供程序及其提供的所有内容,有人可能会以某种方式延长此列表。
您甚至可以在生产中对此库方法进行基准测试 :只需将该方法复制到新的源文件中,然后添加一些日志记录和一些定期调用它的代码(如果您愿意,还可以手动调用)。 当发生减速时,你会有一些东西需要比较,你会在日志中找到一些详细的时间。
当所有可以想象的原因都用尽时,尝试不可想象的原因,例如不同的iterations
(你认为这是一个常数),等等。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.