Distributed Unique Identifier Generator: Algoritma & Sistem

Distributed Unique Identifier Generator adalah komponen arsitektur perangkat lunak yang menghasilkan ID unik secara global di berbagai node, server, atau pusat data tanpa koordinasi terpusat yang ketat. Dalam sistem terdistribusi skala besar, penggunaan basis data monolitik dengan fitur auto-increment menjadi hambatan performa dan titik kegagalan tunggal (single point of failure). Oleh karena itu, diperlukan algoritma yang mampu memproduksi ID unik, berurutan secara kronologis, dan berkinerja tinggi secara independen pada setiap instance aplikasi.

Pemilihan algoritma ID generator sangat menentukan skalabilitas sistem penyimpanan data, performa pengindeksan database (indexing), dan konsistensi data lintas layanan mikro (microservices). Pendekatan yang salah dapat menyebabkan benturan ID (collision), fragmentasi indeks B-Tree yang menurunkan kecepatan tulis database, atau kebocoran informasi waktu pembuatan data.

Perbandingan Algoritma Distributed Identifier

Tabel berikut menyajikan perbandingan teknis dari berbagai metode pembangkitan ID terdistribusi yang umum digunakan dalam arsitektur modern.

Algoritma Panjang Format Urutan Waktu Risiko Collision Kasus Penggunaan Utama
UUID v4 128-bit (36 karakter hex) Tidak ada Sangat Rendah (Probabilistik) Primary key umum, token acak
Twitter Snowflake 64-bit (Angka desimal besar) Ya (Monotonik naik) Nol (dalam satu worker) Sistem high-throughput, chat, e-commerce
ULID 128-bit (26 karakter Crockford Base32) Ya Sangat Rendah Log, database primary key yang ramah URL
UUID v7 128-bit (36 karakter hex) Ya Sangat Rendah Standar baru pengganti UUID v4 dengan sortabilitas waktu

Implementasi Twitter Snowflake di Go

Algoritma Snowflake memecah ID 64-bit menjadi beberapa bagian: timestamp (41-bit), worker ID atau datacenter ID (10-bit), dan sequence number (12-bit). Berikut adalah contoh implementasi dasar logika pembuatan ID menggunakan bahasa Go.

package main

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

type Snowflake struct {
	mu        sync.Mutex
	epoch     int64
	workerID  int64
	sequence  int64
	lastTime  int64
}

func NewSnowflake(workerID int64) *Snowflake {
	return &Snowflake{
		epoch:    1609459200000, // 2021-01-01
		workerID: workerID,
		sequence: 0,
		lastTime: -1,
	}
}

func (s *Snowflake) NextID() (int64, error) {
	s.mu.Lock()
	defer s.mu.Unlock()

	now := time.Now().UnixMilli()

	if now < s.lastTime {
		return 0, fmt.Errorf("clock moved backwards")
	}

	if now == s.lastTime {
		s.sequence = (s.sequence + 1) & 4095
		if s.sequence == 0 {
			for now <= s.lastTime {
				now = time.Now().UnixMilli()
			}
		}
	} else {
		s.sequence = 0
	}

	s.lastTime = now

	id := ((now - s.epoch) << 22) | (s.workerID << 12) | s.sequence
	return id, nil
}

func main() {
	SF := NewSnowflake(1)
	id, _ := SF.NextID()
	fmt.Printf("Generated Snowflake ID: %d\n", id)
}

Panduan Teknis Pemilihan ID Generator

Dalam merancang sistem terdistribusi, perhatikan aspek-aspek teknis berikut untuk menghindari masalah pada performa database:

  • Indeks Database (B-Tree): Gunakan ID yang dapat diurutkan berdasarkan waktu (seperti Snowflake, UUID v7, atau ULID) untuk tabel berukuran besar. ID acak seperti UUID v4 menyebabkan seringnya terjadi pergeseran halaman memori (page splits) pada database relasional karena acaknya lokasi penyisipan data.
  • Keterbatasan Tipe Data: Pastikan bahasa pemrograman dan sistem database tujuan mendukung integer 64-bit secara penuh jika menggunakan format Snowflake. Beberapa bahasa pemrograman web lama mungkin mengalami kehilangan presisi angka (precision loss) pada tipe Number berbasis Float64 JSON (batas aman 2^53 - 1).
  • Sinkronisasi Waktu (NTP): Algoritma berbasis waktu sangat bergantung pada konsistensi jam sistem (NTP drift). Gunakan layanan sinkronisasi waktu yang ketat pada setiap server klaster untuk mencegah duplikasi ID akibat mundurnya waktu sistem.