You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
***Fast**: Minimal overhead using thread-local state.
11
-
***Monotonic**: IDs generated on the same thread increase monotonically. It supports up to ~262k IDs per millisecond before incrementing the timestamp to preserve order.
11
+
***Configurable**: Choose between maximum randomness (default) or per-thread monotonicity.
12
12
13
13
## Why?
14
14
15
15
I was testing the performance of network streams and used the original `uuid` v7 to generate messages
16
16
with unique IDs. I wondered why there was a maximum of 400,000 messages per
17
17
second, even though the rest of the code looked like it could handle millions.
18
18
I figured out that 400,000 is mostly the limit of the standard `uuid` crate when
19
-
using v7. Even v4 was not significantly faster. This happened due to the strong
19
+
using v7 without any additional feature flags. This happened due to the strong
20
20
random number generator used in `uuid`. While a strong RNG is correct and avoids potential issues
21
21
in security or crypto contexts, it is otherwise just very slow.
22
+
I found out about the `fast-rng` feature flag of `uuid` after creating this crate. But even with `fast-rng` feature flag, `fast-uuid-ui` is much faster than `uuid`.
22
23
23
24
## Comparison to `uuid` crate
24
25
25
26
Compared to the standard `uuid` crate (which may take up to ~1.4µs / 1440ns per ID):
26
27
***`fast-uuid-v7` can be up to ~130x faster** (11ns vs 1440ns).
28
+
* When using feature `fast-rng` on the original `uuid` crate, `fast-uuid-v7` can still be up to
29
+
8 times faster for `uint128` (11ns vs 90ns) and 6 times faster for `&str` generation (26ns vs 170ns).
27
30
28
-
As the potential throughput is much higher, the internal counter was increased
29
-
from 12 bits to 18 bits, and the random part was reduced from 64 bits to 56 bits.
31
+
## Configuration
32
+
33
+
### Default (74 bits randomness)
34
+
By default, `fast-uuid-v7` uses all available 74 bits for randomness. This matches the standard UUID v7 randomness layout.
35
+
***Pros**: Extremely low collision risk across distributed systems.
36
+
***Cons**: IDs generated within the same millisecond on the same thread are not guaranteed to be monotonic (they will be random).
37
+
38
+
### Feature `use_counter`
39
+
If you enable the `use_counter` feature in `Cargo.toml`, the library uses an 18-bit counter and 56 bits of randomness.
40
+
***Pros**: Guarantees monotonicity per thread (up to ~262k IDs/ms).
41
+
***Cons**: Reduced randomness (56 bits) increases collision risk in massive distributed systems (approx. 50% chance after 4.5 billion IDs/ms globally).
30
42
31
43
## Bit Layout
32
44
33
45
The 128-bit ID is fully compatible with UUID v7. It is composed of:
34
46
35
47
***48 bits**: Unix timestamp in milliseconds.
36
48
***4 bits**: Version (7).
37
-
***12 bits**: Counter (High 12 bits).
49
+
***12 bits**: Random Data (or Counter High 12 bits with `use_counter`).
38
50
***2 bits**: Variant (10xx).
39
-
***6 bits**: Counter (Low 6 bits).
40
-
***56 bits**: Random data.
51
+
***62 bits**: Random Data (or Counter Low 6 bits + 56 bits random with `use_counter`).
52
+
53
+
**Total Randomness:**
54
+
* Default: **74 bits**
55
+
* With `use_counter`: **56 bits**
41
56
42
57
## Usage
43
58
@@ -63,8 +78,8 @@ fn main() {
63
78
64
79
On a modern machine (e.g., Apple M1 or recent x86_64), you can expect:
Generating 10 million IDs takes approximately **120ms** on a single core.
@@ -80,7 +95,7 @@ Generating 10 million IDs takes approximately **120ms** on a single core.
80
95
### Limitations
81
96
82
97
***Not Cryptographically Secure**: The randomness is optimized for speed, not unpredictability. Do not use for session tokens or secrets. If you don't need speed, use the original `uuid` crate.
83
-
***Per-Thread Monotonicity**: IDs are monotonic within a single thread. Across threads, they are only roughly ordered by timestamp (1ms precision).
98
+
***Monotonicity**: Only guaranteed per-thread if `use_counter` is enabled. Otherwise, IDs within the same millisecond are random.
84
99
***Clock Drift Risk**: The batched timestamp check assumes the CPU counter frequency is stable. While we include safety checks, extreme edge cases (e.g., VM migration) might cause a 1ms timestamp lag.
85
100
***Still needs SystemTime::now()**: The speed of 11ns is not constant and can only be achieved if we can skip calling `SystemTime::now()`. We still need to call `SystemTime::now()` from time to time, for example if the previous call was 1ms ago. In that case, we still need to call `SystemTime::now()` and the performance drops to about 50ns. This is still much faster than the original `uuid` crate.
0 commit comments