Bug 记录:SecureRandom.getInstanceStrong()导致验证码获取阻塞

问题描述:

在发送验证码到邮件中,接口调用时卡在生成验证码阶段,导致验证码功能完全不可用;

经排查开发环境一切正常,测试环境会重现此问题;


问题分析:

现象:

  • 代码卡在 SecureRandom.getInstanceStrong().nextInt() 无法继续执行

原因:

  • SecureRandom.getInstanceStrong() 方法在 Linux 下默认使用/dev/random来生成随机数,而这个文件的数据来源于系统的扰动。当系统产生扰动很少的时候,就会导致读取这个文件的线程阻塞;
  • /dev/random:阻塞型设备,当熵不足时会阻塞程序;
  • /dev/urandom:非阻塞型设备,熵不足时使用伪随机算法;

熵池不足是什么意思?

  • 熵池不足"是指系统中可用于生成随机数的随机性资源不足。当熵池中的熵值低于某个阈值时,系统无法提供足够的随机性;

查询服务器熵值:

java 复制代码
cat /proc/sys/kernel/random/entropy_avail 

正常应该1000以上

解决方案:

方案一:使用使new SecureRandom()

new SecureRandom() 默认使用非阻塞源,在 Linux 环境下,Java 默认使用 /dev/urandom 作为熵源(永不阻塞,即使熵不足时使用伪随机算法补充)

方案二:使用ThreadLocalRandom来生成验证码

java 复制代码
public class CaptchaNumCreator extends DefaultTextCreator {
    @Override
    public String getText() {
        // 确保使用高效的随机数生成方式
        return ThreadLocalRandom.current()
                .ints(6, 0, 10)  // 生成6位数字
                .collect(StringBuilder::new, StringBuilder::append, StringBuilder::append)
                .toString();
    }
}

方案三:在 JVM 启动参数中添加

java 复制代码
-Djava.security.egd=file:/dev/./urandom

注意:这里使用 /dev/./urandom 而非 /dev/urandom 是为了绕过 JDK 的一个历史 Bug

相关推荐
aiks_yuan4 小时前
Spring Boot SSE 流式输出变成一次性返回怎么办:大模型打字机效果失效的 5 个原因(Spring Boot 4.1.2 实测)
spring boot
Flynn Liang6 小时前
上线后怎么排查 AI 调用?Spring AI Observability:token/延迟/成本埋点与全链路追踪
java·人工智能·spring·监控·可观测性·observability·springai
Thomas.Sir6 小时前
第15课:SpringBoot连接池详解:HikariCP配置、调优、监控,4.x连接池新特性
java·spring boot
VimorphTech7 小时前
每批开 4 个线程,为什么限制不住 TTS 的总并发?
java·spring boot·spring
杨凯凡7 小时前
Spring Boot 缓存一致性怎么保证?@Cacheable、@CacheEvict 与事务提交时机实战
java·spring boot·spring cache·后端开发·缓存一致性
软件技术NINI9 小时前
基于SpringBoot和Vue的项目评审系统
javascript·vue.js·spring boot·后端·spring·毕业设计·毕设
vipxieliang9 小时前
Spring Boot 性能优化实战:从启动加速到运行时调优
java·spring boot
AI全栈学习助手9 小时前
告别“转圈等待”:Spring Boot + SSE 让大模型像 ChatGPT 一样流式输出
java·人工智能·spring boot·后端·aigc
代码不停9 小时前
Spring Aop
java·数据库·spring
云-缩影18 小时前
拆解 AI 图像生成应用的后端架构:ECS、OSS 和大模型 API 怎么配合
java·spring boot·后端