0 | 0001100 10100010 10111110 10001001 01011100 00 | 10001 | 1 1001 | 0000 00000000
Twitter在把存儲系統從MySQL遷移到Cassandra的過程中由于Cassandra沒有順序ID生成機制,snowflake 算法是 twitter 開源的分布式 id 生成算法,
就是
把一個 64 位的 long 型的 id,
1 個 bit 是不用的,
用其中的 41 bit 作為毫秒數,
用 10 bit 作為工作機器 id,
12 bit 作為序列號。
于是自己開發了一套全局唯一ID生成服務:Snowflake。
1 bit:不用,為啥呢?因為二進制里第一個 bit 為如果是 1,那么都是負數,但是我們生成的 id 都是正數,所以第一個 bit 統一都是 0。
41位的時間序列(精確到毫秒,41位的長度可以使用69年)
10位的機器標識(10位的長度最多支持部署1024個節點)
12位的計數順序號(12位的計數順序號支持每個節點每毫秒產生4096個ID序號)
最高位是符號位,始終為0。
優點:高性能,低延遲;獨立的應用;按時間有序。
缺點:需要獨立的開發和部署。
package com.NETtyrpc.test.util;public class IdWorker {private final long workerId;private final static long twepoch = 1288834974657L;private long sequence = 0L;private final static long workerIdBits = 4L;public final static long maxWorkerId = -1L ^ -1L << workerIdBits;private final static long sequenceBits = 10L;private final static long workerIdShift = sequenceBits;private final static long timestampLeftShift = sequenceBits + workerIdBits;public final static long sequenceMask = -1L ^ -1L << sequenceBits;private long lastTimestamp = -1L;public IdWorker(final long workerId) {super();if (workerId > this.maxWorkerId || workerId < 0) {throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", this.maxWorkerId));}this.workerId = workerId;}public synchronized long nextId() {long timestamp = this.timeGen();if (this.lastTimestamp == timestamp) {this.sequence = (this.sequence + 1) & this.sequenceMask;if (this.sequence == 0) {System.out.println("###########" + sequenceMask);timestamp = this.tilNextMillis(this.lastTimestamp);}} else {this.sequence = 0;}if (timestamp < this.lastTimestamp) {try {throw new Exception(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds",this.lastTimestamp - timestamp));} catch (Exception e) {e.printStackTrace();}}this.lastTimestamp = timestamp;long nextId = ((timestamp - twepoch << timestampLeftShift)) | (this.workerId << this.workerIdShift)| (this.sequence);System.out.println("timestamp:" + timestamp + ",timestampLeftShift:" + timestampLeftShift + ",nextId:" + nextId+ ",workerId:" + workerId + ",sequence:" + sequence);return nextId;}private long tilNextMillis(final long lastTimestamp) {long timestamp = this.timeGen();while (timestamp <= lastTimestamp) {timestamp = this.timeGen();}return timestamp;}private long timeGen() {return System.currentTimeMillis();}public static void main(String[] args) {IdWorker worker2 = new IdWorker(2);System.out.println(worker2.nextId());}}