1. 程式人生 > >分布式服務自增長唯一ID小結

分布式服務自增長唯一ID小結

mongod ESS 毫秒 long args mas one 10個 bit

1、常用生成唯一ID的方式,例如UUID

2、生成唯一自自增長ID方式:

  例如:

    • Zookeeper的增加ID;
    • redis的incr方法
    • mongodb的objectId

3、采用雪花模型

如下代碼:

  1 /**
  2  * 采用twitter的雪花算法,生成有一定順序且不重復的id,結果類型為64位的long型
  3  */
  4 public class SnowflakeIdUtils {
  5     //集群id
  6     private long datacenterId;
  7     //機器id
  8     private long workerId;
9 //序列號 10 private long sequenceId; 11 12 //集群id的bit位數 13 private long datacenterIdBits = 5L; 14 //機器id的bit位數 15 private long workerIdBits = 5L; 16 //序列號的bit位數 17 private long sequenceIdBits = 12L; 18 19 //集群id的最大編號 20 private long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
21 //機器id的最大編號 22 private long maxWorkerId = -1L ^ (-1L << workerIdBits); 23 //序列號的掩碼 24 private long sequenceIdMask = -1L ^ (-1L << sequenceIdBits); 25 26 //生成最終結果時,集群id需移動的bit位數 27 private long timestampShiftBits = sequenceIdBits + workerIdBits + datacenterIdBits;
28 //生成最終結果時,集群id需移動的bit位數 29 private long datacenterIdShiftBits = sequenceIdBits + workerIdBits; 30 //生成最終結果時,機器id需移動的bit位數 31 private long workerIdShiftBits = sequenceIdBits; 32 33 //去掉過去的時間,即從指定時間(本例以2017-10-12 00:00:00)開始算, 34 // 大約可用69.5年(41位的時間位,最大值換成毫秒,再換算成年,大約69.5年) 35 //1507737600000為從1970-01-01 00:00:00到2017-10-12 00:00:00經過的毫秒數 36 private long pastMills = 1507737600000L; 37 //上一次生成id使用的timestamp ,以毫秒為單位 38 private long lastTimestamp = 1L; 39 40 /** 41 * 若沒有指定集群id和機器id,則默認均為0 42 */ 43 public SnowflakeIdUtils() { 44 this(0, 0); 45 } 46 47 /** 48 * 指定集群id和機器id 49 * 50 * @param datacenterId 51 * @param workerId 52 */ 53 public SnowflakeIdUtils(long datacenterId, long workerId) { 54 if (datacenterId < 0 || datacenterId > maxDatacenterId) { 55 throw new RuntimeException(String.format("datacenterId greater than %d or less than 0", maxDatacenterId)); 56 } 57 if (workerId < 0 || workerId > maxWorkerId) { 58 throw new RuntimeException(String.format("workerId greater than %d or less than 0", maxWorkerId)); 59 } 60 this.datacenterId = datacenterId; 61 this.workerId = workerId; 62 } 63 64 /** 65 * 生成全局唯一的id 66 * 67 * @return 68 */ 69 public synchronized long nextId() { 70 long timestamp = System.currentTimeMillis(); 71 if (timestamp < lastTimestamp) { //出現這種情況,通常是由於機器時間出問題了 72 throw new RuntimeException("machine time error"); 73 } 74 75 //同一時刻生成的id號 76 if (timestamp == lastTimestamp) { 77 sequenceId = (sequenceId + 1) & sequenceIdMask; 78 if (sequenceId == 0) { //說明當前毫秒的序列號用完了,需從下個毫秒數開始重新計數 79 timestamp = nextTimestamp(lastTimestamp); 80 } 81 } else { 82 //否則序列號從0開始 83 sequenceId = 0L; 84 } 85 86 lastTimestamp = timestamp; 87 long id = ((timestamp - pastMills) << timestampShiftBits) 88 | (datacenterId << datacenterIdShiftBits) 89 | (workerId << workerIdShiftBits) 90 | sequenceId; 91 return id; 92 } 93 94 /** 95 * 獲取上次取數毫秒的下一時刻 96 * 97 * @param lastTimestamp 98 * @return 99 */ 100 long nextTimestamp(long lastTimestamp) { 101 long timestamp = System.currentTimeMillis(); 102 while (timestamp <= lastTimestamp) { 103 timestamp = System.currentTimeMillis(); 104 } 105 return timestamp; 106 } 107 108 public static void main(String[] args) throws Exception { 109 SnowflakeIdUtils snowflakeIdGen = new SnowflakeIdUtils(); 110 //測試,生成10個唯一id 111 for (int i = 0; i < 10; i++) { 112 long id = snowflakeIdGen.nextId(); 113 System.out.println(id); 114 } 115 } 116 }

這裏采用的是默認構造生成 SnowflakeIdUtils,如果分布式服務同時調用的話,會出現重復ID,

所以需要加上 集群id(0~31),workerId(0~31)

了解更多雪花模型知識,後續補充。

分布式服務自增長唯一ID小結