生成随机 UUID 非阻塞

lin*_*bon 7 java uuid reactive-programming project-reactor spring-webflux

通过使用 Blockhound io.projectreactor.tools blockhound-junit-platform我发现 UUID.randomUUID 是一个阻塞调用,这对我们来说是一个问题,因为我们使用的是 Spring Boot Webflux 版本 2.2.2.RELEASE

有没有其他方法可以以非阻塞方式获取随机 uuid,或者是否有任何其他 Java 库推荐用于非阻塞生成随机字符串。

来自blockhound的堆栈跟踪:

java.lang.Error: Blocking call! java.io.FileInputStream#readBytes
at reactor.blockhound.BlockHound$Builder.lambda$new$0(BlockHound.java:196) ~[blockhound-1.0.1.RELEASE.jar:na]
Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: 
Error has been observed at the following site(s):
|_ checkpoint ? org.springframework.boot.actuate.metrics.web.reactive.server.MetricsWebFilter [DefaultWebFilterChain][ExceptionHandlingWebHandler]
Stack trace:
    at reactor.blockhound.BlockHound$Builder.lambda$new$0(BlockHound.java:196) ~[blockhound-1.0.1.RELEASE.jar:na]
    at reactor.blockhound.BlockHound$Builder.lambda$install$6(BlockHound.java:318) ~[blockhound-1.0.1.RELEASE.jar:na]
    at reactor.blockhound.BlockHoundRuntime.checkBlocking(BlockHoundRuntime.java:46) ~[na:na]
    at java.base/java.io.FileInputStream.readBytes(FileInputStream.java) ~[na:na]
    at java.base/java.io.FileInputStream.read(FileInputStream.java:279) ~[na:na]
    at java.base/java.io.FilterInputStream.read(FilterInputStream.java:133) ~[na:na]
    at java.base/sun.security.provider.NativePRNG$RandomIO.readFully(NativePRNG.java:424) ~[na:na]
    at java.base/sun.security.provider.NativePRNG$RandomIO.ensureBufferValid(NativePRNG.java:526) ~[na:na]
    at java.base/sun.security.provider.NativePRNG$RandomIO.implNextBytes(NativePRNG.java:545) ~[na:na]
    at java.base/sun.security.provider.NativePRNG.engineNextBytes(NativePRNG.java:220) ~[na:na]
    at java.base/java.security.SecureRandom.nextBytes(SecureRandom.java:741) ~[na:na]
    at java.base/java.util.UUID.randomUUID(UUID.java:150) ~[na:na]
Run Code Online (Sandbox Code Playgroud)

fab*_*ace 3

这是有关如何使用uuid-creator减少 Linux 上的线程争用的三个示例的列表。

\n

另一个示例使用ulid-creator生成单调 ULID,然后将其转换为 RFC-4122 UUID(标准)。单调 ULID 的生成速度非常快

\n

基准代码可在GitHub Gist上找到。

\n

示例 1:使用UuidCreatorandSHA1PRNG

\n

如何设置SHA1PRNG要使用的算法UuidCreator

\n
# Append to /etc/environment or ~/.profile\n# Use the the algorithm SHA1PRNG for SecureRandom\nexport UUIDCREATOR_SECURERANDOM="SHA1PRNG"\n
Run Code Online (Sandbox Code Playgroud)\n
// generate a random-based UUID\nUUID uuid = UuidCreator.getRandomBased();\n
Run Code Online (Sandbox Code Playgroud)\n

UuidCreator使用固定池SecureRandom。该变量UUIDCREATOR_SECURERANDOM指示UuidCreator使用另一种SecureRandom算法,而不是NativePRNG在 Linux 上。UuidCreatorSHA1PRNG算法一起生成的 UUID 比UUID.randomUUID().

\n

查看使用 4 线程的基准测试:

