Distributed ID for snowflake implementation
package com.marcosbarbero.cloud.autoconfigure.zuul.ratelimit.support;
import java.util.concurrent.ThreadLocalRandom;
/**
* @date 19-3-27
* @auther jackliang
* @description TODO
*/
public class SimpleFlakeGenerator {
private static class SimpleFlake {
private static SimpleFlake simpleFlake = new SimpleFlake(1, 1, (2 >>> 8));
private long workerId; // machine id assert < 31 bit
private long datacenterId; // application id assert < 31 bit
/**
* The 12-bit count sequence number supports each node to
* generate 4096 ID numbers per millisecond (same machine, same time cut)
*/
//Different serial numbers of different services according to business classification
private long sequence;
private long twepoch = 1553688313603L; // Start using component time difference 2019-3-27 x:x:x:
private long workerIdBits = 5L; // 5 bit
private long datacenterIdBits = 5L; // 5bit
private long sequenceBits = 12L;
private long workerIdShift = sequenceBits;
private long datacenterIdShift = sequenceBits + workerIdBits;
private long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
private long sequenceMask = -1L ^ (-1L << sequenceBits);
private long lastTimestamp = -1L;
private SimpleFlake(long workerId, long datacenterId, long sequence)
{
this.workerId = workerId;
this.datacenterId = datacenterId;
this.sequence = sequence;
}
/**
* Default flake method
*
* @return
*/
public static SimpleFlake getDefaultFlake()
{
return simpleFlake;
}
/**
* Here different instances are cached according to different services
*
* @param workerId
* @param datacenterId
* @param sequence
* @return
*/
public static SimpleFlake getCustomizeFlake(long workerId, long datacenterId, long sequence)
{
return new SimpleFlake(workerId, datacenterId, sequence);
}
public synchronized long nextId()
{
long timestamp = unixCurrentTime();
if (timestamp < lastTimestamp) {
System.err.printf("clock is moving backwards. Rejecting requests until %d.", lastTimestamp);
throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds",
lastTimestamp - timestamp));
}
if (lastTimestamp == timestamp) {
sequence = (sequence + 1) & sequenceMask;
if (sequence == 0) {
timestamp = tilNextMillis(lastTimestamp);
}
} else {
sequence = ThreadLocalRandom.current().nextInt(0, 6);
}
lastTimestamp = timestamp;
return ((timestamp - twepoch) << timestampLeftShift) |
(datacenterId << datacenterIdShift) |
(workerId << workerIdShift) |
sequence;
}
/**
* Secure the next timestamp peak
* @param lastTimestamp
* @return
*/
private long tilNextMillis(long lastTimestamp)
{
long timestamp = unixCurrentTime();
while (timestamp <= lastTimestamp)
{
timestamp = unixCurrentTime();
}
return timestamp;
}
/**
* current time for unix
* @return
*/
private long unixCurrentTime()
{
return System.currentTimeMillis();
}
}
//---------------test---------------
public static void main(String[] args) {
// SimpleFlakeGenerator worker = new SimpleFlakeGenerator(1, 1, 1);
SimpleFlake simpleFlake = SimpleFlake.getDefaultFlake();
for (int i = 0; i < 30; i++) {
System.out.println(simpleFlake.nextId());
}
System.out.println(System.currentTimeMillis());
}
}