A distributed unique ID generator inspired by Twitter's Snowflake

Sonyflake

GoDoc Build Status Coverage Status Go Report Card

Sonyflake is a distributed unique ID generator inspired by Twitter's Snowflake.

Sonyflake focuses on lifetime and performance on many host/core environment. So it has a different bit assignment from Snowflake. A Sonyflake ID is composed of

39 bits for time in units of 10 msec
 8 bits for a sequence number
16 bits for a machine id

As a result, Sonyflake has the following advantages and disadvantages:

  • The lifetime (174 years) is longer than that of Snowflake (69 years)
  • It can work in more distributed machines (2^16) than Snowflake (2^10)
  • It can generate 2^8 IDs per 10 msec at most in a single machine/thread (slower than Snowflake)

However, if you want more generation rate in a single host, you can easily run multiple Sonyflake ID generators concurrently using goroutines.

Installation

go get github.com/sony/sonyflake

Usage

The function NewSonyflake creates a new Sonyflake instance.

func NewSonyflake(st Settings) *Sonyflake

You can configure Sonyflake by the struct Settings:

type Settings struct {
	StartTime      time.Time
	MachineID      func() (uint16, error)
	CheckMachineID func(uint16) bool
}
  • StartTime is the time since which the Sonyflake time is defined as the elapsed time. If StartTime is 0, the start time of the Sonyflake is set to "2014-09-01 00:00:00 +0000 UTC". If StartTime is ahead of the current time, Sonyflake is not created.

  • MachineID returns the unique ID of the Sonyflake instance. If MachineID returns an error, Sonyflake is not created. If MachineID is nil, default MachineID is used. Default MachineID returns the lower 16 bits of the private IP address.

  • CheckMachineID validates the uniqueness of the machine ID. If CheckMachineID returns false, Sonyflake is not created. If CheckMachineID is nil, no validation is done.

In order to get a new unique ID, you just have to call the method NextID.

func (sf *Sonyflake) NextID() (uint64, error)

NextID can continue to generate IDs for about 174 years from StartTime. But after the Sonyflake time is over the limit, NextID returns an error.

AWS VPC and Docker

The awsutil package provides the function AmazonEC2MachineID that returns the lower 16-bit private IP address of the Amazon EC2 instance. It also works correctly on Docker by retrieving instance metadata.

AWS VPC is assigned a single CIDR with a netmask between /28 and /16. So if each EC2 instance has a unique private IP address in AWS VPC, the lower 16 bits of the address is also unique. In this common case, you can use AmazonEC2MachineID as Settings.MachineID.

See example that runs Sonyflake on AWS Elastic Beanstalk.

License

The MIT License (MIT)

See LICENSE for details.

