Trong những hệ thống backend lớn như Twitter, Discord, hay Instagram, việc tạo ra một ID duy nhất toàn cầu (globally unique ID) cho hàng triệu bản ghi mỗi giây là một thách thức khổng lồ.

Nếu bạn vẫn đang dùng AUTO_INCREMENT trong MySQL hay ObjectId mặc định của MongoDB — thì bài viết này sẽ cho bạn thấy một cách tiếp cận khác: Snowflake ID.

1. Vấn đề với ID tự tăng (Auto Increment)

Trong các hệ thống đơn giản, việc tạo ID tự tăng (1, 2, 3, 4...) là điều quá quen thuộc. Nhưng khi hệ thống bắt đầu phân tán, mọi chuyện trở nên rối rắm.

Ví dụ:

  • Bạn có 10 máy chủ, mỗi máy có một instance của MySQL.

  • Nếu cả 10 máy cùng tạo bản ghi mới, làm sao để chắc chắn rằng không hai bản ghi nào có cùng ID?

Ta có thể gán mỗi máy một khoảng ID khác nhau (ví dụ máy 1 tạo 1–1000, máy 2 tạo 1001–2000…), nhưng cách này rất khó scaledễ lỗi khi thêm node mới.

Ngoài ra, AUTO_INCREMENT không thể hiện thời điểm tạo ID, cũng không cho biết máy nào tạo ra nó.

2. Snowflake ID là gì?

Snowflake là một cơ chế tạo ID 64-bit được Twitter phát triển để giải quyết bài toán trên.

Mục tiêu của nó:

  • Duy nhất toàn cầu.

  • Có thể sắp xếp theo thời gian (sortable).

  • Tạo độc lập trên nhiều node mà không cần database trung tâm.

  • Hiệu năng cực cao (hàng triệu ID/giây).

3. Cấu trúc của Snowflake ID

Một Snowflake ID gồm 64 bit, chia thành các phần như sau:

| 1 bit sign | 41 bits timestamp | 10 bits machine id | 12 bits sequence |

Thành phần

Số bit

Ý nghĩa

Sign bit

1

Luôn bằng 0 (để ID dương)

Timestamp

41

Thời gian tính bằng mili-giây kể từ một “epoch” tùy chỉnh

Machine ID

10

Xác định máy chủ hoặc datacenter tạo ID

Sequence

12

Bộ đếm tăng dần trong cùng một mili-giây

Ví dụ:

  • 41 bit timestamp => 2⁴¹ = 69 năm tính từ epoch.

  • 10 bit machine => tối đa 1024 node.

  • 12 bit sequence => mỗi node có thể tạo 4096 ID mỗi mili-giây.

Tổng hợp lại: bạn có thể tạo hơn 4 triệu ID/giây trên toàn hệ thống, mà không cần lock hay database trung tâm. Quá ấn tượng!

4. Cách Snowflake hoạt động

Khi cần tạo ID mới, quá trình diễn ra như sau:

  1. Lấy timestamp hiện tại (ms).

  2. Nếu timestamp trùng với lần trước → tăng sequence lên 1.

  3. Nếu sequence vượt quá 4095 → đợi sang mili-giây kế tiếp.

  4. Gộp tất cả bit lại thành một số 64-bit duy nhất.

Như vậy, mỗi ID không chỉ duy nhất, mà còn có thể sắp xếp theo thời gian — chỉ cần so sánh giá trị số là biết cái nào được tạo trước.

5. Ưu và nhược điểm của Snowflake ID

Ưu điểm:

  • Phân tán hoàn toàn – mỗi node tự tạo ID độc lập.

  • Sắp xếp được theo thời gian, tiện cho logging, sorting, hoặc analytics.

  • Không cần truy cập database trung tâm → tốc độ cực nhanh.

  • Có thể xác định nguồn tạo ID (dựa trên machine ID).

Nhược điểm:

  • Phụ thuộc vào đồng hồ hệ thống. Nếu clock bị lệch (clock drift) giữa các node, có thể sinh lỗi ID trùng.

  • Không hoàn toàn ngẫu nhiên, nên không phù hợp nếu bạn cần ID “ẩn danh” (ví dụ public link).

  • Cần đồng bộ hóa epoch và machine ID giữa các node.

6. Demo: Tạo Snowflake ID bằng Node.js

Dưới đây là một ví dụ tối giản giúp bạn hiểu cơ chế hoạt động của Snowflake ID:

