The UUIDs.random() method currently provides a shortcut for UUID.randomUUID() in both 3.x and 4.x. It turns out that internally randomUUID() relies on SecureRandom 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 use SecureRandom arguably an implementation detail.
Let me know what you think and I can submit a patch accordingly.
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.
As a side note, we should also investigate the usage of ThreadLocalRandom as it seems it has better performance under contention.
Tentatively scheduling for 4.10.
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.
I took a note to do a round of micro-benchmarks before 4.10 release, but I don't expect regressions.