🛠️

Whiz Tools

Build • Create • Innovate

Enhanced Snowflake ID Generator for Distributed Systems

Hasilkan dan analisis ID Snowflake Twitter, pengenal unik 64-bit yang digunakan dalam sistem terdistribusi. Alat ini memungkinkan Anda untuk membuat ID Snowflake baru dan mengurai yang sudah ada, memberikan wawasan tentang komponen timestamp, ID mesin, dan nomor urutnya.

Generator ID Snowflake

Generator ID Snowflake

Optional: Unix timestamp in milliseconds (defaults to current time)
📚

Dokumentasi

1## Snowflake ID Generator
2
3### Introduction
4
5Snowflake ID adalah pengenal unik yang digunakan dalam sistem terdistribusi, awalnya dikembangkan oleh Twitter. Alat ini memungkinkan Anda untuk menghasilkan dan menganalisis Snowflake ID, yang merupakan bilangan bulat 64-bit yang terdiri dari timestamp, ID mesin, dan nomor urut.
6
7### How Snowflake IDs Work
8
9Snowflake ID adalah bilangan bulat 64-bit yang terstruktur sebagai berikut:
10
11- 41 bit: Timestamp (milidetik sejak epoch khusus)
12- 10 bit: ID Mesin (5 bit untuk ID pusat data, 5 bit untuk ID pekerja)
13- 12 bit: Nomor urut
14
15Struktur ini memungkinkan untuk menghasilkan sekitar 4.096 ID unik per milidetik per mesin.
16
17### Using the Snowflake ID Generator
18
191. (Opsional) Atur epoch khusus (default adalah epoch Twitter: 2010-11-04T01:42:54.657Z)
202. Masukkan ID mesin (0-31) dan ID pusat data (0-31)
213. Klik "Generate" untuk membuat Snowflake ID baru
224. ID yang dihasilkan dan komponennya akan ditampilkan
23
24Untuk mengurai Snowflake ID yang ada, masukkan di kolom "Parse ID" dan klik "Parse".
25
26### Formula
27
28Snowflake ID dibangun menggunakan operasi bitwise:
29
30

plaintext ID = (timestamp << 22) | (datacenterId << 17) | (workerId << 12) | sequence

1
2Dimana:
3- `timestamp` adalah jumlah milidetik sejak epoch
4- `datacenterId` adalah bilangan bulat 5-bit (0-31)
5- `workerId` adalah bilangan bulat 5-bit (0-31)
6- `sequence` adalah bilangan bulat 12-bit (0-4095)
7
8### Calculation
9
10Generator Snowflake ID melakukan langkah-langkah berikut:
11
121. Dapatkan timestamp saat ini dalam milidetik
132. Pastikan timestamp lebih besar dari timestamp terakhir yang digunakan (untuk keunikan)
143. Jika timestamp sama dengan yang terakhir, tingkatkan nomor urut
154. Jika nomor urut meluap (mencapai 4096), tunggu milidetik berikutnya
165. Gabungkan komponen menggunakan operasi bitwise untuk membuat ID akhir
17
18### Use Cases
19
20Snowflake ID sangat berguna dalam:
21
221. Sistem Terdistribusi: Menghasilkan ID unik di beberapa mesin tanpa koordinasi
232. Data Volume Tinggi: Membuat ID yang dapat diurutkan untuk dataset besar
243. Microservices: Memastikan pengenal unik di berbagai layanan
254. Pembagian Basis Data: Menggunakan komponen timestamp atau ID mesin untuk pembagian yang efisien
26
27#### Alternatives
28
29Meskipun Snowflake ID sangat kuat, sistem penghasil ID lainnya termasuk:
30
311. UUID (Universally Unique Identifier): Berguna ketika diperlukan generasi terdistribusi tanpa keterurutan
322. ID basis data auto-increment: Sederhana tetapi terbatas pada satu instance basis data
333. ULID (Universally Unique Lexicographically Sortable Identifier): Mirip dengan Snowflake, tetapi dengan struktur yang berbeda
34
35### Edge Cases and Limitations
36
371. Sinkronisasi Jam: Snowflake ID bergantung pada waktu sistem. Jika jam bergerak mundur karena penyesuaian NTP atau perubahan waktu musim panas, ini dapat menyebabkan masalah dalam generasi ID.
38
392. Masalah Tahun 2038: Timestamp 41-bit akan meluap pada tahun 2079 (dengan asumsi epoch Twitter). Sistem yang menggunakan Snowflake ID harus merencanakan kemungkinan ini.
40
413. Kolisi ID Mesin: Dalam sistem terdistribusi yang besar, memastikan ID mesin yang unik bisa menjadi tantangan dan mungkin memerlukan koordinasi tambahan.
42
434. Meluapnya Urutan: Dalam skenario throughput yang sangat tinggi, mungkin saja untuk menghabiskan 4096 urutan per milidetik, yang dapat menyebabkan keterlambatan.
44
455. Non-monotonisitas di Antara Mesin: Meskipun ID meningkat secara monoton pada satu mesin, mereka mungkin tidak sepenuhnya monoton di antara beberapa mesin.
46
47### History
48
49Snowflake ID diperkenalkan oleh Twitter pada tahun 2010 untuk mengatasi kebutuhan akan pengenal unik yang terdistribusi dan dapat diurutkan berdasarkan waktu. Sejak itu, mereka telah diadopsi dan diadaptasi oleh banyak perusahaan dan proyek lainnya.
50
51### Examples
52
53Berikut adalah implementasi generator Snowflake ID dalam berbagai bahasa:
54
55

