雪花算法生成主键id demo

package com.kids.demo01.snow;

//SnowFlake算法用来生成64位的ID,刚好可以用long整型存储,能够用于分布式系统中生产唯一的ID, 并且生成的ID有大致的顺序。
//在这次实现中,生成的64位ID可以分成5个部分:
//  `0 - 41位时间戳 - 5位数据中心标识 - 5位机器标识 - 12位序列号`
public class SnowFlake {

    private final static long START_STMP = 1480166465631L;
    private final static long SEQUENCE_BIT = 12; //序列号占用的位数
    private final static long MACHINE_BIT = 5;   //机器标识占用的位数
    private final static long DATACENTER_BIT = 5;//数据中心占用的位数
    private final static long MAX_DATACENTER_NUM = -1L ^ (-1L << DATACENTER_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 DATACENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT;
    private final static long TIMESTMP_LEFT = DATACENTER_LEFT + DATACENTER_BIT;

    private long datacenterId;  //数据中心
    private long machineId;     //机器标识
    private long sequence = 0L; //序列号
    private long lastStmp = -1L;//上一次时间戳




    public static void main(String[] args) {
        SnowFlake snowFlake = new SnowFlake(2, 3);

        //生成2个主键
        for (int i = 0; i < 2; i++) {
            System.out.println(snowFlake.nextId());
        }

    }


    public SnowFlake(long datacenterId, long machineId) {
        if (datacenterId > MAX_DATACENTER_NUM || datacenterId < 0) {
            throw new IllegalArgumentException("");
        }
        if (machineId > MAX_MACHINE_NUM || machineId < 0) {
            throw new IllegalArgumentException("");
        }
        this.datacenterId = datacenterId;
        this.machineId = machineId;
    }

    public synchronized long nextId() {
        long currStmp = getNewstmp();
        if (currStmp < lastStmp) {
            throw new RuntimeException("Clock moved backwards.  Refusing to generate id");
        }

        if (currStmp == lastStmp) {
            sequence = (sequence + 1) & MAX_SEQUENCE;
            if (sequence == 0L) {
                currStmp = getNextMill();
            }
        } else {
            sequence = 0L;
        }

        lastStmp = currStmp;

        return (currStmp - START_STMP) << TIMESTMP_LEFT
                | datacenterId << DATACENTER_LEFT
                | machineId << MACHINE_LEFT
                | sequence;
    }

    private long getNextMill() {
        long mill = getNewstmp();
        while (mill <= lastStmp) {
            mill = getNewstmp();
        }
        return mill;
    }

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

 

### 谷粒商城中分布式ID生成——雪花算法的实现与应用 #### 雪花算法的核心原理 雪花算法是一种用于生成全局唯一ID的分布式算法。其核心思想是通过组合多个字段来构建一个64位的整数型ID,具体结构如下: - **1位标志位**:通常固定为0,表示这是一个正数。 - **41位时间戳**:记录毫秒级别的当前时间,相对于某个起始时间(如2022年1月1日),能够支持约69年的有效范围[^1]。 - **5位数据中心ID (datacenterId)** 和 **5位工作节点ID (workerId)**:共同标识不同的机器实例,最多可支持 \(2^{10} = 1024\) 个节点[^2]。 - **12位序列号**:在同一毫秒内生成的不同ID会递增此部分,最大值可达 \(2^{12}-1=4095\)。 这种设计使得每秒钟理论上可以生成多达 \(\text{1ms * 4095}\) 的ID数量,满足大多数高并发场景的需求。 #### Java中的实现方式 在谷粒商城的实际开发过程中,可以通过Java语言实现雪花算法。以下是基于上述理论的一个典型代码示例: ```java public class SnowflakeIdGenerator { private final long workerId; private final long dataCenterId; private static final long WORKER_ID_BITS = 5L; // 工作节点ID长度 private static final long DATA_CENTER_ID_BITS = 5L; // 数据中心ID长度 private static final long SEQUENCE_BITS = 12L; // 序列号长度 private static final long MAX_WORKER_ID = ~(-1L << WORKER_ID_BITS); // 最大工作节点ID private static final long MAX_DATA_CENTER_ID = ~(-1L << DATA_CENTER_ID_BITS); // 最大数据中心ID private static final long SEQUENCE_MASK = ~(-1L << SEQUENCE_BITS); private static final long WORKER_ID_SHIFT = SEQUENCE_BITS; private static final long DATA_CENTER_ID_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS; private static final long TIMESTAMP_LEFT_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS + DATA_CENTER_ID_BITS; private static final long START_TIMESTAMP = 1672531200000L; // 自定义的时间起点(单位:毫秒) private long sequence = 0L; private long lastTimestamp = -1L; public SnowflakeIdGenerator(long workerId, long dataCenterId) { if (workerId > MAX_WORKER_ID || workerId < 0) { throw new IllegalArgumentException("Worker ID is invalid"); } if (dataCenterId > MAX_DATA_CENTER_ID || dataCenterId < 0) { throw new IllegalArgumentException("Data Center ID is invalid"); } this.workerId = workerId; this.dataCenterId = dataCenterId; } public synchronized long nextId() { long timestamp = System.currentTimeMillis(); if (timestamp < lastTimestamp) { throw new RuntimeException("Clock moved backwards."); } if (lastTimestamp == timestamp) { sequence = (sequence + 1) & SEQUENCE_MASK; if (sequence == 0) { // 如果超出序列上限,则等待下一毫秒 timestamp = waitNextMillis(lastTimestamp); } } else { sequence = 0L; } lastTimestamp = timestamp; return ((timestamp - START_TIMESTAMP) << TIMESTAMP_LEFT_SHIFT) | (dataCenterId << DATA_CENTER_ID_SHIFT) | (workerId << WORKER_ID_SHIFT) | sequence; } private long waitNextMillis(long lastTimestamp) { long timestamp = System.currentTimeMillis(); while (timestamp <= lastTimestamp) { timestamp = System.currentTimeMillis(); } return timestamp; } } ``` 这段代码实现了完整的雪花算法逻辑,包括时间戳偏移、节点编号分配以及序列号管理等功能。 #### 在谷粒商城中的实际应用场景 谷粒商城作为一个典型的电商系统,在处理大规模数据存储时采用了分库分表技术。为了确保跨数据库之间的主键不冲突,同时提高性能并减少对外部服务的依赖,选择了雪花算法作为分布式环境下的ID生成方案[^4]。 例如,在订单模块的设计中,当用户提交订单时,系统会调用雪花算法生成唯一的订单ID,并将其保存到对应的分片数据库中。如果用户的`userId`为偶数,则将订单写入`demo_ds_0`;如果是奇数,则写入`demo_ds_1`。这种方式不仅解决了传统UUID带来的冗余问题,还显著提升了查询效率。 另外,在商品上架流程中,当管理员触发SPU信息更新操作时,也会利用类似的机制生成新的版本控制所需的唯一标识符[^5]。 --- #### 总结 综上所述,雪花算法凭借其高效性和可靠性成为谷粒商城解决分布式环境下唯一ID生成难题的重要工具之一。它既保障了业务层面的数据一致性需求,又兼顾了系统的扩展能力与运行效能。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值