分布式—雪花算法生成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() );
    }
}
相关推荐
ly768919 小时前
Redis 分布式锁的边界条件:Redlock 争议、锁续期与客户端崩溃后的互斥失效
数据库·redis·分布式·分布式锁·watchdog·redlock
灯澜忆梦21 小时前
【minio】#5 | MinIO 分布式部署 + HTTPS 部署
分布式·网络协议·https·对象存储·minio
谢亮_vipxieliang1 天前
Spring Cloud 服务治理入门:注册发现、配置中心、网关限流、熔断降级与分布式一致性方案
分布式·spring·spring cloud
樱花落木兰2 天前
分布式登录实战:Session 会话共享改造,Redis 存储用户登录状态
java·javascript·数据库·redis·分布式·缓存
ShineWinsu2 天前
对于Redis:Steam、Geospatial、Hyperloglog、Bitmap、Bitfield类型的解析
数据库·c++·redis·分布式·缓存·面试·zset
Flynt2 天前
Redis Cluster主节点挂了,为什么"高可用"还全员掉线?我把三次kill的记录翻出来了
数据库·redis·分布式
JosieBook2 天前
【数据库】MySQL 实战精通系列 · 第10篇:分库分表与分布式事务实战
数据库·分布式·mysql
梦帮科技3 天前
vLLM / TensorRT-LLM 极限推理:PagedAttention 细粒度物理页表管理与连续批处理(Continuous Batching)实战
数据结构·人工智能·分布式·python·深度学习·算法·vllm
Frank_refuel3 天前
分布式RPC框架实战(二):服务端模块划分与底层设计
分布式·网络协议·rpc
mftang4 天前
EtherCAT协议:从“飞读飞写”机制到分布式时钟同步的实时以太网架构深度解析
分布式·架构·ethercat·分布式时钟·从站控制器