前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >雪花算法:分布式系统唯一ID生成算法

雪花算法:分布式系统唯一ID生成算法

作者头像
Jensen_97
发布2023-09-19 08:45:30
8100
发布2023-09-19 08:45:30
举报
文章被收录于专栏:技术客栈技术客栈

一、由来

雪花算法(Snowflake Algorithm)是一种用于生成分布式系统中唯一ID的算法。起初由Twitter设计,用于解决分布式系统中唯一ID的需求。这一算法的目标是生成全局唯一、有序的64位整数ID,以确保数据不冲突、不重复。

二、结构

雪花算法生成的ID由以下部分组成:

  • 41位时间戳:精确到毫秒级,记录ID生成的时间。
  • 10位机器ID:用于标识不同机器或节点,可自定义分配。
  • 12位序列号:解决同一毫秒内生成多个ID的冲突问题。

三、工作原理

雪花算法的工作原理如下:

  1. 获取当前时间戳的41位,并将其左移22位,以获取时间戳部分。
  2. 获取机器ID,并将其左移12位,以获取机器ID部分。
  3. 生成序列号,同一毫秒内生成多个ID时,序列号递增。
  4. 合并时间戳、机器ID和序列号,形成64位整数ID。

四、应用场景与特点

雪花算法广泛应用于分布式系统,用于生成唯一标识符,如订单号、用户ID、消息ID等。在解决分布式系统中唯一ID生成需求时非常有效,已被众多大型互联网公司和开源项目采用。

主要有以下特点:

  • 唯一性:雪花算法生成的ID在分布式环境下全局唯一,不会重复。
  • 有序性:生成的ID有序,可根据ID大小排序。
  • 高性能:ID生成速度快,适用于高并发的分布式系统。
  • 可定制性:机器ID可自定义,适用于各种规模和需求的系统

五、Java代码实现

工具类:

代码语言:javascript
复制
package com.forum.core.Utils.Snowflake;

public class SnowflakeIdGenerator {
    // ==============================字段==============================
    private final long workerId;          // 机器ID
    private final long datacenterId;      // 数据中心ID
    private long sequence = 0L;           // 序列号

    // 配置参数
    private static final long MAX_WORKER_ID = 31L;
    private static final long MAX_DATACENTER_ID = 31L;
    private static final long TIMESTAMP_BITS = 41L;
    private static final long MAX_TIMESTAMP = ~(-1L << TIMESTAMP_BITS);
    private static final long WORKER_ID_BITS = 5L;
    private static final long DATACENTER_ID_BITS = 5L;
    private static final long SEQUENCE_BITS = 12L;

    // 位移偏移量
    private static final long TIMESTAMP_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS + DATACENTER_ID_BITS;
    private static final long WORKER_ID_SHIFT = SEQUENCE_BITS + DATACENTER_ID_BITS;
    private static final long DATACENTER_ID_SHIFT = SEQUENCE_BITS;

    private long lastTimestamp = -1L;     // 上次生成ID的时间戳

    // ==============================构造函数==============================
    /**
     * 构造函数
     * @param workerId     机器ID (0 - 31)
     * @param datacenterId 数据中心ID (0 - 31)
     */
    public SnowflakeIdGenerator(long workerId, long datacenterId) {
        // 检查workerId和datacenterId是否合法
        if (workerId > MAX_WORKER_ID || workerId < 0) {
            throw new IllegalArgumentException("Worker ID must be between 0 and " + MAX_WORKER_ID);
        }
        if (datacenterId > MAX_DATACENTER_ID || datacenterId < 0) {
            throw new IllegalArgumentException("Datacenter ID must be between 0 and " + MAX_DATACENTER_ID);
        }

        // 设置workerId和datacenterId
        this.workerId = workerId;
        this.datacenterId = datacenterId;
    }

    // ==============================方法==============================
    /**
     * 生成唯一ID
     * @return 唯一ID
     */
    public synchronized long generateUniqueId() {
        long timestamp = getCurrentTimestamp();

        // 检查时钟回退情况
        if (timestamp < lastTimestamp) {
            throw new RuntimeException("Clock moved backwards. Refusing to generate ID.");
        }

        // 同一毫秒内自增序列号
        if (timestamp == lastTimestamp) {
            sequence = (sequence + 1) & ((1 << SEQUENCE_BITS) - 1);  // 自增并掩码
            if (sequence == 0) {
                // 序列号用完,等待下一毫秒
                timestamp = getNextTimestamp(lastTimestamp);
            }
        } else {
            sequence = 0L;  // 不同毫秒重置序列号
        }

        lastTimestamp = timestamp;

        // 组合生成唯一ID
        return ((timestamp << TIMESTAMP_SHIFT) |
                (datacenterId << DATACENTER_ID_SHIFT) |
                (workerId << WORKER_ID_SHIFT) |
                sequence);
    }

    /**
     * 获取当前时间戳
     * @return 当前时间戳(毫秒)
     */
    private long getCurrentTimestamp() {
        return System.currentTimeMillis();
    }

    /**
     * 等待下一毫秒,直到获得新的时间戳
     * @param lastTimestamp 上次生成ID的时间戳
     * @return 新的时间戳
     */
    private long getNextTimestamp(long lastTimestamp) {
        long timestamp = getCurrentTimestamp();
        while (timestamp <= lastTimestamp) {
            timestamp = getCurrentTimestamp();
        }
        return timestamp;
    }

    // ==============================测试==============================
    public static void main(String[] args) {
        // 创建一个雪花算法生成器,传入机器ID和数据中心ID
        SnowflakeIdGenerator idGenerator = new SnowflakeIdGenerator(0, 0);
        // 生成10个唯一ID并打印
        for (int i = 0; i < 10; i++) {
            new Thread(()->{
                long uniqueId = idGenerator.generateUniqueId();
                System.out.println("Generated Unique ID: " + uniqueId);
            }).start();
        }
    }
}

测试输出:

代码语言:javascript
复制
Generated Unique ID: 7109423425210286080
Generated Unique ID: 7109423425214480385
Generated Unique ID: 7109423425214480384
Generated Unique ID: 7109423425210286081
Generated Unique ID: 7109423425214480389
Generated Unique ID: 7109423425214480388
Generated Unique ID: 7109423425214480387
Generated Unique ID: 7109423425214480386
Generated Unique ID: 7109423425214480391
Generated Unique ID: 7109423425214480390

六、总结

雪花算法是一种为分布式系统生成唯一ID的算法,具备唯一性、有序性和高性能等特点,适用于各类分布式系统。通过合理分配机器ID和序列号,满足不同规模和需求的系统,成为分布式系统中常用的ID生成方案。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、由来
  • 二、结构
  • 三、工作原理
  • 四、应用场景与特点
  • 五、Java代码实现
  • 六、总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档