Owner
Sony
Sony Corporation
Sony
Comments
  • Introduce mocking framework and increase coverage

    Introduce mocking framework and increase coverage

    This change introduces three common Golang patterns to the SonyFlake project test framework:

    • types: this will allow fine-tuned control over imported types by defining how they will be used, project-wide

    • mock: this allows the generation of mock constructors, which lends itself to testing any individual path in a function by "injecting" a mock object which matches the expected type

    • array-based-testing: privateIPv4 and lower16BitPrivateIP were lacking tests for their error paths, but using types and mocks, I was able add two array-based tests that cover all test cases for these methods

    This change also increases test coverage to 💯, while adding no additional time for testing ⌛ .

    This is a really cool project, and I'd be happy to contribute more!

  • Is it practical to implement sonyflake in RDBMS like MySQL, Postgres?

    Is it practical to implement sonyflake in RDBMS like MySQL, Postgres?

    Just curious to know, how practical is it to limit generation of 2^8 (256) unique IDs per 10ms on databases. Can someone please explain me with example like if I have 4GB RAM to 16GB RAM database instance, how many insert load I can expect to be handled by that server?

    It will help me use sonyflake as id generation at database level.

  • Are Sonyflakes strings always guaranteed to be in order and the same length?

    Are Sonyflakes strings always guaranteed to be in order and the same length?

    Hi!

    We would like to know if sonyflakes generated from now are a guaranteed sort order and if not then when is the next time that length will change. We have noticed an issue in our database where our sort order is being ill-computed based on that we sometimes store sonyflakes as strings. Could you kindly affirm whether the length of a sonyflake string can change? Or is there a guaranteed length.

    In particular the following algorithm...

    l = [
        "1",
        "9999",
        "2",
        "10000",
        "3",
        "4",
        "999",
        "6",
        "7",
        "8",
        "9",
        "5",
        "10",
        "100",
        "1000",
        "90",
    ]
    
    print(l)
    l.sort()
    print(l)
    

    Shows that say the number 2 > 1000000000000000 when doing string comparison. I would like to know how Sonyflakes generated reliably are affected by this as the impact of this could affect the sort ordering for some production data (may require migration). Due to the algorithmic complexity of the Sonyflake and how its generated (sonyflakes are always the same length I believe) I'm not sure if we would be impacted by this in the near future.

    Go example

    package main
    
    import (
        "fmt"
        "sort"
    )
    
    func main() {
        sl := []string{"1", "9999", "2", "10000", "3", "4", "999", "6", "7", "8", "9", "5", "10", "100", "1000", "90"}
        fmt.Println(sl)
        sort.Strings(sl)
        fmt.Println(sl)
    }
    

    I appreciate that this is not your concern and represents a mistake made in our systems, however I would appreciate any help on the matter. It would be helpful if I can run unit tests locally to generate snowflake now to the range generate one years in the future, but I have no idea how to adjust the snowflake without changing my system time like this. Appreciate the easiest way to diagnose the impact!

  • Is it possible to have a method which returns the timestamp/metadata used to create the sonyflake?

    Is it possible to have a method which returns the timestamp/metadata used to create the sonyflake?

    Hi,

    Thanks for the library. It would be nice to get the time{} struct the sonyflake is based off so that implementing services can prevent drift between recording current time and time allocated to the sonyFlake.

    Please let me know if this is something you can do.

    Cheers!

  • add benchmarks

    add benchmarks

    $ go test  -bench=.
    sonyflake id: 838861161
    decompose: map[id:838861161 machine-id:361 msb:0 sequence:0 time:50]
    max sequence: 255
    number of id: 256000
    number of cpu: 8
    number of id: 100000
    goos: linux
    goarch: amd64
    pkg: github.com/sony/sonyflake
    BenchmarkNextID-8            	   50000	     38984 ns/op
    --- FAIL: BenchmarkNextID_validate
        sonyflake_test.go:205: NextID returned err:over the time limit
    FAIL
    exit status 1
    FAIL	github.com/sony/sonyflake	16.740s
    
  • Fix ineffassign error

    Fix ineffassign error

    Fix ineffassign error. And, add a badge image.


    % pwd
    /path/to/sonyflake
    
    % ineffassign .
    /path/to/sonyflake/awsutil/awsutil.go:59:5: err assigned and not used
    
  • How do you use the timestamp extracted from the id?

    How do you use the timestamp extracted from the id?

    Seems like when I try to use the sonyflake.Decompose on the generated ID, I get a timestamp which is similar to 24869724975. How can I convert this into an epoch timestamp so a I can sort by date in the DB? What I need is to be able to generate a timestamp from the current date and compare to the timestamps stored in the DBs as primary keys

  • Question: uint64 or int64?

    Question: uint64 or int64?

    From the README, sonyflake uses 63 bits. This aligns with the design of Snowflake ID, which is specifically designed to fit in a signed integer:

    Snowflakes are 64 bits. (Only 63 are used to fit in a signed integer.)

    I notice that sonyflake returns uint64 rather than int64:

    https://github.com/sony/sonyflake/blob/848d664ceea4c980874f2135c85c42409c530b1f/sonyflake.go#L86

    Should it return int64, instead?

    I assume not since it has been around for a while. If that's correct, perhaps some documentation could be added to describe how to safely convert the value into an int64 so that it might more easily be used in databases that don't support uint?

  • Add DecomposeToBuffer() API to avoid allocating a map on hot paths

    Add DecomposeToBuffer() API to avoid allocating a map on hot paths

    Allocating a map[string]uint64 can be very expensive if called from a hot loop. Add a new function DecomposeToBuffer() that writes the ID components into a struct. The new function is implicitly covered by the existing tests because Decompose() uses it under the covers.

  • is it safe for PostgreSQL bigint

    is it safe for PostgreSQL bigint

    I see that it leaves most significant bit unused. That shall make it safe for use with 64 bit signed integer, because it will never go into the negative range from DB perspective (and will stay sortable).

    Am I reading it right?

  • Add sortable test

    Add sortable test

    TestSortableID will test if the generated ID is always sortable even when you run in Go routine. So, if you have a system that needs to generate id in application level in a thread, the generated ID can be sorted by those generated ids. Sorted by ID will resemble like sorted by time. And SonyFlake id resembles increment id in the database when you want to sort it.

  • AWS Lambda

    AWS Lambda

    I'd like to use this code in an AWS Lambda. Is it possible to get a unique 16 bit id for the lambda instance it is running in? The equivalent of AmazonEC2MachineID() but for Lambdas.

    As I understand it - Lambda's are limited to 1000 instances - so if we could get something like a "slot" number, ir a unique number from 0 to 999, 1 to 1000 etc - that would be even better and we could reduce the size of the server id field.

    @yuokada (or anyone) please let me know if this is possible. I would pay for help with this.

  • Add NewReproducibleID()

    Add NewReproducibleID()

    For build systems, unit tests, research, and a range of other contexts it is useful to be able to generate reproducible IDs. Similar to controlling the random seed of a RNG. This branch adds a new method NextReproducibleID() with this feature.

    Thanks for an awesome library :-)

