雪花算法简介
下文笔者讲述雪花算法的简介说明,如下所示
雪花算法简介
雪花算法(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。
版权声明
本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。


