SecureRandom使用不当引起的线程阻塞

问题起因

一个对外提供的接口,中间需要调用第三方接口,涉及到三方机密问题,其中使用到了安全随机数
之前的写法如下

public static String randomCode() {
    Random r = new Random();
    StringBuilder str = new StringBuilder();
    for (int i=0;i<6;i++){
        str.append((r.nextInt(10)));
    }
    return str.toString();
}

被solar扫面到不符合规范于是就改成下面的:

public class CodeUtil {

    private CodeUtil() {}

    // SecureRandom is preferred to Random
    private static Random rand;

    static {
        try {
            rand = SecureRandom.getInstanceStrong();
        } catch (NoSuchAlgorithmException e) {
            log.error("NoSuchAlgorithmException: {}", e);
        }
    }

    public static String randomCode() {
        StringBuilder str = new StringBuilder();
        for (int i=0;i<6;i++){
            str.append((rand.nextInt(10)));
        }
        return str.toString();
    }
}

bug现象

之前所有调用对外暴漏的服务的时候都是正常的,第二天莫名其妙的报错

 

 

 根据这个报错很自然就是想到服务调用超时,于是各种设置feign调用超时时间,但是都没有起到效果,本地测试服务调用时间,发现时间开销也并不是很高,总是感觉客户端链接一到服务端就断开了,于是估计因该是服务端的问题,但是本地调用也没有问题,甚至在服务中sleep了30s,依然没有显示超时,排查了一个下午,也没有搞明白到底是什么错误

曙光
当时也不知道是什么力量让我在服务器上打出了一个top命令,发现了一个叫java的进程,pid为1,于是就jstack了一下,惊喜的返现下面这些懂

 

 仔细观察了一下发现所有的http线程都阻塞在了同一把锁上面,这个时候问题基本已经定位到了
于是还原了一下源代码,问题成功解决。

SecureRandom.getInstanceStrong(); 是jdk1.8里新增的加强版随机数实现

如果你的服务器在Linux操作系统上,这里的罪魁祸首是SecureRandom generateSeed()。它使用/dev/random生成种子。但是/dev/random是一个阻塞数字生成器,如果它没有足够的随机数据提供,它就一直等,这迫使JVM等待。键盘和鼠标输入以及磁盘活动可以产生所需的随机性或熵。但在一个服务器缺乏这样的活动,可能会出现问题

有2种解决方案:

1. 在Tomcat环境中解决:

可以通过配置 JRE 使用非阻塞的 Entropy Source:
在 catalina.sh 中加入这么一行:-Djava.security.egd=file:/dev/./urandom 即可。
 

2. 在 JVM 环境中解决(本人使用此方法):

打开jdk安装路径 $JAVA_PATH/jre/lib/security/java.security 这个文件,找到下面的内容:
securerandom.source=file:/dev/random
替换成:
securerandom.source=file:/dev/./urandom
 

问题完美解决

这里值为何要在 dev 和 random 之间加一个点呢?是因为一个 JDK 的 bug,有人反馈即使对 securerandom.source 设置为
/dev/urandom 它也仍然使用的 /dev/random,有人提供了变通的解决方法,其中一个变通的做法是对 securerandom.source
设置为 /dev/./urandom 才行。也有人评论说这个不是 bug,是有意为之。


————————————————
版权声明:本文为CSDN博主「你们都是坏孩子00」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/wmq930626/java/article/details/105951216

原文地址:https://www.cnblogs.com/it-deepinmind/p/13344553.html