SnowFlake算法生成的數據組成結構以下:java
在java中用long類型標識,共64位(每部分用-分開): 0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 0000000000 00算法
/** * 雪花算法<br> * 在java中用long類型標識,共64位(每部分用-分開):<br> * 0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 0000000000 00<br> * 1位標識,0表示正數。<br> * 41位時間戳,當前時間的毫秒減去開始時間的毫秒數。可用 (1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69年。<br> * 5位數據中心標識,可支持(1L << 5) = 32個數據中心。<br> * 5位機器標識,每一個數據中心可支持(1L << 5) = 32個機器標識。<br> * 12位序列號,每一個節點每一毫秒支持(1L << 12) = 4096個序列號。<br> */ public class SnowflakeIdWorker { /** * 機器標識 */ private long workerId; /** * 數據中心標識 */ private long dataCenterId; /** * 序列號 */ private long sequence; /** * 機器標識佔用5位 */ private long workerIdBits = 5L; /** * 數據中心標識佔用5位 */ private long dataCenterIdBits = 5L; /** * 12位序列號 */ private long sequenceBits = 12L; /** * 12位序列號支持的最大正整數 * ....... 00001111 11111111 * 2^12-1 = 4095 */ private long sequenceMask = ~(-1L << sequenceBits); /** * The Worker id shift. * 12位 */ private long workerIdShift = sequenceBits; /** * The Data center id shift. * 12 + 5 = 17位 */ private long dataCenterIdShift = sequenceBits + workerIdBits; /** * The Timestamp shift. * 12 + 5 + 5 = 22位 */ private long timestampShift = sequenceBits + workerIdBits + dataCenterIdBits; /** * 開始時間戳毫秒 */ private long startEpoch = 29055616000L; /** * The Last timestamp. */ private long lastTimestamp = -1L; public SnowflakeIdWorker(long workerId, long dataCenterId, long sequence) { // 檢查workerId是否正常 /* 機器標識最多支持的最大正整數 -1的補碼: 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 -1 左移 5 位,高位溢出,低位補0: 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11100000 取反: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00011111 轉10進制: 16 + 8 + 4 + 2 + 1 = 31 */ long maxWorkerId = ~(-1L << workerIdBits); if (workerId > maxWorkerId || workerId < 0) { throw new IllegalArgumentException(String.format("工做Id不能大於%d或小於0", maxWorkerId)); } /* 數據中心最多支持的最大正整數31 */ long maxDataCenterId = ~(-1L << dataCenterIdBits); if (dataCenterId > maxDataCenterId || dataCenterId < 0) { throw new IllegalArgumentException(String.format("數據中心Id不能大於%d或小於0", maxDataCenterId)); } this.workerId = workerId; this.dataCenterId = dataCenterId; this.sequence = sequence; } private synchronized long nextId() { //獲取當前時間毫秒數 long timestamp = timeGen(); //若是當前時間毫秒數小於上一次的時間戳 if (timestamp < lastTimestamp) { System.err.printf("時鐘發生回調,拒絕生成ID,直到: %d.", lastTimestamp); throw new RuntimeException(String.format("時鐘發生回調, 拒絕爲 %d 毫秒生成ID。", lastTimestamp - timestamp)); } //當前時間毫秒數與上次時間戳相同,增長序列號 if (lastTimestamp == timestamp) { //假設sequence=4095 //(4095 + 1) & 4095 //4096: ....... 00010000 00000000 //4095: ....... 00001111 11111111 // ....... 00000000 00000000 //最終sequence爲0,即sequence發生溢出。 sequence = (sequence + 1) & sequenceMask; //若是發生序列號爲0,即當前毫秒數的序列號已經溢出,則借用下一毫秒的時間戳 if (sequence == 0) { timestamp = tilNextMillis(lastTimestamp); } } else { //當前毫秒數大於上次的時間戳,序列號爲0 sequence = 0; } //更新 lastTimestamp = timestamp; //生成ID算法,左移幾位,則後面加幾個0。 //一、當前時間的毫秒數-開始時間的毫秒數,結果左移22位 // 假設:timestamp - startEpoch = 1 // 二進制: // 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 // 左移22位: // 00000000 00000000 00000000 00000000 00000000 01000000 00000000 00000000 //二、dataCenterId左移17位 // 假設:dataCenterId = 1 // 二進制: // 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 // 左移17位: // 00000000 00000000 00000000 00000000 00000000 00000010 00000000 00000000 //三、workerId左移12位 // 假設:workerId = 1 // 二進制: // 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 // 左移12位: // 00000000 00000000 00000000 00000000 00000000 00000000 00010000 00000000 //四、最後的全部結果按位`或` //假設:sequence = 1 //00000000 00000000 00000000 00000000 00000000 01000000 00000000 00000000 //00000000 00000000 00000000 00000000 00000000 00000010 00000000 00000000 //00000000 00000000 00000000 00000000 00000000 00000000 00010000 00000000 //00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 //00000000 00000000 00000000 00000000 00000000 01000010 00010000 00000001 //結果: 0 - 0000000 00000000 00000000 00000000 00000000 01 - 00001 - 00001 - 0000 00000001 return ((timestamp - startEpoch) << timestampShift) | (dataCenterId << dataCenterIdShift) | (workerId << workerIdShift) | sequence; } /** * 獲取下一秒 * * @param lastTimestamp the last timestamp * @return the long */ private long tilNextMillis(long lastTimestamp) { //獲取當前毫秒數 long timestamp = timeGen(); //只要當前的毫秒數小於上次的時間戳,就一直循環,大於上次時間戳 while (timestamp <= lastTimestamp) { //獲取當前毫秒數 timestamp = timeGen(); } return timestamp; } /** * 獲取當前毫秒數 * * @return the long */ private long timeGen() { return System.currentTimeMillis(); } public static void main(String[] args) { SnowflakeIdWorker worker = new SnowflakeIdWorker(1, 1, 1); for (int i = 0; i < 10000; i++) { long id = worker.nextId(); System.out.println(id); System.out.println(Long.toString(id).length()); System.out.println(Long.toBinaryString(id)); System.out.println(Long.toBinaryString(id).length()); } } }
Tips: 左移幾位,則後面加幾個0。segmentfault
private long workerIdBits = 5L; long maxWorkerId = ~(-1L << workerIdBits);
計算過程:分佈式
sequence = (sequence + 1) & sequenceMask;
計算過程:<br> 假設sequence=4095:<br>post
((timestamp - startEpoch) << timestampShift) | (dataCenterId << dataCenterIdShift) | (workerId << workerIdShift) | sequence
計算過程:this
假設:timestamp - startEpoch = 1<br> 二進制: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001<br> 左移22位: 00000000 00000000 00000000 00000000 00000000 01000000 00000000 00000000<br>code
假設:dataCenterId = 1<br> 二進制: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001<br> 左移17位: 00000000 00000000 00000000 00000000 00000000 00000010 00000000 00000000<br>orm
假設:workerId = 1<br> 二進制: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001<br> 左移12位: 00000000 00000000 00000000 00000000 00000000 00000000 00010000 00000000<br>blog
或
00000000 00000000 00000000 00000000 00000000 01000010 00010000 00000001<br>ip
0 - 0000000 00000000 00000000 00000000 00000000 01 - 00001 - 00001 - 0000 00000001<br> 符合SnowFlake算法數據組成結構。
理解分佈式id生成算法SnowFlake Twitter雪花算法SnowFlake算法的java實現