javascript class SnowflakeGenerator { constructor(epoch = 1288834974657, datacenterIdBits = 5, workerIdBits = 5, sequenceBits = 12) { this.epoch = BigInt(epoch); this.datacenterIdBits = datacenterIdBits; this.workerIdBits = workerIdBits; this.sequenceBits = sequenceBits; this.maxDatacenterId = -1n ^ (-1n << BigInt(datacenterIdBits)); this.maxWorkerId = -1n ^ (-1n << BigInt(workerIdBits)); this.sequenceMask = -1n ^ (-1n << BigInt(sequenceBits)); this.workerIdShift = BigInt(sequenceBits); this.datacenterIdShift = BigInt(sequenceBits + workerIdBits); this.timestampLeftShift = BigInt(sequenceBits + workerIdBits + datacenterIdBits); this.sequence = 0n; this.lastTimestamp = -1n; }

nextId(datacenterId, workerId) { let timestamp = this.currentTimestamp();

if (timestamp < this.lastTimestamp) {
  throw new Error('Clock moved backwards. Refusing to generate id');
}

if (timestamp === this.lastTimestamp) {
  this.sequence = (this.sequence + 1n) & this.sequenceMask;
  if (this.sequence === 0n) {
    timestamp = this.tilNextMillis(this.lastTimestamp);
  }
} else {
  this.sequence = 0n;
}

this.lastTimestamp = timestamp;

return ((timestamp - this.epoch) << this.timestampLeftShift) |
       (BigInt(datacenterId) << this.datacenterIdShift) |
       (BigInt(workerId) << this.workerIdShift) |
       this.sequence;

}

tilNextMillis(lastTimestamp) { let timestamp = this.currentTimestamp(); while (timestamp <= lastTimestamp) { timestamp = this.currentTimestamp(); } return timestamp; }

currentTimestamp() { return BigInt(Date.now()); } }

// Usage const generator = new SnowflakeGenerator(); const id = generator.nextId(1, 1); console.log(Generated Snowflake ID: ${id});

1
2

python import time import threading

