使用 SecureRandom 产生随机数采坑记录
公众号「码海」欢迎关注
背景
我们的项目工程里经常在每个函数需要用到 Random 的地方定义一下 Random 变量(如下)
public void doSomethingCommon() {
  Random rand = new Random();
  ...
}
在用 sonar 进行检查时,会发现会有如下告警
Creating a new Random object each time a random value is needed is inefficient and may produce numbers which are not random depending on the JDK. For better efficiency and randomness, create a single Random, then store, and reuse it.
简单地说就是在每个函数都创建一个 Random 效率太低了,而且由于 JDK 版本的不同,可能 Random 产生的随机数不够随机。为了提升性能和随机性,建议定义一个 Random 单例来统一产生随机数, Sonar 建议使用 SecureRandom.getInstanceStrong() 来初始化,如下
private Random rand = SecureRandom.getInstanceStrong();
于是我们就将其改成 sonar 建议的形式来生成随机数
问题初现
结果问题来了,下午在我们业务的接口上,第三方反馈接口调用超时,从我们的监控来看,接口执行阻塞,看起来像陷入了某种死循环。

定位问题
复现问题:首先使用了相同的请求参数在预发进行了测试,但令人不解的是,问题无法复现。随后又测试了线上机器,可以稳定的复现问题。这时一脸黑人问号。
打日志:为了定位问题,在代码的关键位置插入日志,经过多次的发布定位到问题,执行到 SecureRandom.getInstanceStrong() 方法后就阻塞了。
原因剖析
SecureRandom.getInstanceStrong() 方法在 linux 环境下使用 /dev/random 生成种子。但是 /dev/random 是一个阻塞数字生成器,如果它没有足够的随机数据提供,它就一直等,这迫使 JVM 等待。键盘和鼠标输入以及磁盘活动可以产生所需的随机性或熵。但在一个缺乏这样的活动服务器,可能会出现问题,当系统的熵池中数量不足时,就会阻塞当前线程。
那么 Linux 中随机数是如何产生的呢 PRNG(Pseudo-Random Number Generator),以下解释摘自 IBM 的文章
Linux 内核采用熵来描述数据的随机性,熵(entropy)是描述系统混乱无序程度的物理量,一个系统的熵越大则说明该系统的有序性越差,即不确定性越大。内核维护了一个熵池用来收集来自设备驱动程序和其它来源的环境噪音。理论上,熵池中的数据是完全随机的,可以实现产生真随机数序列。为跟踪熵池中数据的随机性,内核在将数据加入池的时候将估算数据的随机性,这个过程称作熵估算。熵估算值描述池中包含的随机数位数,其值越大表示池中数据的随机性越好。 内核中随机数发生器 PRNG 为一个字符设备 random,代码实现在 drivers/char/random.c,该设备实现了一系列接口函数用于获取系统环境的噪声数据,并加入熵池。系统环境的噪声数据包括设备两次中断间的间隔,输入设备的操作时间间隔,连续磁盘操作的时间间隔等。 对应的接口包括
void add_device_randomness(const void *buf, unsigned int size);
void add_input_randomness(unsigned int type, unsigned int code,
				unsigned int value);
void add_interrupt_randomness(int irq, int irq_flags);
void add_disk_randomness(struct gendisk *disk);
内核提供了 1 个的接口来供其他内核模块使用。
该接口会返回指定字节数的随机数。random 设备了提供了 2 个字符设备供用户态进程使用——/dev/random 和/dev/urandom:
- /dev/random 适用于对随机数质量要求比较高的请求,在熵池中数据不足时, 读取 dev/random 设备时会返回小于熵池噪声总数的随机字节。/dev/random 可生成高随机性的公钥或一次性密码本。若熵池空了,对/dev/random 的读操作将会被阻塞,直到收集到了足够的环境噪声为止。这样的设计使得/dev/random 是真正的随机数发生器,提供了最大可能的随机数据熵。
- /dev/urandom,非阻塞的随机数发生器,它会重复使用熵池中的数据以产生伪随机数据。这表示对/dev/urandom 的读取操作不会产生阻塞,但其输出的熵可能小于/dev/random 的。它可以作为生成较低强度密码的伪随机数生成器,对大多数应用来说,随机性是可以接受的。
解决方案
有了以上的的解释,我们就知道解决方案了,使用 /dev/urandom 这种非阻塞的方式来产生随机数即可,在 Java 中我们这样写即可
SecureRandom random = new SecureRandom();
new SecureRandom() 使用 /dev/urandom 生成种子,不会产生阻塞。
参考文章
使用 SecureRandom 产生随机数采坑记录的更多相关文章
- Charles 抓包工具安装和采坑记录
		Charles 抓包工具安装和采坑记录 网络抓包是解决网络问题的第一步,也是网络分析的基础.网络出现问题,第一步肯定是通过抓包工具进行路径分析,看哪一步出现异常.做网络爬虫,第一步就是通过抓包工具对目 ... 
