SnowFlake雪花算法的介紹及Java實現(工具類)

一、概念

❄ 什麼是雪花算法

SnowFlake算法是Twitter公司出品的開源的分佈式id生成算法
其特點爲 使用一個64 bit的long型的數字作爲全局唯一 id
雪花算法在分佈式系統中的應用十分廣泛 且引入了時間戳 基本保持自增的

❄ 雪花算法字符串各部分的含義

在這裏插入圖片描述

  • 1位符號位 始終爲0
    (這是因爲生成的id都是正數 而在二進制中第一個bit若爲0則不爲負數)
  • 後面是41位時間戳 精確到毫秒級
    41位的長度可以表示2^41-1個毫秒值 也就是說可以使用69年
    時間戳還有一個很重要的作用 可以根據時間進行排序
  • 之後的10位機器標識 前5bit是機房id 後5bit是機器id
    10位的長度表明該服務最多可以部署在2^10臺機器(即1024臺機器)上
  • 最後12位計數序列號
    序列號是一系列的自增id 表示了同一個毫秒內產生的不同id
    可以支持同一節點同一毫秒生成多個id 12位的計數序列號支持每個節點每毫秒產生2^12-1(即4096)個ID序號

❄ 生成過程

  • 1、若某個服務需要生成一個唯一id 則發送一個請求給部署了SnowFlake算法的系統(前提是該SnowFlake算法系統知道自己所在的機房和機器的編號)
  • 2、SnowFlake算法系統接收到該請求後 使用二進制位運算的方式生成一個64bit的long型id 當然 第一個bit是無意義的
  • 3、接着41個bit使用當前時間戳(單位爲毫秒) 然後的5bit設爲該機房的id 剩餘5bit設爲機器的id
  • 4、最後 再判斷當前機房的該機器在這一毫秒內是第幾個請求 給本次生成id的請求後再累加一個序號 作爲id最後的12個bit
    至此 就得到了一個64bit的唯一id 這就是雪花算法

二、代碼實現

工具類:

public class SnowFlakeUtil {

    // 起始時間戳
    private final static long START_STMP = 1480166465631L;

    // 每部分的位數
    private final static long SEQUENCE_BIT = 12; // 序列號佔用位數
    private final static long MACHINE_BIT = 5; // 機器id佔用位數
    private final static long DATACENTER_BIT = 5; // 機房id佔用位數

    // 每部分最大值
    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; // 機房id
    private long machineId; // 機器id
    private long sequence = 0L; // 序列號
    private long lastStmp = -1L; // 上次的時間戳

    public SnowFlakeUtil(long datacenterId, long machineId) {
        if (datacenterId > MAX_DATACENTER_NUM || datacenterId < 0)
        {
            throw new IllegalArgumentException("datacenterId can't be greater than MAX_DATACENTER_NUM or less than 0");
        }
        if (machineId > MAX_MACHINE_NUM || machineId < 0)
        {
            throw new IllegalArgumentException("machineId can't be greater than MAX_MACHINE_NUM or less than 0");
        }
        this.datacenterId = datacenterId;
        this.machineId = machineId;
    }

    // 產生下一個ID
    public synchronized long getNextId() {
        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 {
            // 若在不同毫秒內 則序列號置爲0
            sequence = 0L;
        }
        lastStmp = currStmp;

        return (currStmp - START_STMP) << TIMESTMP_LEFT // 時間戳部分
                | datacenterId << DATACENTER_LEFT // 機房id部分
                | machineId << MACHINE_LEFT // 機器id部分
                | sequence; // 序列號部分
    }

    // 獲取新的毫秒數
    private long getNextMill()
    {
        long mill = getNewstmp();
        while (mill <= lastStmp)
        {
            mill = getNewstmp();
        }
        return mill;
    }

    // 獲取當前的毫秒數
    private long getNewstmp()
    {
        return System.currentTimeMillis();
    }
}

使用:

SnowFlakeUtil snowFlakeUtil = new SnowFlakeSnowFlakeUtil (12,13);
System.out.println(snowFlakeUtil.nextId());

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章