class SnowflakeGenerator: def init(self, datacenter_id, worker_id, sequence=0): self.datacenter_id = datacenter_id self.worker_id = worker_id self.sequence = sequence

    self.last_timestamp = -1
    self.epoch = 1288834974657

    self.datacenter_id_bits = 5
    self.worker_id_bits = 5
    self.sequence_bits = 12

    self.max_datacenter_id = -1 ^ (-1 << self.datacenter_id_bits)
    self.max_worker_id = -1 ^ (-1 << self.worker_id_bits)

    self.worker_id_shift = self.sequence_bits
    self.datacenter_id_shift = self.sequence_bits + self.worker_id_bits
    self.timestamp_left_shift = self.sequence_bits + self.worker_id_bits + self.datacenter_id_bits
    self.sequence_mask = -1 ^ (-1 << self.sequence_bits)

    self._lock = threading.Lock()

def _til_next_millis(self, last_timestamp):
    timestamp = self._get_timestamp()
    while timestamp <= last_timestamp:
        timestamp = self._get_timestamp()
    return timestamp

def _get_timestamp(self):
    return int(time.time() * 1000)

def next_id(self):
    with self._lock:
        timestamp = self._get_timestamp()

        if timestamp < self.last_timestamp:
            raise ValueError("Clock moved backwards. Refusing to generate id")

        if timestamp == self.last_timestamp:
            self.sequence = (self.sequence + 1) & self.sequence_mask
            if self.sequence == 0:
                timestamp = self._til_next_millis(self.last_timestamp)
        else:
            self.sequence = 0

        self.last_timestamp = timestamp

        return ((timestamp - self.epoch) << self.timestamp_left_shift) | \
               (self.datacenter_id << self.datacenter_id_shift) | \
               (self.worker_id << self.worker_id_shift) | \
               self.sequence

Usage

generator = SnowflakeGenerator(datacenter_id=1, worker_id=1) snowflake_id = generator.next_id() print(f"Generated Snowflake ID: {snowflake_id}")

1
2

java import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock;

public class SnowflakeGenerator { private final long epoch; private final long datacenterIdBits; private final long workerIdBits; private final long sequenceBits; private final long maxDatacenterId; private final long maxWorkerId; private final long workerIdShift; private final long datacenterIdShift; private final long timestampLeftShift; private final long sequenceMask;

private long datacenterId;
private long workerId;
private long sequence = 0L;
private long lastTimestamp = -1L;

private final Lock lock = new ReentrantLock();

public SnowflakeGenerator(long datacenterId, long workerId) {
    this.epoch = 1288834974657L;
    this.datacenterIdBits = 5L;
    this.workerIdBits = 5L;
    this.sequenceBits = 12L;

    this.maxDatacenterId = ~(-1L << datacenterIdBits);
    this.maxWorkerId = ~(-1L << workerIdBits);

    this.workerIdShift = sequenceBits;
    this.datacenterIdShift = sequenceBits + workerIdBits;
    this.timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
    this.sequenceMask = ~(-1L << sequenceBits);

    if (datacenterId > maxDatacenterId || datacenterId < 0) {
        throw new IllegalArgumentException("datacenterId can't be greater than maxDatacenterId or less than 0");
    }
    if (workerId > maxWorkerId || workerId < 0) {
        throw new IllegalArgumentException("workerId can't be greater than maxWorkerId or less than 0");
    }
    this.datacenterId = datacenterId;
    this.workerId = workerId;
}

public long nextId() {
    lock.lock();
    try {
        long timestamp = timeGen();
        if (timestamp < lastTimestamp) {
            throw new RuntimeException("Clock moved backwards. Refusing to generate id");
        }

        if (lastTimestamp == timestamp) {
            sequence = (sequence + 1) & sequenceMask;
            if (sequence == 0) {
                timestamp = tilNextMillis(lastTimestamp);
            }
        } else {
            sequence = 0L;
        }

        lastTimestamp = timestamp;

        return ((timestamp - epoch) << timestampLeftShift) |
               (datacenterId << datacenterIdShift) |
               (workerId << workerIdShift) |
               sequence;
    } finally {
        lock.unlock();
    }
}

private long tilNextMillis(long lastTimestamp) {
    long timestamp = timeGen();
    while (timestamp <= lastTimestamp) {
        timestamp = timeGen();
    }
    return timestamp;
}

private long timeGen() {
    return System.currentTimeMillis();
}

public static void main(String[] args) {
    SnowflakeGenerator generator = new SnowflakeGenerator(1, 1);
    long id = generator.nextId();
    System.out.println("Generated Snowflake ID: " + id);
}

}

