基于twitter的雪花算法生成不重复id

来源:互联网 发布:精准数据库营销 编辑:程序博客网 时间:2024/06/05 19:19

一、简介

在很多业务场景中,在单台机器或者由多台机器构成的分布式场景中,我们需要生成全局唯一的id。

在这里,将介绍基于twitter的雪花算法,生成全局的、唯一的、基于时间排序的、基本有序的id生成方法。

二、twitter雪花算法的原理

twitter的雪花算法,是将id按二进制比特位切割,不同的位区间,表示不同的含义,也即是不同位区间

的值生成方式不同,从而生成唯一的id。

如位区间可分为时间位区间、集群位区间、机器位区间、自增位区间,这样可在不同时间内、不同集群、

不同机器间,生成全局唯一的id。

三、twitter雪花算法的实例

在此以生成64位(即long型)为例进行介绍(其实区间位可以根据具体的业务需要自行指定)。

1、位区间化分

最高位(即第64位,从右向左数)为符号位,不使用;

41位(第23位到第63位)为时间位,可使用个数为2199023255551个,以毫秒为单位,大约69.5年;

5位(第18位到第22位)为集群位,可使用个数为32个;

5位(第13位到第17位)为机器位,可使用个数为32个;

12位(第1位到第12位)为序列号位,即是从0开始自增,可使用个数为4096个;

2、确定时间位开始计算的时间点

本例以2017-10-12 00:00:00开始计时,那么过去掉的时间(从1970-01-01 00:00:00开始)的毫秒数

为1507737600000,取时间时需要减去这段时间。

四、代码实例

/** * 采用twitter的雪花算法,生成有一定顺序且不重复的id,结果类型为64位的long型 */public class SnowflakeIdGen {    //集群id    private long datacenterId;    //机器id    private long workerId;    //序列号    private long sequenceId;    //集群id的bit位数    private long datacenterIdBits = 5L;    //机器id的bit位数    private long workerIdBits = 5L;    //序列号的bit位数    private long sequenceIdBits = 12L;    //集群id的最大编号    private long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);    //机器id的最大编号    private long maxWorkerId = -1L ^ (-1L << workerIdBits);    //序列号的掩码    private long sequenceIdMask = -1L ^ (-1L << sequenceIdBits);    //生成最终结果时,集群id需移动的bit位数    private long timestampShiftBits = sequenceIdBits + workerIdBits + datacenterIdBits;    //生成最终结果时,集群id需移动的bit位数    private long datacenterIdShiftBits = sequenceIdBits + workerIdBits;    //生成最终结果时,机器id需移动的bit位数    private long workerIdShiftBits = sequenceIdBits;    //去掉过去的时间,即从指定时间(本例以2017-10-12 00:00:00)开始算,    // 大约可用69.5年(41位的时间位,最大值换成毫秒,再换算成年,大约69.5年)    //1507737600000为从1970-01-01 00:00:00到2017-10-12 00:00:00经过的毫秒数    private long pastMills = 1507737600000L;    //上一次生成id使用的timestamp ,以毫秒为单位    private long lastTimestamp = 1L;    /**     * 若没有指定集群id和机器id,则默认均为0     */    public SnowflakeIdGen() {        this(0, 0);    }    /**     * 指定集群id和机器id     *     * @param datacenterId     * @param workerId     */    public SnowflakeIdGen(long datacenterId, long workerId) {        if (datacenterId < 0 || datacenterId > maxDatacenterId) {            throw new RuntimeException(String.format("datacenterId greater than %d or less than 0", maxDatacenterId));        }        if (workerId < 0 || workerId > maxWorkerId) {            throw new RuntimeException(String.format("workerId greater than %d or less than 0", maxWorkerId));        }        this.datacenterId = datacenterId;        this.workerId = workerId;    }    /**     * 生成全局唯一的id     *     * @return     */    public synchronized long nextId() {        long timestamp = System.currentTimeMillis();        if (timestamp < lastTimestamp) {  //出现这种情况,通常是由于机器时间出问题了            throw new RuntimeException("machine time error");        }        //同一时刻生成的id号        if (timestamp == lastTimestamp) {            sequenceId = (sequenceId + 1) & sequenceIdMask;            if (sequenceId == 0) {  //说明当前毫秒的序列号用完了,需从下个毫秒数开始重新计数                timestamp = nextTimestamp(lastTimestamp);            }        } else {            //否则序列号从0开始            sequenceId = 0L;        }        lastTimestamp = timestamp;        long id = ((timestamp - pastMills) << timestampShiftBits)                | (datacenterId << datacenterIdShiftBits)                | (workerId << workerIdShiftBits)                | sequenceId;        return id;    }    /**     * 获取上次取数毫秒的下一时刻     *     * @param lastTimestamp     * @return     */    long nextTimestamp(long lastTimestamp) {        long timestamp = System.currentTimeMillis();        while (timestamp <= lastTimestamp) {            timestamp = System.currentTimeMillis();        }        return timestamp;    }    public static void main(String[] args) throws Exception {        SnowflakeIdGen snowflakeIdGen = new SnowflakeIdGen();        //测试,生成10个唯一id        for (int i = 0; i < 10; i++) {            long id = snowflakeIdGen.nextId();            System.out.println(id);        }    }}

结果输出:

330918199820288
330918199820289
330918199820290
330918199820291
330918199820292
330918199820293
330918199820294
330918199820295
330918199820296
330918199820297