雪花算法简介

书欣 Java经验 发布时间:2023-01-08 18:21:42 阅读数:6849 1
下文笔者讲述雪花算法的简介说明,如下所示

雪花算法简介

 
雪花算法(SnowFlake)称为雪花算法。
  是Twitter公司在其内部用于分布式环境下生成唯一ID
2014年开源scala 语言版本
雪花算法
 
首位:1bit,固定为0。
时间戳:41bit,((2^41 ) - 1) / (1000x60x60x24x365) 大约可以使用69年。
机器码:10bit,一般前5bit用户机房,后5bit用于服务器,共可部署2^5 x 2^5 = 1024 台服务器。
序列号:12bit,同一毫秒时间戳,通过序列号来递增区分,1ms可以容纳 (2^12) -1= 4095个id,
 超过则获取下一毫秒

java版雪花算法

package com.java265.utils;

public class SnowFlake {

    /**
     * 组成部分 最高符号位 + 时间戳 + (机房id+机房id) + 序列号
     */

    // 修复时间戳 2022-08-12 20:30:00
    private static final long FIX_TIME_STAMP = 1660307400L;

    // 机房id
    private final long computerRoomId;

    // 机器id
    private final long machineId;

    // 序列号
    private long sequence = 0L;

    /**
     * 所占用的bit个数
     */

    // 时间戳41bit

    // 5bit机房id
    private static final long COMPUTER_ROOM_BIT_CNT = 5L;

    // 5bit机器id
    private static final long MACHINE_BIT_CNT = 5L;

    // 12bit序列号
    private static final long SEQUENCE_BIT_CNT = 12L;

    /**
     * 位移的位数
     */

    // 机器id 左移12位
    private static final long MACHINE_ID_SHIFT = SEQUENCE_BIT_CNT;

    // 机房id 左移17位
    private static final long COMPUTER_ROOM_ID_SHIFT = MACHINE_ID_SHIFT + MACHINE_BIT_CNT;

    // 时间戳 左移22位
    private final static long TIME_STAMP_SHIFT = COMPUTER_ROOM_ID_SHIFT + COMPUTER_ROOM_BIT_CNT;

    /**
     * 聚合信息
     */

    // 支持最大的机房id机房id  5bit
    private static final long MAX_COMPUTER_ROOM_ID = ~(-1 << COMPUTER_ROOM_BIT_CNT);

    // 支持最大的机器id 5bit
    private static final long MAX_MACHINE_ID = ~(-1 << MACHINE_BIT_CNT);

    // 序列号支持的最大的个数 12bit
    private static final long SEQUENCE_MASK = ~(-1 << SEQUENCE_BIT_CNT);

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

    /**
     * @param computerRoomId 机房id
     * @param machineId      机器id
     */
    public SnowFlake(long computerRoomId, long machineId) {
        if (computerRoomId < 0 || computerRoomId > MAX_COMPUTER_ROOM_ID) {
            throw new IllegalArgumentException("computerRoomId 不在范围");
        }

        if (machineId < 0 || machineId > MAX_MACHINE_ID) {
            throw new IllegalArgumentException("computerRoomId 不在范围");
        }

        this.computerRoomId = computerRoomId;
        this.machineId = machineId;
    }

    /**
     * @return 返回毫秒级时间戳
     */
    private long getCurrentTime() {
        return System.currentTimeMillis();
    }

    /**
     * @return 雪花刷法生成 id
     */
    public synchronized long getNextId() {
        // 拿到时间戳
        long currentTimeStamp = getCurrentTime();

        // 时间戳回拨问题
        if (currentTimeStamp < lastTimeStamp) {
            throw new RuntimeException(
                    String.format("可能出现服务器时钟回拨问题,
                    请检查服务器时间。当前服务器时间戳:%d,
                     上一次使用时间戳:%d", currentTimeStamp,
                            lastTimeStamp));
        }

        // 时间为同一毫秒时间,sequence + 1
        if (currentTimeStamp == lastTimeStamp) {
            // 序列号 + 1
            sequence = (sequence + 1) & SEQUENCE_MASK;
            // 序列号用完
            if (sequence == 0) {
                // 获取下一个毫秒级
                currentTimeStamp = getNextMillis();
            }
        } else {
            sequence = 0;
        }

        // 记录上一次时间戳
        lastTimeStamp = currentTimeStamp;
        // 生成唯一id
        return ((currentTimeStamp - FIX_TIME_STAMP) << TIME_STAMP_SHIFT) |
                (computerRoomId << COMPUTER_ROOM_ID_SHIFT) |
                (machineId << MACHINE_ID_SHIFT) |
                sequence;
    }

    /**
     * @return 下一毫秒
     */
    private long getNextMillis() {
        long currentTimeStamp = getCurrentTime();
        while (currentTimeStamp <= lastTimeStamp) {
            currentTimeStamp = getCurrentTime();
        }
        return currentTimeStamp;
    }

}

springBoot整合雪花算法

配置yaml

SnowFlake:
  computerRoomId: 0
  machineId: 0

引入上面编写的SnowFlake算法文件,注意加入@service注解

编写SnowFlakeConfig配置文件

package com.java265.config;

import com.java265.utils.SnowFlake;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Slf4j
@Configuration
public class SnowFlakeConfig {
    @Value("${SnowFlake.computerRoomId}")
    private long computerRoomId;

    @Value("${SnowFlake.machineId}")
    private long machineId;

    @Bean
    public SnowFlake snowFlake() {
        return new SnowFlake(computerRoomId,machineId);
    }
}

测试雪花算法

package com.java265;

import com.java265.utils.SnowFlake;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class DemoApplicationTests {

	@Autowired
	SnowFlake snowFlake;

	@Test
	void contextLoads() {
	    //生成100个雪花算法
		for (int i = 0; i < 100; i++) {
			long flakeId = snowFlake.getNextId();
			System.out.println(i + " = " +flakeId);
		}
	}
}

算法优缺点

雪花算法优点:
  高并发分布式环境下生成不重复 id,每秒可生成百万个不重复 id。
  基于时间戳,以及同一时间戳下序列号自增,基本保证 id 有序递增。
  不依赖第三方库或者中间件。
  算法简单,在内存中进行,效率高。

雪花算法缺点:
  依赖服务器时间
  服务器时钟回拨时可能会生成重复 id
   算法中可通过记录最后一个生成 id 时的时间戳来解决
    每次生成 id 之前比较当前服务器时钟是否被回拨
    避免生成重复 id。
版权声明

本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。

本文链接: https://www.Java265.com/JavaJingYan/202301/16731734385316.html

最近发表

热门文章

好文推荐

Java265.com

https://www.java265.com

站长统计|粤ICP备14097017号-3

Powered By Java265.com信息维护小组

使用手机扫描二维码

关注我们看更多资讯

java爱好者