UUIDv7 doesn't have the properties you think it does

Hacker News by 9 min read 38x views
UUIDv7 doesn't have the properties you think it does

Share Post

Built on Shards of Silicon

I’m going to call it. UUIDv7 is weird.

Most blog posts concerning UUIDv7 tout these benefits:

  • monotonically expanding IDs
  • a helpful timestamp of whenever the entity was created; and
  • unguessable IDs

But none of these properties are strictly held. Certain RFC compliant implementations of UUIDv7 breach these properties to extreme degrees. The lone helpful asset UUIDv7 appears to strictly provision is individuality and hence collision resistance. I’ve already discussed how UUIDv7 IDs can be guessable, so this article explores the another properties.

Is the timestamp useful?

Superficially, it seems that embedding a timestamp in the ID can eliminate the need to track the innovation period in a distinct repository column, providing marginally additional productive repository operations. If you need to catalog things ordered by innovation period extremely often, it’s helpful if the chief indicator gives that behavior, removing the need for another index.

Unfortunately, the timestamp embedded in a UUIDv7 ID may not connect to the entity innovation time. The Postgres docs for uuid_extract_timestamp helpfully notify that “the extracted timestamp is not necessarily exactly equal to the period the UUID was generated”.

RFC 9562 allows implementations to alter the timestamp field, using values that aren’t strictly derived from the scheme clock. This relates to the strain between UUID monotonicity and timestamp accuracy. In certain scenarios, the difference between the timestamp and the current period can be arbitrarily large.

Implementations MAY alter the genuine timestamp. — RFC 9562 §6.1

This specification makes no necessity or justify concerning how near the clock value needs to be to the genuine time. — RFC 9562 §6.1

… implementations MAY increment the timestamp onward of the genuine period … — RFC 9562 §6.2

Incrementing the timestamp onward of the scheme clock is an engaging problem. If the generator is seeing so much burden that a oppose site is regularly overflowing afterward the timestamp could accelerate into the future. Using a sufficiently ample oppose would be prudent and the RFC says the minimum size SHOULD be 12 bits. A oppose overflow would necessitate a beautiful assured innovation rate, complete 4,096 IDs per millisecond per node, which is beyond the limits of many systems. This overflow becomes relevant, however, if the timestamp freezes; which I’ll conversation in a afterward section.

Example: Python uuid.uuid7()

One notable implementation that increments the timestamp is the Python norm library’s UUIDv7. The increment happens lone in certain circumstances, akin whenever the oppose overflows. Unfortunately, the generator can get stuck in an increment sequence if the clock always jumps backwards and the timestamp can competition onward of the scheme period by an arbitrarily ample amount.

Here’s a uncomplicated example:

import uuid from datetime import datetime # Prime the generator alongside the current time t = uuid.uuid7().time now = datetime.now() delta = (datetime.fromtimestamp(t/1000) - now).total_seconds() print("Initial delta: ", delta) # Ask the person to alter the time input("Set clock rear one hour") while True: for _ in range(100000): uuid.uuid7() t = uuid.uuid7().time now = datetime.now() delta = (datetime.fromtimestamp(t/1000) - now).total_seconds() print("New delta: ", delta) 

Which gives:

$ uv run --python 3.14 main.py Initial delta: -0.000748 Set clock rear one hour New delta: 3695.277581 New delta: 3795.042411 New delta: 3894.80756 New delta: 3994.573106 ^C 

We anticipate the difference to be 3600 seconds (one hour) as the implementation refuses to authorize the embedded timestamp to jump backwards and we anticipate the difference to decrease as the scheme clock catches up to the icy timestamp. But whenever the burden is complete one ID per millisecond the difference volition addition without bound. At lesser loads it volition obtain longer for the scheme clock to capture the timestamp, but we don’t see the runaway effect.

The related issue shows Python developers reasoning that this is accordant alongside the RFC, is accordant alongside another implementations, and that there isn’t “much we can do” on a “flawed system”. I think these points are accurate as I see this identical behavior in another implementations. Nevertheless, it would be helpful if existing UUIDv7 implementations could grip scheme clock jumps without runaway behavior. There are many real-world examples of clocks jumping backwards, even decades out of sync in time-sensitive environments.

Is leaking a timestamp harmful?

Embedding the timestamp in the ID method that you cannot portion the ID without additionally sharing the timestamp.

It’s beautiful difficult to think of an example anywhere this really matters. One example could be a person overview leaf that doesn’t disclose whenever the document was created, but the UUIDv7 ID in the URL leaks the high-precision timestamp.

