Cơ chế sinh ID tự tăng truyền thống và giải pháp thay thế bằng Snowflake trong MyBatis-Plus

Việc sử dụng cơ chế sinh ID tự tăng truyền thống thường gặp phải hai vấn đề nghiêm trọng: điểm lỗi đơn và nghẽn cổ chai hiệu năng.

Nguyên nhân chính

  • Điểm lỗi đơn: Hệ thống phụ thuộc vào một máy chủ hoặc dịch vụ duy nhất để cấp phát ID. Khi thành phần này sập, toàn bộ hệ thống không thể tạo ID mới — dẫn đến gián đoạn hoạt động.
  • Nghẽn cổ chai hiệu năng: Khi lượng yêu cầu sinh ID tăng cao, tài nguyên tính toán và lưu trữ bị quá tải, làm chậm tốc độ xử lý hoặc thậm chí gây treo hệ thống.
  • Vấn đề đồng thời: Trong môi trường có hàng nghìn yêu cầu đồng thời, cơ chế tuần tự truyền thống không đủ nhanh để đáp ứng.
  • Tính nhất quán dữ liệu: Nhiều tiến trình cùng lúc yêu cầu ID có thể dẫn đến xung đột hoặc giá trị trùng lặp nếu không được kiểm soát chặt chẽ.

Giải pháp phổ biến hiện nay là chuyển sang các thuật toán phân tán như Snowflake, cho phép sinh ID độc lập trên nhiều node mà vẫn đảm bảo tính duy nhất toàn cục.

Thuật toán Snowflake

Snowflake do Twitter thiết kế, là một phương pháp sinh ID 64-bit gồm ba thành phần:

  • Thời gian (41 bit): Tính từ epoch tùy chọn, đủ dùng trong ~69 năm.
  • ID máy (10 bit): Phân biệt các node trong hệ thống phân tán.
  • Counter (12 bit): Đếm số ID được sinh trong cùng một mili giây, hỗ trợ tối đa 4096 ID/ms.

Thuật toán này yêu cầu đồng hồ hệ thống phải ổn định và tăng dần — nếu đồng hồ bị lùi, ID có thể bị trùng hoặc sai thứ tự.

Lưu ý quan trọng: ID do Snowflake sinh ra là số nguyên 64-bit, nên kiểu dữ liệu trong code phải là Long hoặc String để tránh tràn số.

Tích hợp Snowflake với MyBatis-Plus

MyBatis-Plus hỗ trợ sẵn Snowflake thông qua enum IdType.ASSIGN_ID. Chỉ cần khai báo annotation @TableId trên trường khóa chính:

@TableName("sys_user")
public class User {
    @TableId(value = "id", type = IdType.ASSIGN_ID)
    private Long userId;
    private String fullName;
    private Integer userAge;
    private String contactEmail;
}

Enum IdType trong MyBatis-Plus cung cấp nhiều tùy chọn sinh ID:

public enum IdType {
    AUTO(0),      // Tự tăng bởi CSDL
    NONE(1),      // Không chỉ định, theo cấu hình toàn cục
    INPUT(2),     // Người dùng tự nhập
    ASSIGN_ID(3), // Dùng Snowflake (mặc định)
    ASSIGN_UUID(4); // Dùng UUID không dấu gạch ngang
}

Khi dùng ASSIGN_ID, MyBatis-Plus sẽ tự động gọi DefaultIdentifierGenerator — triển khai mặc định của Snowflake — để sinh ID trước khi insert bản ghi.

Thẻ: MyBatis-Plus Snowflake Java Distributed-ID Database

Đăng vào ngày 15 tháng 9 lúc 02:27