Snowflake-Me
English | Chinese
A high-performance, highly concurrent, distributed Snowflake ID generator in Rust.
This implementation is lock-free, designed for maximum throughput and minimum latency on multi-core CPUs.
Highlights
- Lock-Free Concurrency: Uses
AtomicU64and CAS (Compare-And-Swap) operations to manage internal state, completely eliminating the overhead ofMutexcontention and context switching. - High Performance: Cache-line aligned state (
#[repr(align(64))]) prevents false sharing between threads. CAS loop defaults tocompare_exchange_weakfor better throughput on ARM and other architectures. - Highly Customizable: The
Builderpattern allows you to flexibly configure:start_time: The epoch timestamp to shorten the time component of the generated ID.machine_idanddata_center_id: Identifiers for your machines and data centers.- Bit lengths for each component (
time,sequence,machine_id,data_center_id). - Clock drift strategy and maximum allowed drift.
- Batch Generation: Generate multiple unique IDs in a single call with
next_ids(count), amortizing overhead across the batch. - Smart IP Fallback: With the
ip-fallbackfeature enabled, ifmachine_idordata_center_idare not provided, the system will automatically use the machine's local IP address.- Supports both IPv4 and IPv6: It prioritizes private IPv4 addresses and falls back to private IPv6 addresses if none are found.
- Conflict-Free: To ensure uniqueness,
machine_idanddata_center_idare derived from distinct parts of the IP address.
no_stdSupport: Works inno_std+allocenvironments with a user-provided time source.- Thread-Safe:
Snowflakeinstances can be safely cloned and shared across threads. Cloning is a lightweight operation (just anArcreference count increment).
Snowflake ID Structure
The generated ID is a 64-bit unsigned integer (u64) with the following default structure:
┌─────────────────────────────────────────────────────────────────┐
│ 0 │ 41 bits: time │ 5 bits: dc │ 5 bits: machine │ 12 bits: seq │
└─────────────────────────────────────────────────────────────────┘
- Sign Bit (1 bit): Always 0 to ensure the ID is positive.
- Timestamp (41 bits): Milliseconds elapsed since your configured
start_time. 41 bits can represent about 69 years. - Data Center ID (5 bits): Allows for up to 32 data centers.
- Machine ID (5 bits): Allows for up to 32 machines per data center.
- Sequence (12 bits): The number of IDs that can be generated per millisecond on a single machine. 12 bits allow for 4096 IDs per millisecond.
Note: The bit lengths of all components are customizable via the Builder, but their sum must be 63.
Quick Start
1. Add Dependency
Add this library to your Cargo.toml:
[]
= "2.1.1"
To enable the IP address fallback feature:
[]
= { = "2.1.1", = ["ip-fallback"] }
To enable all optional features at once:
[]
= { = "2.1.1", = ["full"] }
Feature Flags
| Feature | Default | Description |
|---|---|---|
std |
Yes | Standard library support (time via jiff). Disable for no_std environments. |
ip-fallback |
No | Auto-detect machine_id and data_center_id from local network interfaces (IPv4/IPv6). Requires std. |
serde |
No | Serde Serialize/Deserialize for SnowflakeId (u64) and SnowflakeIdString (string). |
tracing |
No | Structured logging via tracing at key points (ID generation, clock drift, etc.). |
metrics |
No | Counters and gauges via metrics crate for observability. |
use-strong-cas |
No | Use compare_exchange instead of compare_exchange_weak. Slightly slower but eliminates spurious CAS failures. |
full |
No | Enables all optional features at once. |
2. Basic Usage
#
3. Batch Generation
Generate multiple unique IDs in a single call:
#
4. Multi-threaded Usage
Snowflake instances can be efficiently cloned and shared between threads.
#
5. Decomposing an ID
You can decompose a Snowflake ID back into its components for debugging or analysis.
#
6. Clock Drift Protection
If the system clock moves backward (e.g., due to NTP adjustments), the generator handles it based on the configured strategy. By default, it busy-waits until the clock catches up.
#
Available strategies:
ClockDriftStrategy::Wait(default) — Busy-wait until the clock catches up. Optionally setmax_clock_drift_msto fail if the drift is too large.ClockDriftStrategy::Error— ReturnError::ClockDriftimmediately on backward drift.ClockDriftStrategy::LastTimestamp— Reuse the last known timestamp. IDs remain unique but timestamps become approximate.
7. no_std Usage
In no_std environments, disable default features and provide a time source:
[]
= { = "2.1.1", = false }
use ;
// Call periodically (e.g., from a timer interrupt or RTC read)
set_time_source;
let sf = builder
.start_time // 2022-01-01 UTC in milliseconds
.machine_id
.data_center_id
.finalize
.unwrap;
let id = sf.next_id.unwrap;
Migration from v0.6.x
If you are upgrading from v0.6.x, note the following breaking changes:
next_id()now returnsResult<SnowflakeId, Error>instead ofResult<u64, Error>. Useid.as_u64()to get the rawu64value.DecomposedSnowflake::idfield type changed fromu64toSnowflakeId.Error::NoPrivateIPv4renamed toError::NoPrivateIP(also attempts IPv6 fallback).Error::MutexPoisonedremoved (the generator is now lock-free).- New optional features:
serde,tracing,metrics,use-strong-cas.
Contributing
Issues and Pull Requests are welcome.
License
This project is dual-licensed under the MIT and Apache 2.0 licenses.