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)
了解更多雪花模型知识,后续补充。