您的位置:首页 > 其它

twitter ID生成算法

2017-08-29 17:56 323 查看
分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。

为了满足Twitter每秒上万条消息的请求,每条消息都必须分配一条唯一的id,这些id还需要一些大致的顺序(方便客户端排序),并且在分布式系统中不同机器产生的id必须不同。

public class IdSeqGenerator {
private final static long twepoch            = 1463108596098L;             //日期起始点

private final long        workerId;
private long              sequence           = 0L;
private long              lastTimestamp      = -1L;

private final static long workerIdBits       = 10L;                        //机器ID占用10bits
private final static long sequenceBits       = 12L;                        //序列占用12bits

public final static long  maxWorkerId        = -1L ^ -1L << workerIdBits;  //机器ID 最大值

private final static long timestampLeftShift = sequenceBits + workerIdBits;//时间偏移位
private final static long workerIdShift      = sequenceBits;               //机器ID偏移位

public final static long  sequenceMask       = -1L ^ -1L << sequenceBits;  //序列掩码

public IdSeqGenerator(final long workerId) {
super();
if (workerId > maxWorkerId || workerId < 0) {
throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
}
LogKit.log().info(String.format("worker Id : greater than %d or less than 0", maxWorkerId));
this.workerId = workerId;
}
//生成ID
public synchronized long nextId() {
long timestamp = this.timeGen();
//如果是同一时间生成的,则自增
if (this.lastTimestamp == timestamp) {
this.sequence = (this.sequence + 1) & sequenceMask;
if (this.sequence == 0) {
//生成下一个毫秒级的序列
timestamp = this.tilNextMillis(this.lastTimestamp);
}
} else {
//如果发现是下一个时间单位,则自增序列回0,重新自增
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 << workerIdShift) | (this.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) {
Map<Long, Long> store = new ConcurrentHashMap<>();

final int MAX_POOL_SIZE = 4;
ExecutorService service = Executors.newFixedThreadPool(MAX_POOL_SIZE);
for (int i = 0; i < MAX_POOL_SIZE; i++) {
final int x = i;
service.execute(() -> {
IdSeqGenerator seqKit = new IdSeqGenerator(x);
for (int j = 0; j < 100; j++) {
long id = seqKit.nextId();
if (store.containsKey(id)) {
System.out.println("dublicate:" + id);
} else {
store.put(id, id);
System.out.println(id);
}
}

System.out.println("thread" + x + " end.");
});
}

service.shutdown();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: