從零到日誌採集索引視覺化、監控報警、rpc trace跟蹤-分散式唯一ID生成
阿新 • • 發佈:2018-12-24
public class UniqueIdGen implements IdGen {
// 開始使用該演算法的時間為: 2017-01-01 00:00:00
private static final long START_TIME = 1483200000000L;
// 時間戳bit數,最多能支援到2050年,首位為標記位(java的long首位是0表示為正數)
private static final int TIME_BITS = 40;
// worker id的bit數,最多支援8192個app和host的組合(即在N個伺服器上每個伺服器部署M個專案,總共部署N*M=8192)
private static final int APP_HOST_ID_BITS = 13;
// 序列號,支援單節點最高1000*1024的併發
private final static int SEQUENCE_BITS = 10;
// 最大的app host id,65535
private final static long MAX_APP_HOST_ID = ~(-1L << APP_HOST_ID_BITS);
// 最大的序列號,127
private final static long MAX_SEQUENCE = ~(-1L << SEQUENCE_BITS);
// app host編號的移位
private final static long APP_HOST_ID_SHIFT = SEQUENCE_BITS;
// 時間戳的移位
private final static long TIMESTAMP_LEFT_SHIFT = APP_HOST_ID_BITS + APP_HOST_ID_SHIFT;
// 該專案的app host id,對應著為某臺機器上的某個專案分配的serviceId(注意區分Span中的serviceId)
private long appHostId;
// 上次生成ID的時間戳
private long lastTimestamp = -1L;
// 當前毫秒生成的序列
private long sequence = 0L;
// 單例
private static volatile UniqueIdGen idGen = null;
/**
* 例項化
* @param appHostId
* @return
*/
public static UniqueIdGen getInstance(long appHostId) {
if (idGen == null) {
synchronized(UniqueIdGen.class) {
if (idGen == null) {
idGen = new UniqueIdGen(appHostId);
}
}
}
return idGen;
}
private UniqueIdGen(long appHostId) {
if (appHostId > MAX_APP_HOST_ID) {
// zk分配的serviceId過大(基本小規模的公司不會出現這樣的問題)
throw new IllegalArgumentException(String.format("app host Id wrong: %d ", appHostId));
}
this.appHostId = appHostId;
}
/**
* 利用twitter的snowflake(做了些微修改)演算法來實現
* @return
*/
@Override
public String nextId() {
return Long.toHexString(this.genUniqueId());
}
/**
* 生成唯一id的具體實現
* @return
*/
private synchronized long genUniqueId() {
long current = System.currentTimeMillis();
if (current < lastTimestamp) {
// 如果當前時間小於上一次ID生成的時間戳,說明系統時鐘回退過,出現問題返回-1
return -1;
}
if (current == lastTimestamp) {
// 如果當前生成id的時間還是上次的時間,那麼對sequence序列號進行+1
sequence = (sequence + 1) & MAX_SEQUENCE;
if (sequence == MAX_SEQUENCE) {
// 當前毫秒生成的序列數已經大於最大值,那麼阻塞到下一個毫秒再獲取新的時間戳
current = this.nextMs(lastTimestamp);
}
} else {
// 當前的時間戳已經是下一個毫秒
sequence = 0L;
}
// 更新上次生成id的時間戳
lastTimestamp = current;
// 進行移位操作生成int64的唯一ID
return ((current - START_TIME) << TIMESTAMP_LEFT_SHIFT)
| (this.appHostId << APP_HOST_ID_SHIFT)
| sequence;
}
/**
* 阻塞到下一個毫秒
* @param timeStamp
* @return
*/
private long nextMs(long timeStamp) {
long current = System.currentTimeMillis();
while (current <= timeStamp) {
current = System.currentTimeMillis();
}
return current;
}
}
// 開始使用該演算法的時間為: 2017-01-01 00:00:00
private static final long START_TIME = 1483200000000L;
// 時間戳bit數,最多能支援到2050年,首位為標記位(java的long首位是0表示為正數)
private static final int TIME_BITS = 40;
// worker id的bit數,最多支援8192個app和host的組合(即在N個伺服器上每個伺服器部署M個專案,總共部署N*M=8192)
private static final int APP_HOST_ID_BITS
// 序列號,支援單節點最高1000*1024的併發
private final static int SEQUENCE_BITS = 10;
// 最大的app host id,65535
private final static long MAX_APP_HOST_ID = ~(-1L << APP_HOST_ID_BITS);
// 最大的序列號,127
private final static long MAX_SEQUENCE = ~(-1L << SEQUENCE_BITS);
// app host編號的移位
private final static long APP_HOST_ID_SHIFT
// 時間戳的移位
private final static long TIMESTAMP_LEFT_SHIFT = APP_HOST_ID_BITS + APP_HOST_ID_SHIFT;
// 該專案的app host id,對應著為某臺機器上的某個專案分配的serviceId(注意區分Span中的serviceId)
private long appHostId;
// 上次生成ID的時間戳
private long lastTimestamp = -1L;
// 當前毫秒生成的序列
private long sequence = 0L;
// 單例
private static volatile
/**
* 例項化
* @param appHostId
* @return
*/
public static UniqueIdGen getInstance(long appHostId) {
if (idGen == null) {
synchronized(UniqueIdGen.class) {
if (idGen == null) {
idGen = new UniqueIdGen(appHostId);
}
}
}
return idGen;
}
private UniqueIdGen(long appHostId) {
if (appHostId > MAX_APP_HOST_ID) {
// zk分配的serviceId過大(基本小規模的公司不會出現這樣的問題)
throw new IllegalArgumentException(String.format("app host Id wrong: %d ", appHostId));
}
this.appHostId = appHostId;
}
/**
* 利用twitter的snowflake(做了些微修改)演算法來實現
* @return
*/
@Override
public String nextId() {
return Long.toHexString(this.genUniqueId());
}
/**
* 生成唯一id的具體實現
* @return
*/
private synchronized long genUniqueId() {
long current = System.currentTimeMillis();
if (current < lastTimestamp) {
// 如果當前時間小於上一次ID生成的時間戳,說明系統時鐘回退過,出現問題返回-1
return -1;
}
if (current == lastTimestamp) {
// 如果當前生成id的時間還是上次的時間,那麼對sequence序列號進行+1
sequence = (sequence + 1) & MAX_SEQUENCE;
if (sequence == MAX_SEQUENCE) {
// 當前毫秒生成的序列數已經大於最大值,那麼阻塞到下一個毫秒再獲取新的時間戳
current = this.nextMs(lastTimestamp);
}
} else {
// 當前的時間戳已經是下一個毫秒
sequence = 0L;
}
// 更新上次生成id的時間戳
lastTimestamp = current;
// 進行移位操作生成int64的唯一ID
return ((current - START_TIME) << TIMESTAMP_LEFT_SHIFT)
| (this.appHostId << APP_HOST_ID_SHIFT)
| sequence;
}
/**
* 阻塞到下一個毫秒
* @param timeStamp
* @return
*/
private long nextMs(long timeStamp) {
long current = System.currentTimeMillis();
while (current <= timeStamp) {
current = System.currentTimeMillis();
}
return current;
}
}