分布式—雪花算法生成ID

一、简介

1、雪花算法的组成:

由64个Bit(比特)位组成的long类型的数字

0 | 0000000000 0000000000 0000000000 000000000 | 00000 | 00000 | 000000000000

1个bit:符号位,始终为0。

41个bit:时间戳,精确到毫秒级别,可以使用69年。

10个bit:工作机器ID,可以部署在1024个节点上。

12个bit:序列号,每个节点每毫秒内最多可以生成4096个ID。

2、雪花算法的优缺点

优点:

全局唯一:雪花算法生成的ID是全局唯一的,可以用于分布式系统中的数据分片和数据合并。

时间有序:雪花算法生成的ID中包含了时间戳信息,可以根据ID的大小推算出生成的时间。

高性能:雪花算法生成ID的速度很快,可以满足高并发的场景需求。

可扩展性:雪花算法的数据结构相对简单,易于扩展和修改。

缺点:

依赖于系统时钟:雪花算法生成ID的过程中依赖于系统时钟,如果系统时钟发生回拨,可能会导致生成的ID出现重复。

长度固定:雪花算法生成的ID长度固定为64位,可能会导致存储和传输成本较高。

不支持分布式计算:雪花算法生成ID的过程是单线程的,不能支持分布式计算。

二、项目中使用

1、引入依赖

XML 复制代码
<dependency>
    <groupId>com.github.beyondfengyu</groupId>
    <artifactId>snowflake-spring-boot-starter</artifactId>
    <version>1.0.0</version>
</dependency>

2、配置参数

cs 复制代码
snowflake:
  data-center-id: 1 # 数据中心ID,可以使用机器IP地址最后一段数字,范围为0-31
  machine-id: 1 # 机器ID,可以使用服务器编号,范围为0-31

3、使用

java 复制代码
@Service
public class OrderSevice {

    @Autowired
    private SnowflakeIdWorker snowflakeIdWorker;
 
    public Long creatOrderId() {
        return snowflakeIdWorker.nextId();
    }
}

三、手写雪花算法生成ID

java 复制代码
/**
 * 功能描述:雪花算法生成订单号
 */
public class SnowFlakeTemplate {

    //起始的时间戳
    private final static long START_STAMP = 1480166465631L;

    //每一部分占用的位数
    private final static long SEQUENCE_BIT = 12; //序列号占用的位数
    private final static long MACHINE_BIT = 5; //机器标识占用的位数
    private final static long DATA_CENTER_BIT = 5;//数据中心占用的位数

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

    //每一部分向左的位移
    private final static long MACHINE_LEFT = SEQUENCE_BIT;
    private final static long DATA_CENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT;
    private final static long TIMESTAMP_LEFT = DATA_CENTER_LEFT + DATA_CENTER_BIT;
    private long dataCenterId; //数据中心
    private long machineId; //机器标识
    private long sequence = 0L; //序列号
    private long lastStamp = -1L;//上一次时间戳

    public SnowFlakeTemplate(long dataCenterId, long machineId) {
        if (dataCenterId > MAX_DATA_CENTER_NUM || dataCenterId < 0) {
            throw new IllegalArgumentException("dataCenterId can't be greaterthan MAX_DATA_CENTER_NUM or less than 0");
        }
        if (machineId > MAX_MACHINE_NUM || machineId < 0) {
            throw new IllegalArgumentException("machineId can't be greater thanMAX_MACHINE_NUM or less than 0");
        }
        this.dataCenterId = dataCenterId;
        this.machineId = machineId;
    }

    private String Prefix() {
        String randomPrefix = "";
        for (int i = 0; i < 2; i++) {
            char c = (char) (Math.random() * 26 + 'A');
            randomPrefix += c;
        }
        return randomPrefix;
    }

    //产生下一个ID
    public synchronized String nextId() {
        long currStamp = getNewStamp();
        if (currStamp < lastStamp) {
            throw new RuntimeException("Clock moved backwards. Refusing to generate id");
        }
        if (currStamp == lastStamp) {
            //相同毫秒内,序列号自增
            sequence = (sequence + 1) & MAX_SEQUENCE;
            //同一毫秒的序列数已经达到最大
            if (sequence == 0L) {
                currStamp = getNextMill();
            }
        } else {
            //不同毫秒内,序列号置为0
            sequence = 0L;
        }
        lastStamp = currStamp;
        return Prefix() + ((currStamp - START_STAMP) << TIMESTAMP_LEFT //时间戳部分
                | dataCenterId << DATA_CENTER_LEFT //数据中心部分
                | machineId << MACHINE_LEFT //机器标识部分
                | sequence); //序列号部分
    }

    private long getNextMill() {
        long mill = getNewStamp();
        while (mill <= lastStamp) {
            mill = getNewStamp();
        }
        return mill;
    }

    private long getNewStamp() {
        return System.currentTimeMillis();
    }

    public static void main(String[] args) {
        System.out.println(new SnowFlakeTemplate(2, 3).nextId() );
    }
}
相关推荐
回家路上绕了弯2 小时前
接口响应时间优化指南:从秒级到毫秒级的全链路方案
分布式·后端
RestCloud2 小时前
OceanBase 分布式数据库的 ETL 实践:从抽取到实时分析
数据库·分布式·postgresql·oceanbase·etl·数据处理·数据同步
西***63474 小时前
从信号零损耗到智能协同:高清混合矩阵全链路技术拆解,分布式可视化系统十大趋势重塑行业
分布式·线性代数·矩阵
菜鸡儿齐13 小时前
kafka简介
分布式·kafka
周杰伦_Jay14 小时前
【实战|旅游知识问答RAG系统全链路解析】从配置到落地(附真实日志数据)
大数据·人工智能·分布式·机器学习·架构·旅游·1024程序员节
兜兜风d'16 小时前
RabbitMQ事务机制详解
数据库·spring boot·分布式·rabbitmq·ruby·java-rabbitmq
ifeng091816 小时前
HarmonyOS分布式任务调度——跨设备智能任务分配与迁移
分布式·华为·harmonyos
9ilk16 小时前
【仿RabbitMQ的发布订阅式消息队列】--- 模块设计与划分
c++·笔记·分布式·后端·中间件·rabbitmq
linweidong19 小时前
多级缓存系统设计:从本地到分布式,打造高性能利器
分布式·缓存·消息队列·雪崩·java面经·击穿·消费端
西***634719 小时前
怕故障?怕扩展难?分布式可视化控制:给足场景安全感
分布式·数据可视化