UUID 意想不到的 block
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 个线程之一的堆栈跟踪:
由于缺少 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)上:
在 Redhat 平台(RHEL、Fedora、CentOS)上:
用/dev/urandom 代替/dev/random
类 Unix 操作系统提供了特殊的文件/dev/random
,用作伪随机数生成器。Java 使用这个文件来生成随机数。可以将其配置为使用/dev/urandom
而不是/dev/random
。
/dev/urandom
是另一个能够生成随机数的特殊文件。然而,由于随机性较小,它具有降低安全性的缺点。如果需要的话,可以通过在启动过程中将下面的 JVM 参数传递给你的 Java 程序来实现它:
版权声明: 本文为 InfoQ 作者【FunTester】的原创文章。
原文链接:【http://xie.infoq.cn/article/85230a3bd0ff217b89f3eb38e】。文章转载请联系作者。
评论