• 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

  • 相关阅读:
    更博不能忘——webpack学习笔记
    面试中遇到过的闭包~
    github踩坑之git命令收集与整理(windows)
    应该写个博客
    重学C语言(一):熟悉汇编语言
    关于Swift的闭包(closure)以及其在可选(Optional)类型中的应用
    解决Xcode 7出现cdtool cannot compile的问题(2015年8月12日更新)
    更改LaTeX的数学模式中使用的字体
    在Mac下安装使用支持中文的LaTeX(二)
    在Mac下安装使用支持中文的LaTeX(一)
  • 原文地址:https://www.cnblogs.com/it-deepinmind/p/13344553.html
Copyright © 2020-2023  润新知