1
2

ruby require 'time'

class SnowflakeGenerator def initialize(datacenter_id, worker_id, sequence = 0) @datacenter_id = datacenter_id @worker_id = worker_id @sequence = sequence @last_timestamp = -1 @epoch = 1288834974657 @datacenter_id_bits = 5 @worker_id_bits = 5 @sequence_bits = 12 @max_datacenter_id = -1 ^ (-1 << @datacenter_id_bits) @max_worker_id = -1 ^ (-1 << @worker_id_bits) @worker_id_shift = @sequence_bits @datacenter_id_shift = @sequence_bits + @worker_id_bits @timestamp_left_shift = @sequence_bits + @worker_id_bits + @datacenter_id_bits @sequence_mask = -1 ^ (-1 << @sequence_bits) end

def next_id timestamp = (Time.now.to_f * 1000).to_i raise 'Clock moved backwards' if timestamp < @last_timestamp

if timestamp == @last_timestamp
  @sequence = (@sequence + 1) & @sequence_mask
  timestamp = til_next_millis(@last_timestamp) if @sequence == 0
else
  @sequence = 0
end

@last_timestamp = timestamp

((timestamp - @epoch) << @timestamp_left_shift) |
  (@datacenter_id << @datacenter_id_shift) |
  (@worker_id << @worker_id_shift) |
  @sequence

end

private

def til_next_millis(last_timestamp) timestamp = (Time.now.to_f * 1000).to_i timestamp = (Time.now.to_f * 1000).to_i while timestamp <= last_timestamp timestamp end end

Usage

generator = SnowflakeGenerator.new(1, 1) snowflake_id = generator.next_id puts "Generated Snowflake ID: #{snowflake_id}"

1
2

php

epoch = 1288834974657; $this->datacenterIdBits = 5; $this->workerIdBits = 5; $this->sequenceBits = 12; $this->maxDatacenterId = -1 ^ (-1 << $this->datacenterIdBits); $this->maxWorkerId = -1 ^ (-1 << $this->workerIdBits); $this->workerIdShift = $this->sequenceBits; $this->datacenterIdShift = $this->sequenceBits + $this->workerIdBits; $this->timestampLeftShift = $this->sequenceBits + $this->workerIdBits + $this->datacenterIdBits; $this->sequenceMask = -1 ^ (-1 << $this->sequenceBits); if ($datacenterId > $this->maxDatacenterId || $datacenterId < 0) { throw new Exception("datacenterId can't be greater than maxDatacenterId or less than 0"); } if ($workerId > $this->maxWorkerId || $workerId < 0) { throw new Exception("workerId can't be greater than maxWorkerId or less than 0"); } $this->datacenterId = $datacenterId; $this->workerId = $workerId; } public function nextId() { $timestamp = $this->timeGen(); if ($timestamp < $this->lastTimestamp) { throw new Exception("Clock moved backwards. Refusing to generate id"); } if ($this->lastTimestamp == $timestamp) { $this->sequence = ($this->sequence + 1) & $this->sequenceMask; if ($this->sequence == 0) { $timestamp = $this->tilNextMillis($this->lastTimestamp); } } else { $this->sequence = 0; } $this->lastTimestamp = $timestamp; return (($timestamp - $this->epoch) << $this->timestampLeftShift) | ($this->datacenterId << $this->datacenterIdShift) | ($this->workerId << $this->workerIdShift) | $this->sequence; } private function tilNextMillis($lastTimestamp) { $timestamp = $this->timeGen(); while ($timestamp <= $lastTimestamp) { $timestamp = $this->timeGen(); } return $timestamp; } private function timeGen() { return floor(microtime(true) * 1000); } } // Usage $generator = new SnowflakeGenerator(1, 1); $id = $generator->nextId(); echo "Generated Snowflake ID: " . $id . "\n";
1
2

