A distributed ID generator utility using the Snowflake algorithm with Redis for coordination.
- Standard Snowflake algorithm implementation
- Redis coordination for distributed environments
- Interface-based Redis client for pluggable implementations (works with any Redis client library: go-redis, redigo, rueidis, etc.)
- Support for custom Redis clients
- Builder pattern for flexible configuration
- Thread-safe ID generation
- High performance
- Strict mode with Redis assistance to prevent duplicates
go get github.com/sunquakes/snowredisAutomatically allocate datacenterID and workerID from Redis. This is the recommended approach for most use cases:
package main
import (
"fmt"
"log"
"github.com/sunquakes/snowredis/redis"
"github.com/sunquakes/snowredis/snowflake"
)
func main() {
// Configure Redis connection
cfg := &redis.Config{
Addr: "localhost:6379", // Redis address
Pwd: "", // Redis password (if any)
Db: 0, // Redis database number
}
// Create a Redis client
redisClient, err := redis.NewClient(cfg)
if err != nil {
log.Fatalf("Failed to create Redis client: %v", err)
}
// Automatically allocate IDs from Redis
sf, err := snowflake.NewBuilder().
SetRedisClient(redisClient). // Redis client required for auto-allocation
Build()
if err != nil {
log.Fatalf("Failed to initialize with auto-allocation: %v", err)
}
defer sf.Cleanup()
// Generate unique IDs
for i := 0; i < 5; i++ {
id, err := sf.Generate()
if err != nil {
log.Printf("Error generating ID: %v", err)
continue
}
fmt.Printf("Generated ID: %d\n", id)
}
}Explicitly set datacenter ID and worker ID:
// Create snowflake algorithm instance with manual configuration
cfg := &redis.Config{
Addr: "localhost:6379", // Redis address
Pwd: "", // Redis password (if any)
Db: 0, // Redis database number
}
redisClient, err := redis.NewClient(cfg)
if err != nil {
log.Fatalf("Failed to create Redis client: %v", err)
}
sf, err := snowflake.NewBuilder().
SetRedisClient(redisClient).
SetDatacenterID(1).
SetWorkerID(1).
Build()
if err != nil {
log.Fatalf("Failed to initialize Redis Snowflake: %v", err)
}
defer sf.Cleanup()
// Generate unique IDs
for i := 0; i < 5; i++ {
id, err := sf.Generate()
if err != nil {
log.Printf("Error generating ID: %v", err)
continue
}
fmt.Printf("Generated ID: %d\n", id)
}Enable strict mode to use Redis assistance for preventing duplicates:
// Create instance with strict mode enabled
cfg := &redis.Config{
Addr: "localhost:6379", // Redis address
Pwd: "", // Redis password (if any)
Db: 0, // Redis database number
}
redisClient, err := redis.NewClient(cfg)
if err != nil {
log.Fatalf("Failed to create Redis client: %v", err)
}
sf, err := snowflake.NewBuilder().
SetRedisClient(redisClient).
SetDatacenterID(1).
SetWorkerID(1).
SetStrictMode(true). // Enable strict mode for additional duplicate prevention
Build()
if err != nil {
log.Fatalf("Failed to initialize in strict mode: %v", err)
}
defer sf.Cleanup()
id, err := sf.Generate() // This will use Redis to ensure uniqueness when strict mode is enabled
}Use default values without Redis coordination:
// Create instance with default values (no Redis client needed)
sf, err := snowflake.NewBuilder().
Build() // Uses default datacenter ID and worker ID
if err != nil {
log.Fatalf("Failed to initialize with defaults: %v", err)
}
defer sf.Cleanup()
id, err := sf.Generate()
if err != nil {
log.Printf("Error generating ID: %v", err)
} else {
fmt.Printf("Generated ID: %d\n", id)
}NewBuilder()- Creates a new builder instanceSetRedisClient(client)- Sets the Redis clientSetDatacenterID(id)- Sets the datacenter IDSetWorkerID(id)- Sets the worker IDSetStrictMode(strict)- Enables/disables strict modeBuild()- Builds the snowflake instance
Generate()- Generates a unique IDCleanup()- Cleans up resources
The library supports three main configuration approaches:
- Auto-allocation (Recommended): Let Redis assign IDs automatically
- Manual Configuration: Explicitly set datacenter ID and worker ID
- Default Values: Use built-in default values
The library is designed for high performance:
- Local ID generation after initialization
- Thread-safe operation
- Minimal Redis interaction in normal mode
- Additional Redis checks in strict mode for enhanced uniqueness
The library uses an interface-based approach for Redis clients, allowing you to implement your own Redis client that conforms to the Client interface:
type Client interface {
SetNX(ctx context.Context, key string, value interface{}, expiration time.Duration) (bool, error)
Incr(ctx context.Context, key string) (int64, error)
Del(ctx context.Context, keys ...string) (int64, error)
}You can implement this interface with any Redis client library of your choice (such as go-redis, redigo, rueidis, goredis/redismock for testing, etc.) and pass your custom implementation to the builder:
type MyCustomRedisClient struct {
// Your Redis client implementation using your preferred library
}
func (c *MyCustomRedisClient) SetNX(ctx context.Context, key string, value interface{}, expiration time.Duration) (bool, error) {
// Implementation using your preferred Redis client library
}
func (c *MyCustomRedisClient) Incr(ctx context.Context, key string) (int64, error) {
// Implementation using your preferred Redis client library
}
func (c *MyCustomRedisClient) Del(ctx context.Context, keys ...string) (int64, error) {
// Implementation using your preferred Redis client library
}
// Usage
customRedisClient := &MyCustomRedisClient{}
sf, err := snowflake.NewBuilder().
SetRedisClient(customRedisClient).
SetDatacenterID(1).
SetWorkerID(1).
Build()This approach provides flexibility to use different Redis client libraries based on your performance, feature, or dependency requirements. The default implementation uses go-redis, but you're not limited to it.
- In normal mode, ID generation is completely local after initialization. Redis is only used during setup to coordinate unique identifiers.
- In strict mode, Redis is additionally used during ID generation to provide an extra layer of duplicate prevention.