A high-performance Snowflake ID generator supporting multiple algorithms (drift, traditional, lock-free) for distributed systems. Supports .NET Framework 4.6.1-4.8, .NET 6-10, .NET Standard 2.0+, and .NET Standard 2.1.
$ dotnet add package Jordium.Snowflake.NETEnglish | 简体中文
High-performance distributed ID generator based on Twitter's Snowflake algorithm for .NET. Supports three implementation methods for different scenarios.
┌─────────────────┬─────────────┬─────────────┬──────────────┐
│ Timestamp(41bit)│ DC ID (5bit)│ Worker(5bit)│ Sequence(12) │
└─────────────────┴─────────────┴─────────────┴──────────────┘
~69 years 32 DCs 32 Workers 4096/ms
| 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:
Install-Package Jordium.Snowflake.NET
dotnet add package Jordium.Snowflake.NET
<PackageReference Include="Jordium.Snowflake.NET" Version="1.2.0" />
using Jordium.Snowflake.NET;
// 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()}");
// 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();
using Jordium.Snowflake.NET.Extensions;
// 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 });
}
}
// 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
});
| 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 |
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.
| 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 | ⭐⭐⭐⭐ |
Features:
lock for synchronizationUse Cases:
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}");
}
};
Features:
lock for synchronizationUse Cases:
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}");
}
Features:
Use Cases:
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
// ...
| 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
| 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
| 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 |
| 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% |
| 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 |
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.
Recommended Approaches:
// Example: Get from environment variable
var workerId = Environment.GetEnvironmentVariable("WORKER_ID");
var options = new IDGeneratorOptions
{
WorkerId = ushort.Parse(workerId ?? "1"),
DataCenterId = 1,
Method = 1
};
| 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 |
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
Checklist:
AddSingleton)DefaultIDGenerator instancesMIT License @ 2025 JORDIUM.COM