- Antd前端开发采坑记录
		背景 基于页面友好,界面整洁美观:基于Antd框架开发虾能平台 选型 基于Antd-admin工程架构,进行开发:基于Antd+React+Umj 采坑记录 按照Html方式天机onClick方法,每 ... 
- HUE Oozie : error=2, No such file or directory采坑记录
		HUE Oozie : error=2, No such file or directory采坑记录 1.错误详情 一直都是同一种方式在hue上定义workflow,不知为啥 今天定义的就是不行... ... 
- uni-app采坑记录
		1. uni-app采坑记录 1.1. 前言 这里记录下uni-app实践中踩的坑 1.2. 坑点 1.2.1. 触发事件@longTap和@longpress 这两个都表示长按触发事件,那么这两个有 ... 
- angular采坑记录
		在angular中会遇到一些莫名的问题,导致不能完成想要的功能,可能是某项用法使用错误,或许是angular相对应不支持,或者是我们功力根本就没有达到.为了在每次采坑之后能有所收获,再遇到时能理解其根 ... 
- v8环境搭建采坑记录
		项目组有把js接入C++服务求的需求,故开始了v8接入的工作,用了一天多时间,v8才在centos环境上成功安装,过程中踩了很多坑,下面将采坑过程记录如下: centos下编译安装v8: 查看ce ... 
- Win7 node多版本管理gnvm采坑记录
		采坑描述:下载新node版本及切换node失败 解决:1.要用管理员权限启动cmd:2.确保node是空闲的 Gnvm下载地址: 32-bit | 64-bit Github 1.下载之后为 得到一个 ... 
- Android Studio采坑记录
		折腾了几个月的Android Studio,终于在今天被我搞定了 ( ̄▽ ̄)~* 开贴记录下,免得下次再次采坑 先说下我之前电脑的环境配置吧,sdk是几年前在网上下载别人整理出来的包,一直没有更新过 ... 
- golang采坑记录
		安装golang,引入第三方库,采坑 1.获取安装包 go语言中文网:https://studygolang.com/dl 官网地址:https://studygolang.com/dl 2.下载 选 ... 
随机推荐
- CSPS模拟 49
			连续退步2333 我怎么这么不稳啊2333 看看人家大敛,天天AK 考后改了改sb错误就变40+80+100了... 但愿我的实力还在? T1 养fa 拿到题心想,这次一定把T1切了 开始研究这个见了 ... 
- CSPS模拟 44
			状态不是很好吧 这套和前边是一套的, skyh在我旁边AK,好像开了三个对拍又在拼小人 T3 正解没调出来,暴力又忘交了qwq 当时心情都要爆炸了 T1 区间$gcd$乘区间长度的最大值 暴力是$n^ ... 
- 使用Typescript重构axios(三)——实现基础功能:处理get请求url参数
			0. 系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三) ... 
- tarjan学习(复习)笔记(持续更新)(各类找环模板)
			题目背景 缩点+DP 题目描述 给定一个n个点m条边有向图,每个点有一个权值,求一条路径,使路径经过的点权值之和最大.你只需要求出这个权值和. 允许多次经过一条边或者一个点,但是,重复经过的点,权值只 ... 
- 解决 scp 和rsync 同步失败【rsync error: unexplained error (code 255) at io.c(226) [sender=3.1.2]】
			解决 scp 和rsync 同步失败 报错信息截图: 解决问题的步骤: 1.检查对方的scp和rsync 是否能使用. rsync 在使用的时候,需要客户端和服务端都有rsync工具.scp 和 rs ... 
- SqlServer2005 查询 第一讲 计算列
			数据库查询[最重要且在数据库中难度最大] 声明一下我这里用的数据库样例是郝斌老师的(scott库) 我尽最大努力把复杂的问题简单化,方便理解,希望我写的东西能够帮助到你们 有些复杂的东西我我用自己的方 ... 
- VMware安装Ubuntu 16.04.4 LTS
			1.下载Ubuntu镜像 https://www.ubuntu.com/download/desktop 2.创建新的虚拟机 3. 4.这里默认即可,可以不选 5. 6. 7.这里位置可以随时改 8. ... 
- linux下制作linux系统盘(光盘、U盘)
			cdrecord制作启动光盘 首先cdrecord -scanbus输出设备列表和标识,(我的此次为5,0,0) [ˈrekərd] 然后用cdrecord -v dev=5,0,0 -eject ... 
- libdispatch.dylib中dispatch_group的实现
			semaphore和group都是libdispatch提供的基于信号量的同步机制,dispatch_group继承自dispatch_semaphore,使用libdispatch层的信号量算法.d ... 
- Linux下安装和使用WPS,体验良好
			最近,我在ubuntu18.04.3下面使用LibreOffice,感觉良好. 正值政府机关在进行2019年度正版软件使用情况整改,保护知识产权,我表示热烈欢迎并强烈支持. 通过摸底,因为以前采购的w ... 
