啥是雪花算法啊?顺便举个栗子

雪花算法(Snowflake Algorithm)是一种用于生成唯一标识符的算法,主要用于分布式系统中对数据进行唯一标识。它最初由Twitter开发,用于在分布式系统中生成全局唯一的ID。

这个算法的原理贼拉简单,它将生成的ID分成三个部分:

  1. 时间戳: 记录了雪花生成的时间,就像雪花落下的瞬间一样。这确保了即使是在同一时刻生成的雪花,它们的ID也会有所不同。 使用了41位来存储自Unix纪元(1970年1月1日)以来的毫秒数。这允许Snowflake在一定的时间内生成唯一的ID。

  2. 机器ID: 就像是雪花的身份证号,用来标识这片雪花是由哪台机器生成的。这样可以避免不同机器生成相同的ID。这个机器码占用了10位。这样可以确保在同一时间戳内由不同机器生成的ID不会重复。

  3. 序列号: 在同一时刻,可能有多个雪花同时生成,序列号就像是雪花的兄弟姐妹们的排行,确保它们在同一时刻内有序。 在同一毫秒内,可以生成多个ID。序列号占用了12位,用于标识同一机器在同一时间戳内生成的不同ID。

想象一下,每个雪花ID就像是一个小档案,里面都包含了这三个关键信息,不同时刻的由时间戳区分了,同一时刻的不同机器上的又由机器码区分了,同一台机器上的又被序列号区分了,所以这种结构保证了在分布式系统中生成的ID是唯一的,并且有一定的顺序性,可以根据时间戳进行排序。

总的来说,雪花算法就是通过这三个要素,巧妙地保证了在分布式系统中生成的ID既是全局唯一的,又有一定的时间顺序。这种设计就像是为雪花们制定了一个独特的身份系统,让它们在大雪纷飞的世界中能够有条不紊地降落。

举个例子,在Java中,可以使用雪花算法生成唯一ID的实现通常是通过类来完成的。以下是一个简单的Java示例代码,使用雪花算法生成唯一ID:

java 复制代码
package com.luke.luketools.snowflakeIdGenerator;

public class SnowflakeIdGenerator {
    // 2021-01-01 00:00:00
    private final long epoch = 1609459200000L; // 设置起始时间戳,例如2021-01-01 00:00:00的毫秒数
    // 机器ID所占的位数
    private final long machineIdBits = 10L;
    // 机器ID的最大值
    private final long maxMachineId = -1L ^ (-1L << machineIdBits);
    // 毫秒内自增位
    private final long sequenceBits = 12L;
    // 机器ID向左移12位
    private final long machineIdShift = sequenceBits;
    // 时间戳向左移22位(10+12)
    private final long timestampLeftShift = sequenceBits + machineIdBits;
    // 生成序列的掩码,这里为4095 (0b111111111111=0xfff=4095)
    private final long sequenceMask = -1L ^ (-1L << sequenceBits);
    // 机器ID(0~1023)
    private long machineId;
    // 毫秒内序列(0~4095)
    private long sequence = 0L;
    // 上次生成ID的时间戳
    private long lastTimestamp = -1L;
    // 构造器
    public SnowflakeIdGenerator(long machineId) {
        if (machineId < 0 || machineId > maxMachineId) {
            throw new IllegalArgumentException("Machine ID must be between 0 and " + maxMachineId);
        }
        this.machineId = machineId;
    }
    // 线程安全的id生成方法
    public synchronized long generateId() {
        long timestamp = System.currentTimeMillis();

        if (timestamp < lastTimestamp) {
            // 如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退过,出现问题返回-1
            throw new RuntimeException("Clock moved backwards. Refusing to generate ID for " + (lastTimestamp - timestamp) + " milliseconds.");
        }
        // 如果是同一时间生成的,则进行毫秒内序列
        if (lastTimestamp == timestamp) {
            // sequence自增,因为sequence只有12bit,所以和sequenceMask相与一下,去掉高位
            sequence = (sequence + 1) & sequenceMask;
            // 判断是否溢出,也就是每毫秒内超过4095,当为4096时,与sequenceMask相与,sequence就等于0
            if (sequence == 0) {
                // 自旋等待到下一毫秒
                timestamp = tilNextMillis(lastTimestamp);
            }
        } else {
            // 如果不是同一时间生成的,则重置sequence
            sequence = 0L;
        }
        // 上次生成ID的时间戳
        lastTimestamp = timestamp;
        // 移位并通过或运算拼到一起组成64位的ID
        return ((timestamp - epoch) << timestampLeftShift) |
                (machineId << machineIdShift) |
                sequence;
    }
    // 自旋等待到下一毫秒
    private long tilNextMillis(long lastTimestamp) {
        // 获取当前时间戳
        long timestamp = System.currentTimeMillis();
        // 如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退过,出现问题返回-1
        while (timestamp <= lastTimestamp) {
            // 获取当前时间戳
            timestamp = System.currentTimeMillis();
        }
        return timestamp;
    }

    public static void main(String[] args) {
        // 使用机器ID为1的实例
        SnowflakeIdGenerator idGenerator = new SnowflakeIdGenerator(1);

        // 生成10个ID并打印
        for (int i = 0; i < 10; i++) {
            long id = idGenerator.generateId();
            System.out.println("Generated ID: " + id);
        }
    }
}

输出结果:

这只是一个简单的实现示例,机器码使用了一位。在实际生产环境中,还需要考虑高并发情况下的性能和线程安全性。

相关推荐
Z_W_H_13 分钟前
【springboot】IDEA手动创建SpringBoot简单工程(无插件)
java·spring boot·intellij-idea
HeXDev15 分钟前
【SkyWalking】服务端部署与微服务无侵入接入实战指南
java·微服务·架构·skywalking·链路追踪·微服务治理
mit6.82434 分钟前
[Meetily后端框架] Whisper转录服务器 | 后端服务管理脚本
c++·人工智能·后端·python
探索java35 分钟前
Java 深入解析:JVM对象创建与内存机制全景图
java·jvm
Sylvia-girl41 分钟前
Java---IDEA
java·开发语言·intellij-idea
Z_W_H_1 小时前
【Springboot】Bean解释
java·开发语言
Apipost的同学们1 小时前
AI时代的接口自动化优化实践:如何突破Postman的局限性
后端·ai·架构·postman·自定义函数·apipost·api+ai
Otaku love travel2 小时前
老系统改造增加初始化,自动化数据源配置(tomcat+jsp+springmvc)
java·tomcat·初始化·动态数据源
DKPT2 小时前
Java设计模式之行为型模式(责任链模式)介绍与说明
java·笔记·学习·观察者模式·设计模式
L_autinue_Star2 小时前
手写vector容器:C++模板实战指南(从0到1掌握泛型编程)
java·c语言·开发语言·c++·学习·stl