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.
Install-Package Jordium.Snowflake.NET
dotnet add package Jordium.Snowflake.NET
<PackageReference Include="Jordium.Snowflake.NET" Version="1.0.0" />
using Jordium.Framework.Snowflake;
// Create ID generator
var options = new IDGeneratorOptions
{
WorkerId = 1, // Worker ID (0-31)
DataCenterId = 1, // Datacenter ID (0-31)
Method = 1 // Algorithm version (1=Drift, 2=Traditional, 3=Lock-free)
};
var generator = new DefaultIDGenerator(options);
// Generate ID
long id = generator.NewLong();
Console.WriteLine($"Generated ID: {id}");
var options = new IDGeneratorOptions
{
WorkerId = 1,
DataCenterId = 1,
Method = 1,
// Custom bit allocation
WorkerIdBitLength = 5, // Worker ID bits (default 5)
DataCenterIdBitLength = 5, // Datacenter ID bits (default 5)
SeqBitLength = 12, // Sequence bits (default 12)
// Base time (for timestamp calculation)
BaseTime = new DateTime(2020, 1, 1, 0, 0, 0, DateTimeKind.Utc),
// Sequence range
MinSeqNumber = 0,
MaxSeqNumber = 4095, // 2^12 - 1
// Drift algorithm specific: max drift count
TopOverCostCount = 2000
};
var generator = new DefaultIDGenerator(options);
// Program.cs or Startup.cs
public void ConfigureServices(IServiceCollection services)
{
// Register as singleton
services.AddSingleton<IIDGenerator>(sp =>
{
var options = new IDGeneratorOptions
{
WorkerId = 1,
DataCenterId = 1,
Method = 1
};
return new DefaultIDGenerator(options);
});
}
// Use in Controller
public class OrderController : ControllerBase
{
private readonly IIDGenerator _idGenerator;
public OrderController(IIDGenerator idGenerator)
{
_idGenerator = idGenerator;
}
[HttpPost]
public IActionResult CreateOrder()
{
long orderId = _idGenerator.NewLong();
// Use generated ID
return Ok(new { OrderId = orderId });
}
}
| 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.
┌─────────────────┬─────────────┬─────────────┬──────────────┐
│ 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:
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