雪花算法生成全局Id,看这篇就够了

分布式id

  • 雪花算法能够生成一个64位long类型数据,适合做分布式系统的全局标识符,或者分库分表中,同类型数据表的主键

原理探究

  • 雪花算法:以一台服务器为对象,在一毫秒时间内,生成一个自增的long数据
  • 特点:雪花算法生成的id具有唯一性,和实时性

下面,就来研究一下,雪花id是如何保证全局唯一的

组成

划重点:一位符号位,41位时间毫秒数,10位机器id,12位同毫秒自增序号,共64位
在这里插入图片描述
由此,我们可以分析得出以下结论:

  • 时间戳位于高位,且时间戳随时间递增,所以,雪花id随时间递增
  • 10位机器id,一共可以为2^10=1024台服务器生成id
  • 12位序列号,即在1毫秒内,可以生成2^12=4096个id,换句话说,就是雪花id最高支持409 万的每秒并发量
  • 雪花id是否会重复,取决于时间戳是否重复,也就是说,当服务器调回过去的时间时,就会导致雪花id不再唯一

生成过程

/**
 * 雪花算法生成id
 */
public class SnowFlakeClient {

    /**
     * 起始时间戳
     */
    private static final long START_TIMESTAMP = 1704038400L; //2024-01-01 00:00:00

    /**
     * 各组成部分占用的位数
     * */
    /**
     * 时间戳
     */
    private static final long TIMESTAMP_BIT = 41;

    /**
     * 机器id
     */
    private static final long MACHINE_BIT = 10;

    /**
     * 序列号
     */
    private static final long SEQUENCE_BIT = 12;

    // 每一部分的最大值
    private static final long MAX_SEQUENCE = ~(-1L << SEQUENCE_BIT);
    private static final long MAX_MACHINE_NUM = ~(-1L << MACHINE_BIT);

    // 每一部分向左的位移
    private static final long MACHINE_LEFT = SEQUENCE_BIT;
    private static final long TIMESTAMP_LEFT = SEQUENCE_BIT + MACHINE_BIT;


    /**
     * 上一次生成id的时间戳(不断改变)
     */
    private static long lastTimeStamp = -1L;

    /**
     * 递增序列号
     */
    private static long sequence = 0L;

    /**
     * 生成雪花id
     */
    public static long nextId() {

        //1.获取当前时间戳
        long now = System.currentTimeMillis();

        //2.判断服务器是否时钟回拨
        if (now < lastTimeStamp) {
            throw new RuntimeException("服务器时钟回拨,可能会导致id不唯一");
        }

        //3.判断是否在同一毫秒
        if (now == lastTimeStamp) {
            //3.1同一毫秒内,就让序列号递增,注意不要超出最大范围
            sequence = (sequence + 1) & MAX_SEQUENCE;//做与运算就能去掉超出最高位的数字
            if (sequence == 0L) {
                //3.1.1序列号已经用完了,本毫秒内不再生成新id
                now = System.currentTimeMillis();
                while (now <= lastTimeStamp) {
                    now = System.currentTimeMillis();
                }
            }
        } else {
            //不在同一个毫秒,重置序列号
            sequence = 0L;
        }

        //更新时间戳
        lastTimeStamp = now;

        //4.组合成id:使用移位,以及或运算
        long id = ((now - START_TIMESTAMP) << TIMESTAMP_LEFT) | (IdConfig.machineId << MACHINE_LEFT) | sequence;

        return id;

    }

}

测试:

public class Test {
    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            System.out.println(Long.toBinaryString(SnowFlakeClient.nextId()));
        }
    }
}

结果:

110001110111110101001000111111101111111100000000000000000000000
110001110111110101001000111111110001001010000000000000000000000
110001110111110101001000111111110001001010000000000000000000001
110001110111110101001000111111110001001010000000000000000000010
110001110111110101001000111111110001001010000000000000000000011
110001110111110101001000111111110001001010000000000000000000100
110001110111110101001000111111110001001010000000000000000000101
110001110111110101001000111111110001001010000000000000000000110
110001110111110101001000111111110001001010000000000000000000111
110001110111110101001000111111110001001010000000000000000001000
110001110111110101001000111111110001001010000000000000000001001
110001110111110101001000111111110001001010000000000000000001010
110001110111110101001000111111110001001100000000000000000000000
110001110111110101001000111111110001001100000000000000000000001
110001110111110101001000111111110001001100000000000000000000010
110001110111110101001000111111110001001100000000000000000000011
110001110111110101001000111111110001001100000000000000000000100
110001110111110101001000111111110001001100000000000000000000101
110001110111110101001000111111110001001100000000000000000000110
110001110111110101001000111111110001001100000000000000000000111
110001110111110101001000111111110001001100000000000000000001000
110001110111110101001000111111110001001100000000000000000001001
110001110111110101001000111111110001001100000000000000000001010
110001110111110101001000111111110001001100000000000000000001011
110001110111110101001000111111110001001100000000000000000001100
110001110111110101001000111111110001001100000000000000000001101
110001110111110101001000111111110001001100000000000000000001110
在这里插入代码片
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值