Global Unique ID Generator
10/30/24About 1 min
Global Unique ID Generator (GID)
When building distributed systems, generating globally unique, trend-increasing, and high-performance IDs is a core requirement. We've implemented a global unique ID generator based on the Twitter Snowflake algorithm, accessible via the simple async function GID().
Core Goal
Just call let id: i64 = GID().await; to get an absolutely unique i64 ID across the entire system.
What is Snowflake ID?
A Snowflake ID is a 64-bit integer (i64) with its binary structure divided into four parts:
| Part | Bits | Description |
|---|---|---|
| 1. Sign bit | 1 bit | Fixed to 0, ensuring positive IDs |
| 2. Timestamp | 41 bits | Milliseconds from a custom epoch (~69 years) |
| 3. Worker Node ID | 10 bits | Identifies different machines/processes |
| 4. Sequence | 12 bits | Auto-incrementing counter within the same millisecond (4096 IDs per node per ms) |
Advantages
- Globally Unique: Combines timestamp and unique worker node ID
- Trend-Increasing: Monotonically increasing over time, friendly to B-Tree indexes
- High Performance: Generated entirely in memory, no external services needed
- High Availability: Each service instance can independently generate IDs, no single point of failure
How to Use GID()
use crate::GID;
async fn create_user() -> Result<()> {
let new_id: i64 = GID().await;
// Use new_id as the primary key
Ok(())
}Internal Implementation Highlights
- Atomic Operations: Uses
AtomicI64for sequence counting, avoiding data races - Handling High Concurrency: When requests exceed 4096 per ms, enters a spin-wait loop
- Clock Skew Protection: Detects system clock rollbacks and panics to prevent duplicate IDs
Important Notes
Deployment Must-Know
- Unique
machine_idandnode_id: Each concurrently running service instance must have a unique combination ofmachine_idandnode_id. - NTP is essential: Deploy NTP on all servers to ensure accurate system time.