Jordium.Snowflake.NET
1.2.1
Prefix Reserved
See the version list below for details.
dotnet add package Jordium.Snowflake.NET --version 1.2.1
NuGet\Install-Package Jordium.Snowflake.NET -Version 1.2.1
<PackageReference Include="Jordium.Snowflake.NET" Version="1.2.1" />
<PackageVersion Include="Jordium.Snowflake.NET" Version="1.2.1" />
<PackageReference Include="Jordium.Snowflake.NET" />
paket add Jordium.Snowflake.NET --version 1.2.1
#r "nuget: Jordium.Snowflake.NET, 1.2.1"
#:package Jordium.Snowflake.NET@1.2.1
#addin nuget:?package=Jordium.Snowflake.NET&version=1.2.1
#tool nuget:?package=Jordium.Snowflake.NET&version=1.2.1
Jordium.Snowflake.NET
English | 简体中文
High-performance distributed ID generator based on Twitter's Snowflake algorithm for .NET. Supports three implementation methods for different scenarios.
Features
- ✅ Globally Unique: Supports multi-datacenter, multi-machine deployment
- 📈 Trend Increasing: IDs increase by timestamp, optimized for database indexing
- ⚡ High Performance: 2 million - 20 million IDs/second per machine (actual results may vary depending on test environment)
- 🔧 Multiple Implementations: Drift algorithm, Traditional algorithm, Lock-free algorithm
- ⏰ Clock Rollback Handling: Automatic handling of system time rollback
- 🎯 Flexible Configuration: Customizable bit allocation
ID Structure
Standard 64-bit Snowflake ID
┌─────────────────┬─────────────┬─────────────┬──────────────┐
│ Timestamp(41bit)│ DC ID (5bit)│ Worker(5bit)│ Sequence(12) │
└─────────────────┴─────────────┴─────────────┴──────────────┘
~69 years 32 DCs 32 Workers 4096/ms
Bit Allocation Examples
| Config | Worker Bits | DC Bits | Seq Bits | Capacity |
|---|---|---|---|---|
| Standard | 5 | 5 | 12 | 32 DC × 32 Worker × 4096/ms |
| Multi-DC | 4 | 6 | 12 | 64 DC × 16 Worker × 4096/ms |
| Multi-Worker | 6 | 4 | 12 | 16 DC × 64 Worker × 4096/ms |
| Low Concurrency | 5 | 5 | 10 | 32 DC × 32 Worker × 1024/ms |
Constraints:
- Worker bits + DC bits + Seq bits ≤ 22
- Seq bits ≤ 12
Installation
NuGet CLI
Install-Package Jordium.Snowflake.NET
.NET CLI
dotnet add package Jordium.Snowflake.NET
PackageReference
<PackageReference Include="Jordium.Snowflake.NET" Version="1.2.0" />
Getting Started (v1.2.0)
Client Application
1. Import Namespace
using Jordium.Snowflake.NET;
2. Create Instance Using Factory Pattern
// Method 1: Create instance using WorkerId and DataCenterId
var generator1 = JordiumSnowflakeIDGeneratorFactory.Create(workerId: 1, dataCenterId: 1);
System.Console.WriteLine($"Generator 1 (WorkerId=1, DataCenterId=1): {generator1.NewLong()}");
// Method 2: Create instance using IDGeneratorOption object
var options = new IDGeneratorOptions(workerId: 2, dataCenterId: 1)
{
Method = 1
};
var generator2 = JordiumSnowflakeIDGeneratorFactory.Create(options);
System.Console.WriteLine($"Generator 2 (WorkerId=2, DataCenterId=1): {generator2.NewLong()}");
// Method 3: Create instance using configuration delegate
var generator3 = JordiumSnowflakeIDGeneratorFactory.Create(opt =>
{
opt.WorkerId = 3;
opt.DataCenterId = 1;
opt.Method = 1;
opt.BaseTime = new DateTime(2024, 1, 1, 0, 0, 0, DateTimeKind.Utc);
});
System.Console.WriteLine($"Generator 3 (WorkerId=3, DataCenterId=1): {generator3.NewLong()}");
3. Singleton Pattern - Use global default instance
// Check if default instance is initialized
if (!JordiumSnowflakeIDGeneratorFactory.IsDefaultInitialized)
{
System.Console.WriteLine("Default instance not initialized. Initializing now...");
// Initialize the default singleton instance
JordiumSnowflakeIDGeneratorFactory.InitializeDefault(workerId: 10, dataCenterId: 2);
System.Console.WriteLine("> Default instance initialized successfully!");
}
// Use the default instance anywhere in your application
long id1 = JordiumSnowflakeIDGeneratorFactory.Default.NewLong();
long id2 = JordiumSnowflakeIDGeneratorFactory.Default.NewLong();
long id3 = JordiumSnowflakeIDGeneratorFactory.Default.NewLong();
ASP.NET Core Dependency Injection (v1.2.0+ Easier Registration, More Standard ASP.NET Core Approach)
1. Import Namespace
using Jordium.Snowflake.NET.Extensions;
2. Register Jordium.Snowflake.NET Service
// Program.cs OR Startup.cs
public void ConfigureServices(IServiceCollection services)
{
// use code-based configuration
services.AddJordiumSnowflakeIdGenerator(options => {
options.WorkerId = 1;
options.DataCenterId = 1;
});
}
// Controller
public class OrderController : ControllerBase
{
private readonly IIDGenerator _idGenerator;
public OrderController(IIDGenerator idGenerator)
{
_idGenerator = idGenerator;
}
[HttpPost]
public IActionResult CreateOrder()
{
long orderId = _idGenerator.NewLong();
// ID Generated
return Ok(new { OrderId = orderId });
}
}
3. Supports 3 Registration Methods
// Method 1: Read default "JordiumSnowflakeConfig" configuration from appsettings.json
services.AddJordiumSnowflakeIdGenerator();
// Configuration in appsettings.json:
"JordiumSnowflakeConfig": {
"DataCenterId": 1,
"WorkerId": 2,
"Method": 1,
"WorkerIdBitLength": 5,
"DataCenterIdBitLength": 5,
"SequenceBitLength": 12
}
// Method 2: Use custom configuration section "MyCustomSnowflakeConfigSection"
services.AddJordiumSnowflakeIdGenerator(_configuration, "MyCustomSnowflakeConfigSection");
// Configuration in appsettings.json:
"MyCustomSnowflakeConfigSection": {
"DataCenterId": 1,
"WorkerId": 2,
"Method": 1,
"WorkerIdBitLength": 5,
"DataCenterIdBitLength": 5,
"SequenceBitLength": 12
}
// Method 3: Code-based configuration
services.AddJordiumSnowflakeIdGenerator(options => {
options.WorkerId = 1;
options.DataCenterId = 1;
...other properties
});
IDGeneratorOptions Property Description
| Property Name | Type | Description | Default Value |
|---|---|---|---|
| Method | short | Calculation method (1-Drift algorithm, 2-Traditional algorithm, 3-Lock-free algorithm) | 1 |
| BaseTime | DateTime | Start time (UTC format), cannot exceed current system time | DateTime(2020, 2, 20, 2, 20, 2, 20, DateTimeKind.Utc) |
| WorkerId | ushort | Machine code | 0 |
| DataCenterId | ushort | Data center identifier | 0 |
| WorkerIdBitLength | byte | Machine code bit length. Recommended range: 1-5 (requirement: sequence bits + data identifier + machine code bits ≤ 22). | 5 |
| DataCenterIdBitLength | byte | Data center identifier bit length. Recommended range: 1-5 (requirement: sequence bits + data identifier + machine code bits ≤ 22). | 5 |
| SeqBitLength | byte | Sequence bit length. Recommended range: 1-12 (requirement: sequence bits + machine code bits ≤ 22) 4096. | 12 |
| MaxSeqNumber | int | Maximum sequence number (inclusive). (Maximum value calculated by SeqBitLength) | 0 |
| MinSeqNumber | int | Minimum sequence number (inclusive). Default 0, not less than 0, not greater than MaxSeqNumber | 0 |
| TopOverCostCount | int | Maximum drift count (inclusive). Default 2000, recommended range 500-10000 (related to computing power) | 2000 |
Supported Target Frameworks
- .NET Framework (>= 4.6.1)
- .NET 6
- .NET 7
- .NET 8
- .NET 9
- .NET 10
- .NET Standard (>= 2.0)
Built-in Algorithm Comparison (see source code provided in the open-source library)
The code blocks mentioned in this section are for unit testing, directly instantiated and demonstrated based on the underlying code, not using dependency injection or factory pattern instances.
Three Algorithms
| Algorithm | Implementation | Use Case | Performance | Clock Rollback | Recommended |
|---|---|---|---|---|---|
| Method 1 | SnowflakeWorkerV1 | Monolith app, high concurrency | ⭐⭐⭐⭐ | ✅ Special sequence | ⭐⭐⭐⭐⭐ |
| Method 2 | SnowflakeWorkerV2 | General, standard implementation | ⭐⭐⭐⭐ | ❌ Throws exception | ⭐⭐⭐ |
| Method 3 | SnowflakeWorkerV3 | Distributed cluster, microservices | ⭐⭐⭐⭐⭐ | ⚠️ Large rollback throws | ⭐⭐⭐⭐ |
Detailed Description
Method 1 - Drift Algorithm (Recommended)
Features:
- ✅ Auto-handles clock rollback (uses reserved sequence 1-4)
- ✅ Auto "drift" to future time when sequence overflows
- ✅ Complete event callback mechanism
- 🔒 Uses
lockfor synchronization
Use Cases:
- Monolithic applications (multiple threads competing for same WorkerId)
- Business sensitive to clock rollback
- Systems requiring ID generation monitoring
Configuration Example:
var options = new IDGeneratorOptions
{
WorkerId = 1,
DataCenterId = 1,
Method = 1,
TopOverCostCount = 2000 // Max drift count
};
var generator = new DefaultIDGenerator(options);
// Optional: Listen to events
generator.GenIdActionAsync = arg =>
{
if (arg.ActionType == 1) // Begin drift
{
Console.WriteLine($"Begin drift: WorkerId={arg.WorkerId}");
}
};
Method 2 - Traditional Algorithm
Features:
- ✅ Standard Snowflake implementation
- ✅ Simple logic, easy to understand
- ❌ Throws exception on clock rollback
- 🔒 Uses
lockfor synchronization
Use Cases:
- Learning and understanding Snowflake algorithm
- Stable environment with rare clock rollback
- Simple scenarios without complex features
Configuration Example:
var options = new IDGeneratorOptions
{
WorkerId = 1,
DataCenterId = 1,
Method = 2
};
var generator = new DefaultIDGenerator(options);
try
{
long id = generator.NewLong();
}
catch (Exception ex)
{
// Throws exception on clock rollback
Console.WriteLine($"Clock rollback error: {ex.Message}");
}
Method 3 - Lock-Free Algorithm (High Performance)
Features:
- ✅ CAS lock-free concurrency, highest performance
- ✅ Timestamp cached in state, reduces system calls
- ✅ Significant performance advantage in distributed scenarios
- ⚠️ Short rollback auto-sleeps and waits
- ⚠️ Large rollback (> 1000ms) throws exception
Use Cases:
- Microservice clusters (each service has independent WorkerId)
- Kubernetes deployment (each Pod has independent WorkerId)
- High-concurrency distributed systems
- Scenarios pursuing extreme performance
Configuration Example:
var options = new IDGeneratorOptions
{
WorkerId = 1,
DataCenterId = 1,
Method = 3
};
var generator = new DefaultIDGenerator(options);
// Lock-free performs best in multi-WorkerId scenarios
// Example: Microservice cluster
// Service 1: WorkerId = 1
// Service 2: WorkerId = 2
// Service 3: WorkerId = 3
// ...
Performance Comparison
Single WorkerId Contention (8 threads)
| Algorithm | Throughput | Note |
|---|---|---|
| Method 1 | 6-8M IDs/sec | Lock performs stable under single-machine contention |
| Method 2 | 5-7M IDs/sec | Standard implementation, medium performance |
| Method 3 | 4-6M IDs/sec | CAS conflict causes performance degradation |
Conclusion: For single WorkerId high concurrency, recommend Method 1
Multi WorkerId Independent Scenario (8 WorkerIds)
| Algorithm | Throughput | Note |
|---|---|---|
| Method 1 | 8-12M IDs/sec | Lock has fixed overhead |
| Method 2 | 7-11M IDs/sec | Standard implementation |
| Method 3 | 12-18M IDs/sec | Lock-free advantage is significant ? |
Conclusion: For multi-WorkerId distributed scenarios, recommend Method 3
Performance Test Report
Test Environment
- CPU: Intel Core i7-12700K (12 cores, 20 threads) @ 3.6GHz
- RAM: 32GB DDR4 3200MHz
- OS: Windows 11 Pro
- .NET Version: .NET 8.0
- Test Mode: Release build, no debugger
Single Machine Performance (Method 1)
| Threads | Throughput | Avg Latency | Note |
|---|---|---|---|
| 1 | 12-15M IDs/sec | 0.067-0.083 μs | Single thread, no contention |
| 2 | 9-12M IDs/sec | 0.167-0.222 μs | Light contention |
| 4 | 7-9M IDs/sec | 0.444-0.571 μs | Medium contention |
| 8 | 6-8M IDs/sec | 1.000-1.333 μs | Heavy contention |
Distributed Performance (Method 3)
| WorkerIds | Count Each | Total Throughput | Performance Gain |
|---|---|---|---|
| 2 | 50,000 | 10-13M IDs/sec | +10-15% |
| 4 | 25,000 | 12-15M IDs/sec | +35-45% |
| 8 | 12,500 | 14-18M IDs/sec | +50-60% |
Correctness Tests
| Test Item | Count | Duplicates | Result |
|---|---|---|---|
| Single WorkerId Concurrent | 1M | 0 | ✅ Pass |
| Multi WorkerId Concurrent | 1M | 0 | ✅ Pass |
| Extreme Concurrency (32 threads) | 3.2M | 0 | ✅ Pass |
| Sustained Pressure (5 sec) | 10M+ | 0 | ✅ Pass |
Stability Tests
- ✅ Million-level Test: Generate 1M IDs at once, no duplicates
- ✅ Sustained Pressure Test: Continuous generation for 5 seconds, no duplicates
- ✅ Multi-datacenter Test: 3 datacenters × 3 workers, no duplicates
- ✅ Clock Rollback Test: Method 1 auto-handles, Method 2/3 correctly throw exceptions
Performance Notes
Note: Actual performance depends on multiple factors:
- CPU model and frequency
- Memory speed
- OS scheduling
- .NET runtime version
- Debug/Release mode
- System load
The above data are reference values from typical test environments. Real deployment environments may have ±30% variations. We recommend running benchmarks on actual hardware for accurate data.
FAQ
1. How to Choose WorkerId?
Recommended Approaches:
- Monolithic app: Fixed value (e.g., 1)
- Microservices: Hash service name and modulo
- K8s: Use Pod ordinal (StatefulSet)
- Config center: Fetch from configuration service
// Example: Get from environment variable
var workerId = Environment.GetEnvironmentVariable("WORKER_ID");
var options = new IDGeneratorOptions
{
WorkerId = ushort.Parse(workerId ?? "1"),
DataCenterId = 1,
Method = 1
};
2. How to Handle Clock Rollback?
| Algorithm | Handling |
|---|---|
| Method 1 | Uses reserved sequence 1-4, supports up to 4 rollbacks |
| Method 2 | Throws exception directly |
| Method 3 | Short time (< 1s) sleeps and waits, long time throws exception |
3. How to Ensure Distributed Uniqueness?
Ensure each machine has a unique WorkerId and DataCenterId combination:
// Wrong Example ❌
// Server 1: WorkerId=1, DataCenterId=1
// Server 2: WorkerId=1, DataCenterId=1 ← Will produce duplicate IDs
// Correct Example ✅
// Server 1: WorkerId=1, DataCenterId=1
// Server 2: WorkerId=2, DataCenterId=1
// Server 3: WorkerId=1, DataCenterId=2
4. What if Performance is Below Expectations?
Checklist:
- ✅ Use singleton pattern (
AddSingleton) - ✅ Avoid frequent creation of
DefaultIDGeneratorinstances - ✅ Choose Method 1 for single-machine high concurrency
- ✅ Choose Method 3 for distributed scenarios
- ✅ Check for duplicate WorkerIds
- ✅ Use Release mode build
- ✅ Ensure stable system clock
License
MIT License @ 2025 JORDIUM.COM
Contact Us
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 is compatible. |
| .NET Framework | net461 is compatible. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 is compatible. net48 is compatible. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETFramework 4.6.1
- Microsoft.Extensions.Configuration.Abstractions (>= 2.1.0)
- Microsoft.Extensions.Configuration.Binder (>= 2.1.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 2.1.0)
- Microsoft.Extensions.Options (>= 2.1.0)
-
.NETFramework 4.7.2
- Microsoft.Extensions.Configuration.Abstractions (>= 2.1.0)
- Microsoft.Extensions.Configuration.Binder (>= 2.1.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 2.1.0)
- Microsoft.Extensions.Options (>= 2.1.0)
-
.NETFramework 4.8
- Microsoft.Extensions.Configuration.Abstractions (>= 2.1.0)
- Microsoft.Extensions.Configuration.Binder (>= 2.1.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 2.1.0)
- Microsoft.Extensions.Options (>= 2.1.0)
-
.NETStandard 2.0
- Microsoft.Extensions.Configuration.Abstractions (>= 2.1.0)
- Microsoft.Extensions.Configuration.Binder (>= 2.1.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 2.1.0)
- Microsoft.Extensions.Options (>= 2.1.0)
-
.NETStandard 2.1
- Microsoft.Extensions.Configuration.Abstractions (>= 3.1.0)
- Microsoft.Extensions.Configuration.Binder (>= 3.1.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 3.1.0)
- Microsoft.Extensions.Options (>= 3.1.0)
-
net10.0
- Microsoft.Extensions.Configuration.Abstractions (>= 10.0.0)
- Microsoft.Extensions.Configuration.Binder (>= 10.0.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.0)
- Microsoft.Extensions.Options (>= 10.0.0)
-
net6.0
- Microsoft.Extensions.Configuration.Abstractions (>= 6.0.0)
- Microsoft.Extensions.Configuration.Binder (>= 6.0.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 6.0.0)
- Microsoft.Extensions.Options (>= 6.0.0)
-
net8.0
- Microsoft.Extensions.Configuration.Abstractions (>= 8.0.0)
- Microsoft.Extensions.Configuration.Binder (>= 8.0.2)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.2)
- Microsoft.Extensions.Options (>= 8.0.2)
-
net9.0
- Microsoft.Extensions.Configuration.Abstractions (>= 9.0.0)
- Microsoft.Extensions.Configuration.Binder (>= 9.0.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 9.0.0)
- Microsoft.Extensions.Options (>= 9.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
v1.2.1: Added Symbol package