在高并发分布式系统中生成唯一ID的方法很多,可以根据项目的特性选择合适的方法。
1、如果分布式系统共用一个oracle数据库,可以用SYS_GUID() 生成32位的唯一ID,或者用sequence自增的方式生成唯一ID。
2、使用UUID,使用UUID有一个弊端:生成是序列过长,没有规律不方便记忆。
3、自己通过代码实现,设计思路是通过时间戳+主机编号+序列号,代码如下:
public class IdWorker {
private final long workerId;
private final static long twepoch = 1515290472631L;
private long sequence = 0L;
private final static long hostIdBits = 7L;//主机占7位,即最大值127
public final static long maxHostId = -1L ^ -1L << hostIdBits;//通过位移计算得到hostId的最大值
private final static long sequenceBits = 10L;//序列占10位,即最大值1023
private final static long hostIdLeftShift = sequenceBits;
private final static long timestampLeftShift = sequenceBits + hostIdBits;
public final static long maxSequence = -1L ^ -1L << sequenceBits;//通过位移计算得到序列的最大值
private long lastTimestamp = -1L;
public IdWorker(final long workerId) {
super();
if (workerId > this.maxHostId || workerId < 0) {
throw new IllegalArgumentException(
String.format("workerId大于 %d,或小于0", this.maxHostId));
}
this.workerId = workerId;
}
public synchronized long nextId() {
long timestamp = this.timeGen();
if (this.lastTimestamp == timestamp) {
this.sequence = (this.sequence + 1) & this.maxSequence;
if (this.sequence == 0) {
System.out.println("sequence大于" + maxSequence);
timestamp = this.tilNextMillis(this.lastTimestamp);
}
} else {
this.sequence = 0;
}
if (timestamp < this.lastTimestamp) {
try {
throw new Exception("当前时间小于上次生成workerId的时间");
} catch (Exception e) {
e.printStackTrace();
}
}
this.lastTimestamp = timestamp;
long nextId = ((timestamp - twepoch << timestampLeftShift)) | (this.workerId << this.hostIdLeftShift)
| (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) {
final IdWorker worker2 = new IdWorker(2);
for (int i = 0; i < 10; i++) {
new Thread(new Runnable() {
public void run() {
while (true) {
worker2.nextId();
}
}
}).start();
}
}
}