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)
这是有关如何使用uuid-creator减少 Linux 上的线程争用的三个示例的列表。
\n另一个示例使用ulid-creator生成单调 ULID,然后将其转换为 RFC-4122 UUID(标准)。单调 ULID 的生成速度非常快。
\n基准代码可在GitHub Gist上找到。
\nUuidCreatorandSHA1PRNG如何设置SHA1PRNG要使用的算法UuidCreator:
# Append to /etc/environment or ~/.profile\n# Use the the algorithm SHA1PRNG for SecureRandom\nexport UUIDCREATOR_SECURERANDOM="SHA1PRNG"\nRun Code Online (Sandbox Code Playgroud)\n// generate a random-based UUID\nUUID uuid = UuidCreator.getRandomBased();\nRun Code Online (Sandbox Code Playgroud)\nUuidCreator使用固定池SecureRandom。该变量UUIDCREATOR_SECURERANDOM指示UuidCreator使用另一种SecureRandom算法,而不是NativePRNG在 Linux 上。UuidCreator与SHA1PRNG算法一起生成的 UUID 比UUID.randomUUID().
查看使用 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----------------------------------------------------------------------\nRun Code Online (Sandbox Code Playgroud)\nThreadLocalRandom如何使用以下方法实现 UUID 生成器ThreadLocalRandom:
----------------------------------------------------------------------\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----------------------------------------------------------------------\nRun Code Online (Sandbox Code Playgroud)\nThreadLocalRandom是一个快速(且不安全)的随机生成器,没有线程争用(非阻塞)。
查看使用 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----------------------------------------------------------------------\nRun Code Online (Sandbox Code Playgroud)\nRandomBasedFactory[]andSHA1PRNG如何使用RandomBasedFactory和数组实现 UUID 生成器SHA1PRNG算法:
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}\nRun Code Online (Sandbox Code Playgroud)\n一系列RandomBasedFactorywith 和SHA1PRNG算法可以生成具有较少线程争用(较少阻塞)的 UUID。
查看使用 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----------------------------------------------------------------------\nRun Code Online (Sandbox Code Playgroud)\nUlidCreatorandMonotonic ULIDs如何使用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----------------------------------------------------------------------\nRun 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-----------------------------------------------------------------------\nRun Code Online (Sandbox Code Playgroud)\n编辑:添加了使用单调 ULID 的第四个示例。
\n免责声明:我是uuid-creator.