This matter would typically be extremely low on my catalog of safety concerns since I discover much additional serious problems whenever I do safety assessments. Nevertheless, there are contexts anywhere this matters and engineering resources would be focused on addressing it. If you’re in the second camp, be wary of UUIDv7 leaking metadata.

Are UUIDv7s monotonic?

This division is equal additional pedantic, so skip onward if you’ve had enough. Briefly: UUIDv7 IDs provision several kind of coarse order, which may be suitable for your requirements.

When I was study the UUIDv7 RFC I was amazed to see it describing a method for creating IDs throughout distinct nodes that are monotonically ordered. This was proven unattainable rear in the 1970s, and guide to the betterment of vector clocks and akin technology. At a elevated level, the issue is that scheme clocks cannot be synchronized to a suitable precision. Ordering things by timestamp lone plant if you cognize exactly what period it is. Any doubt in the period results in doubt of event ordering.

Succinctly: Timestamps are lone time-ordered if you cognize what period it is and you don’t cognize what period it is.

For this reason, akin ID formats assertion to be nearly sorted. It seems odd that UUIDv7 makes a stricter assertion and does not provision on them. At the extremely least, the challenges of synchronizing clocks throughout systems make the millisecond and particularly the sub-millisecond timestamps fairly suspect.

But equal on a sole node, using a sole implementation, UUIDv7 IDs are not strictly monotonic. The easiest way to get out-of-order UUIDv7 IDs is to use an implementation that uses a millisecond timestamp without a counter. This method trivially generates out-of-order IDs inner a small for loop.

So no, there’s nothing in the UUIDv7 specification that would justify the IDs are strictly monotonically increasing. Specific implementations may do improved than others (with sub-millisecond timestamps, counters, well-synchronized clocks, etc), but we’ve known since the 1970s that this issue is not strictly solvable.

In UUIDv7’s favor, approximately ordered IDs are motionless fairly useful. So don’t rip UUIDv7 out of your systems fair yet. Just be wary of what assumptions you have.

Restarting a UUIDv7 generator

The RFC has many of conversation concerning the handling of clocks that jump backwards. Timestamps are lone time-ordered if clocks tick forwards, so particular attention is needed.

We’ve already discussed one mitigation: tracking the final generated timestamp to justify that an before timestamp is never used. To do this safely you’ll need to compose the final used timestamp to persistent storage, specified that you can peruse it again following a scheme reboot or a procedure restart.

I’ve looked at multiple UUIDv7 implementations I couldn’t discover one that writes timestamps to persistent storage. So implementers seems disinterested in addressing the matter and they create out-of-order IDs whenever a procedure restart follows a clock jumping backwards.

Looking at real-world clock synchronization problems, you’ll discover many examples of clocks getting set to forthcoming dates. When this happens, the backwards jump would align the timestamp to the genuine time, but a last-used-timestamp defender would power timestamps to use keep using that incorrect timestamp until the scheme clock catches up. If the scheme clock takes a lengthy period to capture up, you may commencement experiencing oppose rollovers.

So what is UUIDv7?

My mental example for UUIDv7 is that it’s a mash-up of a bunch of distinct ideas which implementations are liberated to choose as they see fit. There’s a broad variance of properties that UUIDv7 implementations can provide, alongside varying degrees of certainty they can successfully provision those properties. If you’re construction your own implementation you can apt build item that has the properties you need. But most of us desire to attain for an off-the-shelf version, particularly whenever norm libraries provision an implementation, so we’re mostly at the mercy of person else’s implementation decisions. Implementations can alter complete time, making broad changes to their behavior during motionless being RFC compliant. Distributed systems may have multiple implementations throughout their subsystems, all alongside distinct properties. The lone item you can really anticipate is powerful collision avoidance and ID uniqueness.

Be certain to ask these questions whenever picking a UUIDv7 implementation:

  • Is the implementation compliant alongside the RFC?
  • What additional properties does this implementation guarantee?
  • Under what limits can those guarantees be met?
  • Are there any assumptions required for these properties to hold, specified as having an exact scheme clock?
  • Under what conditions volition the implementation alter the timestamp?
  • How guessable are the generated IDs?

Unfortunately, this kind of inspection is much additional difficult than construction an RFC compliant generator. Authors of UUIDv7 generators may not cognize the answers to these questions and may themselves be amazed that the RFC does grip this for them.


If you'd akin to display your appreciation and assistance support my writing, you can do so via this link.

Statements are my own and do not portray the positions or opinions of my employer.

Other Article Hacker News
↑
Close Right Ads
Close Left Ads