class Snowflake {
  constructor(workerId, datacenterId, sequence = 0) {
    this.workerId = workerId;
    this.datacenterId = datacenterId;
    this.sequence = sequence;

    this.twepoch = 1288834974657n; // epoch của Twitter
    this.workerIdBits = 5n;
    this.datacenterIdBits = 5n;
    this.sequenceBits = 12n;

    this.maxWorkerId = -1n ^ (-1n << this.workerIdBits);
    this.maxDatacenterId = -1n ^ (-1n << this.datacenterIdBits);
    this.sequenceMask = -1n ^ (-1n << this.sequenceBits);

    this.workerIdShift = this.sequenceBits;
    this.datacenterIdShift = this.sequenceBits + this.workerIdBits;
    this.timestampLeftShift = this.sequenceBits + this.workerIdBits + this.datacenterIdBits;

    this.lastTimestamp = -1n;
  }

  tilNextMillis(lastTimestamp) {
    let timestamp = BigInt(Date.now());
    while (timestamp <= lastTimestamp) {
      timestamp = BigInt(Date.now());
    }
    return timestamp;
  }

  nextId() {
    let timestamp = BigInt(Date.now());
    if (timestamp < this.lastTimestamp) {
      throw new Error('Clock moved backwards!');
    }

    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.twepoch) << this.timestampLeftShift) |
           (BigInt(this.datacenterId) << this.datacenterIdShift) |
           (BigInt(this.workerId) << this.workerIdShift) |
           this.sequence;
  }
}

const snowflake = new Snowflake(1, 1);
console.log(snowflake.nextId().toString());

Kết quả là một chuỗi số 64-bit, ví dụ:

159488555397410304

Nếu bạn giải mã ngược, có thể trích xuất được timestamp, machine ID, và sequence - đúng với cấu trúc ban đầu.

7. So sánh với các phương pháp khác

Phương pháp

Độ duy nhất

Phân tán

Sắp xếp theo thời gian

Độ dài

Auto Increment

Không

Không

Ngắn

UUID v4

Không

Dài (36 ký tự)

ULID

Trung bình

Snowflake

64-bit (rất ngắn & hiệu quả)

Snowflake ID cân bằng tốt giữa hiệu năng, khả năng sắp xếp, và dễ mở rộng — lý do vì sao nó được các hệ thống lớn như Twitter, Discord, Instagram áp dụng.

8. Ứng dụng thực tế

 

Một số hệ thống nổi tiếng sử dụng Snowflake hoặc biến thể của nó:

  • Twitter: Triển khai bản gốc Snowflake (2010) cho Tweet ID.

  • Discord: Dùng Snowflake ID để xác định user, message, server.

  • Instagram / Meta: Áp dụng mô hình tương tự (Time-based ID Generator).

  • Alibaba, TikTok: Có hệ thống ID phân tán tương tự, thường gọi là Leaf ID hoặc UID Generator.

Trong hệ thống microservice hiện đại, Snowflake ID giúp:

  • Mỗi service tự tạo ID, không cần database trung tâm.

  • Đảm bảo log, sự kiện và bản ghi có thể sắp xếp theo thời gian chính xác.

  • Hỗ trợ tracing khi debug (vì ID chứa thông tin timestamp và machine).

9. Khi nào nên (hoặc không nên) dùng Snowflake ID

 

Nên dùng nếu:

  • Hệ thống của bạn phân tán hoặc có nhiều node backend.

  • Bạn cần ID tăng theo thời gian (log, analytics, stream).

  • Bạn muốn tránh bottleneck database.

Không nên dùng nếu:

  • Bạn cần ID ngẫu nhiên, ẩn danh, không đoán được (dùng UUID).

  • Bạn không muốn đồng bộ clock giữa server.

  • Hệ thống không cần scale lớn (auto increment vẫn đủ).

10. Kết luận

Snowflake ID là một trong những ý tưởng tinh tế và hiệu quả nhất trong thế giới backend.

Nó cho phép hệ thống vừa phân tán, vừa có tính thứ tự thời gian, mà vẫn giữ tính duy nhất toàn cầu.

Nếu bạn đang xây dựng:

  • Một microservice backend,

  • Một hệ thống log phân tán,

  • Hoặc chỉ đơn giản là muốn hiểu cách Twitter sinh ID,

… thì Snowflake ID là một “must-know” concept mà mọi backend developer nên nắm.