侧边栏壁纸
  • 累计撰写 49 篇文章
  • 累计创建 23 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

Mysql中利用雪花算法生成唯一ID的方法:在高并发环境中避免重复 ID 的解决方案

阿砖
2025-02-24 / 0 评论 / 0 点赞 / 133 阅读 / 2917 字

引言

在现代分布式系统中,生成唯一的标识符(ID)至关重要。雪花算法作为一种流行的 ID 生成技术,广泛应用于大规模的数据库和微服务架构中。本文将介绍如何通过雪花算法安全地生成唯一 ID,并在高并发环境中避免重复 ID 的问题。

雪花算法简介

雪花算法生成的 ID 结构如下:

+---------------------+-----------+-------------------+
| Timestamp (41 bits) | Machine ID (10 bits) | Sequence (12 bits)  |
+---------------------+-----------+-------------------+
  • 时间戳:41 位,表示从自定义起始时间到当前时间的毫秒数,支持约 69 年的时长。

  • 机器 ID:10 位,表示工作节点的标识,最多支持 1024 个不同的节点。

  • 序列号:12 位,同一毫秒内生成的 ID 数量最大为 4096。

在高并发场景中,如果多个请求在同一毫秒内生成 ID,由于序列号的增量管理无法同步,可能会导致 ID 重复。这会严重影响系统的可靠性,特别是在需要唯一标识的场合。

为了确保生成的 ID 唯一性,建议在数据库中创建一个状态表,来持久化存储 last_timestamp​ 和 sequence​,以下是实现步骤:

1. 创建状态表

首先,在数据库中创建一个表来存储 ID 生成过程中的状态信息:

CREATE TABLE snowflake_state (
    id INT PRIMARY KEY,
    last_timestamp BIGINT DEFAULT 0,
    sequence INT DEFAULT 0
);

-- 初始化表格
INSERT INTO snowflake_state (id) VALUES (1);
2. 修改 ID 生成函数

接下来,修改生成雪花 ID 的函数,以便从状态表中读取并更新状态:

DELIMITER $$

CREATE FUNCTION generate_snowflake_id(machine_id INT)
RETURNS BIGINT
DETERMINISTIC
BEGIN
    DECLARE epoch BIGINT DEFAULT 1577836800000; -- 自定义的起始时间戳(1970-01-01 00:00:00)
    DECLARE current_time_ms BIGINT; 
    DECLARE current_sequence INT; 
    DECLARE last_time BIGINT; 
    DECLARE snowflake_id BIGINT;

    -- 获取当前时间戳(毫秒)
    SET current_time_ms = UNIX_TIMESTAMP(NOW(3)) * 1000;

    -- 从状态表中获取最新的 last_timestamp 和 sequence
    SELECT last_timestamp, sequence INTO last_time, current_sequence FROM snowflake_state WHERE id = 1;

    -- 如果当前时间戳和上一次生成 ID 的时间相同,则增加序列号
    IF current_time_ms = last_time THEN
        SET current_sequence = (current_sequence + 1) % 4096; -- 4096 是 12 位序列数的最大值
    ELSE
        SET current_sequence = 0; -- 重置序列号
    END IF;

    SET snowflake_id = ((current_time_ms - epoch) << 22) | (machine_id << 12) | current_sequence;

    -- 更新状态表中的 last_timestamp 和 sequence
    UPDATE snowflake_state SET last_timestamp = current_time_ms, sequence = current_sequence WHERE id = 1;

    RETURN snowflake_id;
END$$

DELIMITER ;
3. 函数调用

使用函数生成唯一的雪花 ID 如下:

SELECT generate_snowflake_id(1) FROM table; -- 使用 'table' 表,来测试一个内容

虽然上述方法能有效避免重复 ID,但在高并发时,读取和更新数据库表可能会引入性能瓶颈。可以通过加锁机制优化并发访问,确保在同一时刻仅有一个进程在更新状态。

0

评论区