Use non-cryptographic random number generation in Uuids.random()
Activity
Alex Dutra December 18, 2020 at 4:00 PM
I took a note to do a round of micro-benchmarks before 4.10 release, but I don't expect regressions.
Alex Dutra November 19, 2020 at 11:05 PM
I will propose a new implementation for Uuids.random()
within this ticket, then I will open a different ticket + PR for improving Blockhound integration with the driver.
Alex Dutra September 9, 2020 at 2:08 PM
Tentatively scheduling for 4.10.
Alex Dutra September 9, 2020 at 2:07 PM
As a side note, we should also investigate the usage of ThreadLocalRandom
as it seems it has better performance under contention.
Alex Dutra September 9, 2020 at 2:07 PM(edited)
Another argument in favor of switching to non-cryptographic number generators was just brought to my attention: it turns out that SecureRandom
needs to read from /dev/random
and the like, and that is a blocking call. It’s noted in the class javadocs:
Note: Depending on the implementation, the generateSeed and nextBytes methods may block as entropy is being gathered, for example, if they need to read from /dev/random on various Unix-like operating systems.
Such a blocking call can be detected by tools like BlockHound, see this SO question for an example.
Some users already reported this problem using driver 4.x.
The typical stack trace is:
What is really concerning is that it comes from the client ID generation when composing the STARTUP message, so it’s not even something that was caused by user intervention. A workaround is to provide a pre-computed client ID when building the session.
The
UUIDs.random()
method currently provides a shortcut forUUID.randomUUID()
in both 3.x and 4.x. It turns out that internallyrandomUUID()
relies onSecureRandom
to generate a random number. In the context of Cassandra primary key generation it was likely not considered as a requirement but was just overlooked.A quick JMH benchmark iterating over a 1000 calls to
nextLong()
for various*Random
classes give the following results:So in short,
SecureRandom
is at least 250x slower than the usual Java alternatives and generates some garbage for each generated random number whereas the alternatives don't.To work around this problem, I see 3 options:
1. Replace the
UUIDs.random()
implementation with a custom, non-secure UUID generation one.2. Do 1. and move the current implementation to a new
UUIDs.secureRandom()
method, if you feel that there could be some value in keeping a secure implementation.3. Add a
UUIDs.nonSecureRandom()
with the custom implementation discussed in 1. as a safest way to add a workaround without introducing any potential (if any?) security regression.Note that we don’t make any guarantee on the security aspect of
UUIDs.random()
in its Javadoc, making the fact that we actually useSecureRandom
arguably an implementation detail.Let me know what you think and I can submit a patch accordingly.