分散式系統全域性唯一Id(SnowFlake)雪花演算法實現
簡介
由於工作中需要提供通用的唯一ID生成方案,調研了目前市面上通用的解決方案,最終經過彙總,解決了(SnowFlake)雪花演算法的坑,時鐘回撥問題
其中最主要的就是 處理時鐘回撥 ,生成的規則是傳入伺服器的唯一workId,根據workId生成id
程式碼
package com.example.demo;
/**
* @Author: rumenxiaobaidog
* @Date: 2020/12/15
* @Desc: 雪花演算法生成唯一id 處理了時鐘回撥的坑
*/
public class SnowFlakeWorkerUtils {
private volatile static SnowFlakeWorkerUtils snowFlakeWorkerInstance;
// 1位標識部分 - 41位時間戳部分 - 10位節點部分 12位序列號部分
/** 0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000 */
/**
* 起始的時間戳
*/
private final static long START_STMP = 1288834974657L;
/**
* 每一部分佔用的位數
*/
// 序列號佔用的位數
private final static long SEQUENCE_BIT = 12;
// 機器標識佔用的位數
private final static long WORK_BIT = 10;
/**
* WORK_NUM最大值 1023
*/
private final static long MAX_WORK_NUM = -1L ^ (-1L << WORK_BIT);
/**
* SEQUENCE最大值 4095
*/
private final static long MAX_SEQUENCE = -1L ^ (-1L << SEQUENCE_BIT);
/**
* 每一部分向左的位移
*/
private final static long WORK_LEFT = SEQUENCE_BIT;
private final static long TIMESTMP_LEFT = WORK_LEFT + WORK_BIT;
private long workId;
private long sequence = 0L; //序列號
private long lastStmp = -1L; //上一次時間戳
/** 步長, 1024 */
private static long stepSize = 2 << 9;
/** 基礎序列號, 每發生一次時鐘回撥即改變, basicSequence += stepSize */
private long basicSequence = 0L;
private SnowFlakeWorkerUtils(long workId) {
if (workId > MAX_WORK_NUM || workId < 0) {
throw new IllegalArgumentException("datacenterId can't be greater than MAX_DATACENTER_NUM or less than 0");
}
this.workId = workId;
}
private synchronized static SnowFlakeWorkerUtils initSnowFlakeWorker(long workId) {
snowFlakeWorkerInstance = new SnowFlakeWorkerUtils(workId);
return snowFlakeWorkerInstance;
}
public static SnowFlakeWorkerUtils getInstance(long workId) {
if (null == snowFlakeWorkerInstance) {
synchronized (SnowFlakeWorkerUtils.class) {
if (null == snowFlakeWorkerInstance) {
snowFlakeWorkerInstance = new SnowFlakeWorkerUtils(workId);
}
}
}
return snowFlakeWorkerInstance;
}
/**
* 產生下一個ID
*/
public synchronized long nextId() {
long currStmp = getNewstmp();
if (currStmp < lastStmp) {
return handleClockBackwards(currStmp);
}
if (currStmp == lastStmp) {
// 相同毫秒內,序列號自增
sequence = (sequence + 1) & MAX_SEQUENCE;
// 同一毫秒的序列數已經達到最大
if (sequence == 0L) {
currStmp = getNextMill();
}
} else {
// 不同毫秒內,序列號置為 basicSequence
sequence = basicSequence;
}
lastStmp = currStmp;
return (currStmp - START_STMP) << TIMESTMP_LEFT // 時間戳部分
| workId << WORK_LEFT // 節點部分
| sequence; // 序列號部分
}
/**
* 處理時鐘回撥
*/
private long handleClockBackwards(long currStmp) {
basicSequence += stepSize;
if (basicSequence == MAX_SEQUENCE + 1) {
basicSequence = 0;
currStmp = getNextMill();
}
sequence = basicSequence;
lastStmp = currStmp;
return (currStmp - START_STMP) << TIMESTMP_LEFT // 時間戳部分
| workId << WORK_LEFT // 節點部分
| sequence; // 序列號部分
}
private long getNextMill() {
long mill = getNewstmp();
while (mill <= lastStmp) {
mill = getNewstmp();
}
return mill;
}
private long getNewstmp() {
return System.currentTimeMillis();
}
public static void main(String[] args) {
//workId 可根據不同的機器標識唯一的id
Long workId = 1L;
for (int i = 0; i < 100; i++) {
long nextId = SnowFlakeWorkerUtils.getInstance(workId).nextId();
System.out.println(nextId);
}
}
}
基於github開源的SnowFlake加以改進,處理了時鐘回撥
特別感謝: https://github.com/beyondfengyu/SnowFlake/blob/master/SnowFlake.java
希望給大家提供幫助,謝謝
相關文章
- Java使用雪花演算法實現生成全域性唯一idJava演算法
- Snowflake 全域性唯一Id 生成
- 分散式全域性唯一ID分散式
- 分散式唯一ID生成方案選型!詳細解析雪花演算法Snowflake分散式演算法
- 全域性唯一ID生成常見的幾種方式和twitter/snowflake(雪花演算法)解析演算法
- PHP 實現 Snowflake 生成分散式唯一 IDPHP分散式
- 分散式唯一id:snowflake演算法思考分散式演算法
- 框架篇:分散式全域性唯一ID框架分散式
- 分散式唯一ID解決方案-雪花演算法分散式演算法
- 【高併發】之分散式全域性唯一 ID分散式
- Twitter雪花演算法SnowFlake演算法的java實現演算法Java
- 分散式 ID 生成演算法 — SnowFlake分散式演算法
- 分散式雪花演算法獲取id分散式演算法
- 在 Java 中利用 redis 實現分散式全域性唯一標識服務JavaRedis分散式
- 忘掉 Snowflake,感受一下效能高出 587 倍的全域性唯一 ID 生成演算法演算法
- 分散式全域性ID生成方案分散式
- Twitter的分散式雪花演算法 SnowFlake 每秒自增生成26個萬個可排序的ID (Java版)分散式演算法排序Java
- 雪花演算法【分散式ID問題】【劉新宇】演算法分散式
- 分散式系統中唯一 ID 的生成方法分散式
- 分散式ID系列(5)——Twitter的雪法演算法Snowflake適合做分散式ID嗎分散式演算法
- 分散式:分散式系統下的唯一序列分散式
- 基於雪花演算法生成分散式ID(Java版)演算法分散式Java
- 如何在Java服務中實現分散式ID生成:雪花演算法與UUID的對比Java分散式演算法UI
- Twitter的分散式自增ID演算法snowflake (Java版)分散式演算法Java
- Oracle分散式系統中的全域性資料庫名Oracle分散式資料庫
- 分散式系統限流演算法分析與實現分散式演算法
- 聽說:分散式ID不能全域性遞增?分散式
- 鴻蒙系統(HarmonyOS)全域性彈窗實現鴻蒙
- 分散式唯一id生成策略分散式
- 分散式系統Session 實現方式分散式Session
- Go 實現雪花演算法Go演算法
- 雪花演算法的實現演算法
- Java 實現系統全域性快捷鍵繫結Java
- SAP UI5 確保控制元件 id 全域性唯一的實現方法UI控制元件
- 全域性唯一ID(GUID)生成方案對比GUI
- 分散式架構篇 | 如何在分散式架構下完美實現“全域性資料一致性”?分散式架構
- 大型分散式系統現場,阿里大牛帶你實戰分散式系統分散式阿里
- 面試基礎之:叢集高併發情況下如何保證分散式唯一全域性Id生成面試分散式