要汇集还是不汇集java加密服务提供商
解
- MessageDigest =>根据需要经常创建新实例
- KeyFactory =>使用单个共享实例
- SecureRandom =>使用StackObjectPool
- Cipher =>使用StackObjectPool
题
在编写安全框架时,我面临着一个常规的困境:“汇集或不汇集”
基本上这个问题分为两个“群体”:
-
第1组:
SecureRandom
因为对nextBytes(...)
的调用是同步的,它可能成为WebApp /multithreading应用程序的瓶颈 -
第2组:加密服务提供商,如
MessageDigest
,Signature
,Cipher
,KeyFactory
,……(因为getInstance()
的成本?)
你有什么意见 ?
你在这些问题上的习惯是什么?
编辑09/07/2013
我终于抽出时间亲自测试@Qwerky Share
课程,我发现结果非常……令人惊讶。
这个类缺乏我的主要关注:像GenericObjectPool或StackObjectPool这样的池。
所以我重新修改了这个类以测试所有4种选择:
- 具有同步gist的单个共享实例
- 每个循环中的新实例(当你可以在循环外拉动摘要时,我对这种情况不感兴趣)
- GenericObjectPool: 要点
- StackObjectPool: 要点
我不得不将循环次数降低到100000,因为1M花费了太多时间来使用池。
我还在每个循环的末尾添加了一个Thread.yield()
,以便为负载提供更好的形状。
结果(累积运行时):
- 信息摘要
- 新实例:420秒
- 单个实例:550秒
- StackObjectPool:800秒
- GenericObjectPool:1900年代
- 的KeyFactory
- 新实例:400s
- 单个实例:350秒
- StackObjectPool:2900秒
- GenericObjectPool:3500秒
- 的SecureRandom
- StackObjectPool:1600秒
- 新实例:2300秒
- GenericObjectPool:2300s
- 单个实例:2800秒
- 暗号
- StackObjectPool:2800秒
- GenericObjectPool:3500秒
- 单个实例:5100秒
- 新实例:8000秒
结论
对于MessageDigest和KeyFactory,池是执行器杀手,甚至比具有同步瓶颈的单个实例更糟糕,而它们在SecureRandom和Cipher方面非常有用
如果您给100个线程访问共享的MessageDigest
并让它们计算1,000,000个哈希,那么在我的机器上第一个线程在70,160ms完成,最后一个在98,748ms完成。
如果线程每次都创建一个MessageDigest
的新实例,那么第一个线程将在43,492ms完成,最后一个58,691ms完成。
编辑:
事实上,在这个例子中,只有两个线程,创建新实例的示例运行得更快。
import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Share { final byte[] bytes = new byte[100]; final MessageDigest sharedDigest; final ExecutorService pool; int threads = 100; Share() throws NoSuchAlgorithmException { sharedDigest = MessageDigest.getInstance("MD5"); pool = Executors.newFixedThreadPool(threads); } void go() { for (int i=0; i
这个测试似乎有利于缓存
long t0 = System.currentTimeMillis(); byte[] bytes = new byte[100]; MessageDigest md = MessageDigest.getInstance("MD5"); for(int i = 0; i < 1000000; i++) { //MessageDigest md = MessageDigest.getInstance("MD5"); md.reset(); md.update(bytes); md.digest(); } System.out.println(System.currentTimeMillis() - t0);
当md在循环之外时,它打印579,当在内部 - 953。