雪花算法的详解与java实现

雪花算法(Snowflake Algorithm)是一种用于生成分布式系统中唯一 ID 的算法。它的设计目标是在大规模分布式系统中生成唯一的、有序的、趋势递增的 ID,同时保证高性能和可扩展性。

雪花算法的 ID 结构如下图所示:

 0                                             41     51   63
+------+--------------------------------------+-------+-----+
| sign |         timestamp (毫秒级)             | 机器ID | 序列号 |
+------+--------------------------------------+-------+-----+

具体来说,这个64位的 ID 包含以下几个部分:

  • 符号位(1 bit):始终为0。
  • 时间戳(41 bits):记录当前时间与一个固定的起始时间之间的偏移量,精确到毫秒级。41 bits 可以表示约 69 年的时间戳。
  • 机器ID(10 bits):由数据中心ID(5 bits)和工作机器ID(5 bits)组成,用来标识不同的机器。最多可以有1024个不同的机器。
  • 序列号(12 bits):在同一毫秒内产生的不同 ID 的序列号。可以表示每台机器在同一毫秒内生成的最大序列号数量为4096。

通过将时间戳、机器ID和序列号等组合起来,雪花算法可以在分布式环境下生成唯一的、有序的 64 位 ID。在同一毫秒内,不同的机器生成的 ID 是不会重复的,而同一台机器在同一毫秒内也是可以生成连续递增的 ID。

需要注意的是,雪花算法依赖于系统的时钟准确性。如果系统时钟发生回拨,可能会导致生成重复的 ID 或者无法生成 ID,因此要确保系统时钟的稳定性和准确性。

总的来说,雪花算法是一种简单高效的分布式 ID 生成算法,在分布式系统中广泛应用于唯一标识和排序的需求场景,如数据库主键、日志追踪等。

下面是一个用Java实现雪花算法的示例:

public class SnowflakeIdGenerator {
    // 定义起始时间戳
    private final static long START_TIMESTAMP = 1625089168000L; // 2021-06-30 00:00:00

    // 定义各部分占用的位数
    private final static long SEQUENCE_BITS = 12; // 序列号占用的位数
    private final static long WORKER_ID_BITS = 10; // 工作机器ID占用的位数
    private final static long TIMESTAMP_BITS = 41; // 时间戳占用的位数

    // 定义各部分的偏移量
    private final static long WORKER_ID_OFFSET = SEQUENCE_BITS; // 工作机器ID的偏移量
    private final static long TIMESTAMP_OFFSET = WORKER_ID_OFFSET + WORKER_ID_BITS; // 时间戳的偏移量

    // 定义各部分的最大值
    private final static long MAX_SEQUENCE = ~(-1L << SEQUENCE_BITS);
    private final static long MAX_WORKER_ID = ~(-1L << WORKER_ID_BITS);

    private long workerId; // 工作机器ID
    private long sequence = 0L; // 序列号
    private long lastTimestamp = -1L; // 上次生成ID的时间戳

    public SnowflakeIdGenerator(long workerId) {
        if (workerId > MAX_WORKER_ID || workerId < 0) {
            throw new IllegalArgumentException(String.format("Worker ID can't be greater than %d or less than 0", MAX_WORKER_ID));
        }
        this.workerId = workerId;
    }

    public synchronized long nextId() {
        long timestamp = System.currentTimeMillis();

        if (timestamp < lastTimestamp) {
            throw new RuntimeException("Clock moved backwards. Refusing to generate ID.");
        }

        if (timestamp == lastTimestamp) {
            sequence = (sequence + 1) & MAX_SEQUENCE;
            if (sequence == 0L) {
                timestamp = tilNextMillis(lastTimestamp);
            }
        } else {
            sequence = 0L;
        }

        lastTimestamp = timestamp;

        return ((timestamp - START_TIMESTAMP) << TIMESTAMP_OFFSET)
                | (workerId << WORKER_ID_OFFSET)
                | sequence;
    }

    private long tilNextMillis(long lastTimestamp) {
        long timestamp = System.currentTimeMillis();
        while (timestamp <= lastTimestamp) {
            timestamp = System.currentTimeMillis();
        }
        return timestamp;
    }
}

使用示例:

public class Main {
    public static void main(String[] args) {
        SnowflakeIdGenerator idGenerator = new SnowflakeIdGenerator(1);
        
        for (int i = 0; i < 10; i++) {
            long id = idGenerator.nextId();
            System.out.println(id);
        }
    }
}

上述示例中,我们创建了一个SnowflakeIdGenerator类来生成雪花算法ID。在main方法中,我们创建了一个ID生成器实例,并调用nextId()方法来获取唯一ID。运行示例代码,会输出10个不重复的ID。

需要注意的是,该示例中用到了系统当前时间戳来作为参考,因此要确保系统时间的准确性,避免时间回拨等问题。另外,如果在多线程环境下使用,需要保证线程安全。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值