专业的JAVA编程教程与资源

网站首页 > java教程 正文

分布式ID生成——雪花算法 分布式id生成器

temp10 2024-12-24 15:47:42 java教程 10 ℃ 0 评论

这个也没啥讲的,上数据库集群,要是按照

数据库实例1:表ID初始值1,步长3;

分布式ID生成——雪花算法 分布式id生成器

数据库实例2:表ID初始值2,步长3;

数据库实例3:表ID初始值3,步长3;

的设置,可以解决ID重复问题,只是要再加一台就不好办了。

还有就是通过Redis的incr自增,因为是原子操作,也可以保证ID不重复。

再有就是zookeeper的持久顺序节点,也可以。

接着就是要说的雪花算法。

生成的ID是一个Long型数字,结构是:

0~时间戳42位(当前时间-开始时间)~数据中心ID5位~机器ID5位~序列号12位

0是符号位,代表正数。

如果我们实际中没有数据中心的概念,可以把机器ID扩充为10位。

另外多说一句,服务端回传Long给前端页面,JS处理Long会损失精度,所以服务端应该将Long转为String再回传。

同一服务集群部署,配置不同数据中心ID和机器ID即可。

/**
 * 雪花分布式ID生成器 0~时间戳42位~数据中心ID5位~机器ID5位~序列号12位
 *
 */
public class SnowFlakeUtils {

    private int dcId;// 数据中心ID,0~31
    private int mId;// 机器ID,0~31

    private long lastTime = -1L;// 上一次时间戳
    private long seq = 0L;// 序列号

    private static final long START_TIME = 1603524605577L;// 最初时间戳

    /**
     * @param dcId 数据中心ID
     * @param mId  机器ID
     */
    public SnowFlakeUtils(int dcId, int mId) {
        // 如果没有数据中心,可以直接把10位都给机器ID,0~1023
        super();
        if (dcId > 31 || dcId < 0) {
            throw new IllegalArgumentException("数据中心ID范围0~31");
        }
        if (mId > 31 || mId < 0) {
            throw new IllegalArgumentException("机器ID范围0~31");
        }
        this.dcId = dcId;
        this.mId = mId;
    }

    public synchronized long getId() {
        long now = Instant.now().toEpochMilli();
        if (now < lastTime) {
            return -1;
        }
        if (now == lastTime) {
            // 时间相同,序号自增
            seq = (seq + 1) & 4095;
            if (seq == 0) {
                // 如果本毫秒内,序列号已经是4095,+1&之后就会变成0,序列号重复。
                // 通过将时间戳向后挪来解决。
                now = this.getNextTime();
            }
        } else {
            // 时间不同,序列号置为0
            seq = 0L;
        }

        lastTime = now;
        long id = (now - SnowFlakeUtils.START_TIME) << 22// 时间戳左移22位
                | dcId << 17// 数据中心ID左移17位
                | mId << 12// 机器ID左移12位
                | seq;
        return id;
    }

    /**
     * 获取下一时间,如果时间<=上一次时间戳,则继续往后获取
     * 
     * @return
     */
    private long getNextTime() {
        long now = Instant.now().toEpochMilli();
        while (now <= lastTime) {
            now = Instant.now().toEpochMilli();
        }
        return now;
    }

    public int getDcId() {
        return dcId;
    }

    public void setDcId(int dcId) {
        this.dcId = dcId;
    }

    public int getmId() {
        return mId;
    }

    public void setmId(int mId) {
        this.mId = mId;
    }

    public long getLastTime() {
        return lastTime;
    }

    public void setLastTime(long lastTime) {
        this.lastTime = lastTime;
    }

    public long getSeq() {
        return seq;
    }

    public void setSeq(long seq) {
        this.seq = seq;
    }
    
    public static void main(String[] args) {
        SnowFlakeUtils sn = new SnowFlakeUtils(1, 1);
        for (int i = 0; i < 2; i++) {
            System.out.println(sn.getId());
            System.out.println(sn.getId());
            System.out.println(sn.getId());
        }

    }

}

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表