Snowflake - Simple twitter's snowflake uniquely identifiable descriptors (IDs) format generator for Go

Snowflake Dead simple and fast Twitter's snowflake id generator in Go. Installation go get github.com/HotPotatoC/snowflake Usage Generating a snowflak

Oct 6, 2022
Snowflake grafana datasource plugin allows Snowflake data to be visually represented in Grafana dashboards.
Snowflake grafana datasource plugin allows Snowflake data to be visually represented in Grafana dashboards.

Snowflake Grafana Data Source With the Snowflake plugin, you can visualize your Snowflake data in Grafana and build awesome chart. Get started with th

Dec 29, 2022
Snowflake - An implement of snowflake by go, use atomic instead of mutex

snowflake an implement of snowflake by go, use atomic instead of mutex 雪花算法的一种go

Feb 4, 2022
Snowflake - A simple to use Go (golang) package to generate or parse Twitter snowflake IDs
Snowflake - A simple to use Go (golang) package to generate or parse Twitter snowflake IDs

❄️ Go-Snowflake A Snowflake Generator for Go A simple to use Go (golang) package

Oct 20, 2022
✨ Generate unique IDs (Port of Node package "generate-snowflake" to Golang)

✨ Generate Snowflake Generate unique IDs. Inspired by Twitter's Snowflake system. ?? Installation Initialize your project (go mod init example.com/exa

Feb 11, 2022
A distributed unique ID generator of using Sonyflake and encoded by Base58

Indigo About A distributed unique ID generator of using Sonyflake and encoded by Base58. ID max length is 11 characters by unsigned int64 max value. A

Nov 24, 2022
❄ An Lock Free ID Generator for Golang based on Snowflake Algorithm (Twitter announced).
❄ An Lock Free ID Generator for Golang based on Snowflake Algorithm (Twitter announced).

❄ An Lock Free ID Generator for Golang based on Snowflake Algorithm (Twitter announced).

Dec 14, 2022
A tiny and fast Go unique string generator

Nano ID A tiny and fast Go unique string generator Safe. It uses cryptographically strong random APIs and tests distribution of symbols. Compact. It u

Nov 11, 2022
High performance unique number generator powered by Go

SEQSVR High performance unique number generator powered by Go 中文 README Features Distributed: Can be scaled horizontally High performance: Allocation

Nov 16, 2022
Tarmac is a unique framework designed for the next generation of distributed systems
Tarmac is a unique framework designed for the next generation of distributed systems

Framework for building distributed services with Web Assembly

Dec 31, 2022
Distributed-Services - Distributed Systems with Golang to consequently build a fully-fletched distributed service

Distributed-Services This project is essentially a result of my attempt to under

Jun 1, 2022
A simple to use Go (golang) package to generate or parse Twitter snowflake IDs

snowflake snowflake is a Go package that provides A very simple Twitter snowflake generator. Methods to parse existing snowflake IDs. Methods to conve

Dec 30, 2022
Golang wrapper for the Snowflake Api.

GoSnowflakeApi GoSnowflakeApi is an api wrapper for the snowflake api written in golang for golang developers. Example package main import ( "fmt

Jul 25, 2021
Snowflake By Go.

snow Snowflake by Go. package main import "github.com/czasg/snow" func main() { // default WorkID & DataCenterID is 0. snowID := snow.Next()

Dec 4, 2022
Snowflake implemented in GO (Golang)

snowflake Snowflake is a fast, goroutine-safe unique ID generator built for distributed systems Key concepts Snowflake Snowflakes are int64s. uint64 i

Oct 27, 2022
Snowflake algorithm generation worker Id sequence

sequence snowflake algorithm generation worker Id sequence 使用雪花算法生成ID,生成100万个只需要

Jan 21, 2022
Super short, fully unique, non-sequential and URL friendly Ids

Generator of unique non-sequential short Ids The package shortidenables the generation of short, fully unique, non-sequential and by default URL frien

Dec 30, 2022
Compact, sortable and fast unique IDs with embedded metadata.
Compact, sortable and fast unique IDs with embedded metadata.

A spec for unique IDs in distributed systems based on the Snowflake design, i.e. a coordination-based ID variant. It aims to be friendly to both machi

Dec 22, 2022
Universally Unique Lexicographically Sortable Identifier (ULID) in Go

Universally Unique Lexicographically Sortable Identifier A Go port of alizain/ulid with binary format implemented. Background A GUID/UUID can be subop

Jan 9, 2023
Dec 28, 2022