\n
----------------------------------------------------------------------\nBenchmark                      Mode  Cnt      Score     Error   Units\n----------------------------------------------------------------------\nUUID.randomUUID()             thrpt    5   1423,060 \xc2\xb1  30,125  ops/ms\nUuidCreator.getRandomBased()  thrpt    5  10616,016 \xc2\xb1 281,486  ops/ms\n----------------------------------------------------------------------\n
Run Code Online (Sandbox Code Playgroud)\n

示例 2:使用ThreadLocalRandom

\n

如何使用以下方法实现 UUID 生成器ThreadLocalRandom

\n
----------------------------------------------------------------------\nBenchmark                      Mode  Cnt      Score     Error   Units\n----------------------------------------------------------------------\nUUID.randomUUID()             thrpt    5   1423,060 \xc2\xb1  30,125  ops/ms\nUuidCreator.getRandomBased()  thrpt    5  10616,016 \xc2\xb1 281,486  ops/ms\n----------------------------------------------------------------------\n
Run Code Online (Sandbox Code Playgroud)\n

ThreadLocalRandom是一个快速(且不安全)的随机生成器,没有线程争用(非阻塞)。

\n

查看使用 4 线程的基准测试:

\n
----------------------------------------------------------------------\nBenchmark                     Mode  Cnt      Score      Error   Units\n----------------------------------------------------------------------\nUUID.randomUUID()            thrpt    5   1423,060 \xc2\xb1   30,125  ops/ms\nUuidGenerator.generate()     thrpt    5  85390,979 \xc2\xb1 1564,589  ops/ms\n----------------------------------------------------------------------\n
Run Code Online (Sandbox Code Playgroud)\n

示例 3:使用RandomBasedFactory[]andSHA1PRNG

\n

如何使用RandomBasedFactory和数组实现 UUID 生成器SHA1PRNG算法:

\n
public class UuidGenerator {\n\n    private static final RandomBasedFactory UUID_FACTORY;\n\n    static {\n        UUID_FACTORY = new RandomBasedFactory((int length) -> {\n            final byte[] bytes = new byte[length];\n            ThreadLocalRandom.current().nextBytes(bytes);\n            return bytes;\n        });\n    }\n\n    public static UUID generate() {\n        return UUID_FACTORY.create();\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

一系列RandomBasedFactorywith 和SHA1PRNG算法可以生成具有较少线程争用(较少阻塞)的 UUID。

\n

查看使用 4 线程的基准测试:

\n
----------------------------------------------------------------------\nBenchmark                     Mode  Cnt      Score      Error   Units\n----------------------------------------------------------------------\nUUID.randomUUID()            thrpt    5   1423,060 \xc2\xb1   30,125  ops/ms\nUuidGenerator.generate()     thrpt    5  10048,747 \xc2\xb1  195,209  ops/ms\n----------------------------------------------------------------------\n
Run Code Online (Sandbox Code Playgroud)\n

示例 4:使用UlidCreatorandMonotonic ULIDs

\n

如何使用ulid-creator从单调 ULID生成 RFC-4122 UUID :

\n
----------------------------------------------------------------------\nBenchmark                     Mode  Cnt      Score      Error   Units\n----------------------------------------------------------------------\nUUID.randomUUID()            thrpt    5   1423,060 \xc2\xb1   30,125  ops/ms\nUuidGenerator.generate()     thrpt    5  85390,979 \xc2\xb1 1564,589  ops/ms\n----------------------------------------------------------------------\n
Run Code Online (Sandbox Code Playgroud)\n

查看使用 4 线程的基准测试:

\n
-----------------------------------------------------------------------\nBenchmark                       Mode  Cnt     Score      Error   Units\n-----------------------------------------------------------------------\nUUID.randomUUID()              thrpt    5  1423,060 \xc2\xb1   30,125  ops/ms\nUlidCreator.getMonotonicUlid() thrpt    5  7391,917 \xc2\xb1  871,799  ops/ms\n-----------------------------------------------------------------------\n
Run Code Online (Sandbox Code Playgroud)\n

编辑:添加了使用单调 ULID 的第四个示例。

\n
\n

免责声明:我是uuid-creator.

\n