csharp using System; using System.Threading;

public class SnowflakeGenerator { private readonly long _epoch; private readonly int _datacenterIdBits; private readonly int _workerIdBits; private readonly int _sequenceBits; private readonly long _maxDatacenterId; private readonly long _maxWorkerId; private readonly int _workerIdShift; private readonly int _datacenterIdShift; private readonly int _timestampLeftShift; private readonly long _sequenceMask;

private readonly long _datacenterId;
private readonly long _workerId;
private long _sequence = 0L;
private long _lastTimestamp = -1L;

private readonly object _lock = new object();

public SnowflakeGenerator(long datacenterId, long workerId)
{
    _epoch = 1288834974657L;
    _datacenterIdBits = 5;
    _workerIdBits = 5;
    _sequenceBits = 12;

    _maxDatacenterId = -1L ^ (-1L << _datacenterIdBits);
    _maxWorkerId = -1L ^ (-1L << _workerIdBits);

    _workerIdShift = _sequenceBits;
    _datacenterIdShift = _sequenceBits + _workerIdBits;
    _timestampLeftShift = _sequenceBits + _workerIdBits + _datacenterIdBits;
    _sequenceMask = -1L ^ (-1L << _sequenceBits);

    if (datacenterId > _maxDatacenterId || datacenterId < 0)
    {
        throw new ArgumentException($"datacenterId can't be greater than {_maxDatacenterId} or less than 0");
    }
    if (workerId > _maxWorkerId || workerId < 0)
    {
        throw new ArgumentException($"workerId can't be greater than {_maxWorkerId} or less than 0");
    }
    _datacenterId = datacenterId;
    _workerId = workerId;
}

public long NextId()
{
    lock (_lock)
    {
        var timestamp = TimeGen();

        if (timestamp < _lastTimestamp)
        {
            throw new Exception("Clock moved backwards. Refusing to generate id");
        }

        if (_lastTimestamp == timestamp)
        {
            _sequence = (_sequence + 1) & _sequenceMask;
            if (_sequence == 0)
            {
                timestamp = TilNextMillis(_lastTimestamp);
            }
        }
        else
        {
            _sequence = 0L;
        }

        _lastTimestamp = timestamp;

        return ((timestamp - _epoch) << _timestampLeftShift) |
               (_datacenterId << _datacenterIdShift) |
               (_workerId << _workerIdShift) |
               _sequence;
    }
}

private long TilNextMillis(long lastTimestamp)
{
    var timestamp = TimeGen();
    while (timestamp <= lastTimestamp)
    {
        timestamp = TimeGen();
    }
    return timestamp;
}

private long TimeGen()
{
    return DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
}

}

// Usage class Program { static void Main(string[] args) { var generator = new SnowflakeGenerator(1, 1); var id = generator.NextId(); Console.WriteLine($"Generated Snowflake ID: {id}"); } }

1
2

go package main

import ( "fmt" "sync" "time" )

type SnowflakeGenerator struct { epoch int64 datacenterIdBits uint workerIdBits uint sequenceBits uint maxDatacenterId int64 maxWorkerId int64 workerIdShift uint datacenterIdShift uint timestampLeftShift uint sequenceMask int64

datacenterId int64
workerId     int64
sequence     int64
lastTimestamp int64

lock sync.Mutex

}

