写点什么

UUID 意想不到的 block

作者:FunTester
  • 2023-11-06
    河北
  • 本文字数:1762 字

    阅读完需:约 6 分钟

UUID(Universally Unique Identifier,通用唯一标识符)是一种用于标识信息的 128 位标识符。Java 开发人员倾向于使用 java.util.UUID#randomUUID API 来生成 UUID 编号(类似 4c88314f-14ca-4652-8567-4471a0ef917c)。


UUID 通常用于标识数据记录、会话、文件、对象等,以确保它们在不同上下文中的唯一性。注意,UUID 是一种全局唯一性标识符,不保证在不同时间生成的 UUID 之间是有序的或可比较的,因此不应该依赖于 UUID 的大小或顺序。


在某些情况下,使用这个 API 可能对应用程序的可用性产生负面影响。下面,我们将通过一个实际案例来深入讨论这一问题。

randomUUID 如何工作

java.util.UUID#randomUUID API 在内部使用操作系统中的 entropy 来生成一个唯一的数字。entropy 是什么意思 Linux 内核使用某些技术,如用户的鼠标移动,硬件风扇噪音的变化,设备驱动程序噪音的变化,来生成随机数。当操作系统中缺乏时,随机数生成将减慢。当出现减速时,调用此 java.util.UUID#randomUUID 的应用程序线程将被置于 BLOCKED 状态,严重时会让程序处于暂停状态。

真实的世界应用程序-java.util.UUID#randomUUID()API 中阻塞的 50 个线程

下面是一个应用程序的实际线程转储报告,该应用程序正遭受此问题的困扰。在线程转储报告中,我们可以注意到总共有 102 个线程。在这 102 个线程中,有 50 个线程由于java.util.UUID#randomUUID API 而处于 BLOCKED 状态。下面是这 50 个线程之一的堆栈跟踪:


"[ACTIVE] ExecuteThread: '1' for queue: 'weblogic.kernel.Default (self-tuning)'" waiting for lock java.security.SecureRandom@20a56b2b BLOCKED java.security.SecureRandom.nextBytes(SecureRandom.java:433)java.util.UUID.randomUUID(UUID.java:159)com.buggycompany.jtm.bp.<init>(bp.java:185)com.buggycompany.jtm.a4.f(a4.java:94)com.buggycompany.agent.trace.RootTracer.topComponentMethodBbuggycompanyin(RootTracer.java:439)weblogicx.servlet.gzip.filter.GZIPFilter.doFilter(GZIPFilter.java)weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:56)weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.wrapRun(WebAppServletContext.java:3730)weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run(WebAppServletContext.java:3696)weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:321)weblogic.security.service.SecurityManager.runAs(SecurityManager.java:120)weblogic.servlet.internal.WebAppServletContext.securedExecute(WebAppServletContext.java:2273)weblogic.servlet.internal.WebAppServletContext.execute(WebAppServletContext.java:2179)weblogic.servlet.internal.ServletRequestImpl.run(ServletRequestImpl.java:1490)weblogic.work.ExecuteThread.execute(ExecuteThread.java:256)weblogic.work.ExecuteThread.run(ExecuteThread.java:221)
复制代码


由于缺少 entropy,线程在调用 java.util.UUID#randomUUID 时进入了 BLOCKED 状态,无法继续执行代码。这 50 个线程被卡住了。

解决方案

JDK 升级

这个问题是由 Java 中的一个已知 bug 引起的。但是,自 JDK 8 u112 或 JDK 9 b105 以来,它已被修复。所以最优先的解决方案就是升级你的 JDK 版本。

Linux 安装 Haveged

如果你的 Java 程序运行在 Linux 中,那么可以考虑安装haveged库。haveged 项目旨在提供一个易于使用的,不可预测的随机数生成器,基于 HAVEGE 算法的适应。这里是Haveged项目 GIT 仓库页面。以下是如何安装它:


在基于 Debian 的平台(Debian,Ubuntu)上:


sudo apt-get install rng-toolssudo update-rc.d haveged defaults
复制代码


在 Redhat 平台(RHEL、Fedora、CentOS)上:


sudo yum install rng-toolssudo chkconfig haveged on
复制代码

用/dev/urandom 代替/dev/random

类 Unix 操作系统提供了特殊的文件/dev/random,用作伪随机数生成器。Java 使用这个文件来生成随机数。可以将其配置为使用/dev/urandom而不是/dev/random


/dev/urandom是另一个能够生成随机数的特殊文件。然而,由于随机性较小,它具有降低安全性的缺点。如果需要的话,可以通过在启动过程中将下面的 JVM 参数传递给你的 Java 程序来实现它:


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


发布于: 刚刚阅读数: 3
用户头像

FunTester

关注

公众号:FunTester,800篇原创,欢迎关注 2020-10-20 加入

Fun·BUG挖掘机·性能征服者·头顶锅盖·Tester

评论

发布
暂无评论
UUID意想不到的block_FunTester_InfoQ写作社区