func NewSnowflakeGenerator(datacenterId, workerId int64) (*SnowflakeGenerator, error) { g := &SnowflakeGenerator{ epoch: 1288834974657, datacenterIdBits: 5, workerIdBits: 5, sequenceBits: 12, lastTimestamp: -1, }

g.maxDatacenterId = -1 ^ (-1 << g.datacenterIdBits)
g.maxWorkerId = -1 ^ (-1 << g.workerIdBits)

g.workerIdShift = g.sequenceBits
g.datacenterIdShift = g.sequenceBits + g.workerIdBits
g.timestampLeftShift = g.sequenceBits + g.workerIdBits + g.datacenterIdBits
g.sequenceMask = -1 ^ (-1 << g.sequenceBits)

if datacenterId > g.maxDatacenterId || datacenterId < 0 {
	return nil, fmt.Errorf("datacenterId can't be greater than %d or less than 0", g.maxDatacenterId)
}
if workerId > g.maxWorkerId || workerId < 0 {
	return nil, fmt.Errorf("workerId can't be greater than %d or less than 0", g.maxWorkerId)
}
g.datacenterId = datacenterId
g.workerId = workerId

return g, nil

}

func (g *SnowflakeGenerator) NextId() (int64, error) { g.lock.Lock() defer g.lock.Unlock()

timestamp := g.timeGen()

if timestamp < g.lastTimestamp {
	return 0, fmt.Errorf("clock moved backwards, refusing to generate id")
}

if g.lastTimestamp == timestamp {
	g.sequence = (g.sequence + 1) & g.sequenceMask
	if g.sequence == 0 {
		timestamp = g.tilNextMillis(g.lastTimestamp)
	}
} else {
	g.sequence = 0
}

g.lastTimestamp = timestamp

return ((timestamp - g.epoch) << g.timestampLeftShift) |
	(g.datacenterId << g.datacenterIdShift) |
	(g.workerId << g.workerIdShift) |
	g.sequence, nil

}

func (g *SnowflakeGenerator) tilNextMillis(lastTimestamp int64) int64 { timestamp := g.timeGen() for timestamp <= lastTimestamp { timestamp = g.timeGen() } return timestamp }

func (g *SnowflakeGenerator) timeGen() int64 { return time.Now().UnixNano() / int64(time.Millisecond) }

func main() { generator, err := NewSnowflakeGenerator(1, 1) if err != nil { fmt.Printf("Error creating generator: %v\n", err) return }

id, err := generator.NextId()
if err != nil {
	fmt.Printf("Error generating ID: %v\n", err)
	return
}

fmt.Printf("Generated Snowflake ID: %d\n", id)

}

1
2### Diagram
3
4Berikut adalah representasi visual dari struktur Snowflake ID:
5
6<svg width="600" height="100" xmlns="http://www.w3.org/2000/svg">
7  <rect x="0" y="0" width="380" height="50" fill="#4299e1"/>
8  <text x="190" y="30" font-family="Arial" fontSize="14" fill="white" textAnchor="middle">Timestamp (41 bit)</text>
9  
10  <rect x="380" y="0" width="90" height="50" fill="#48bb78"/>
11  <text x="425" y="30" font-family="Arial" fontSize="14" fill="white" textAnchor="middle">ID Mesin (10 bit)</text>
12  
13  <rect x="470" y="0" width="130" height="50" fill="#ed8936"/>
14  <text x="535" y="30" font-family="Arial" fontSize="14" fill="white" textAnchor="middle">Urutan (12 bit)</text>
15  
16  <text x="300" y="80" font-family="Arial" fontSize="16" fill="black" textAnchor="middle">Struktur Snowflake ID 64-bit</text>
17</svg>
18
19### References
20
211. "Mengumumkan Snowflake." Blog Teknik Twitter, https://blog.twitter.com/engineering/en_us/a/2010/announcing-snowflake
222. "Snowflake ID." Wikipedia, https://en.wikipedia.org/wiki/Snowflake_ID
233. "Generasi ID Terdistribusi dalam Microservices." Medium, https://medium.com/swlh/distributed-id-generation-in-microservices-b6ce9a8dd93f
24