JAVA面試寶典 -《分布式ID生成器:Snowflake優化變種》

🚀 分布式ID生成器:Snowflake優化變種

一場訂單高峰,一次鏈路追蹤,一條消息投遞…你是否想過,它們背后都依賴著一個“低調卻關鍵”的存在——唯一ID。本文將帶你深入理解分布式ID生成器的核心原理與工程實踐,重點解構 Snowflake 及其優化變種,揭示高并發場景下的穩定“發號器”設計。

文章目錄

  • 🚀 分布式ID生成器:Snowflake優化變種
  • 1?? 為什么需要分布式ID?
    • ? UUID 的問題
    • ? 數據庫自增ID的局限
    • ? 傳統方案對比
  • 2?? Snowflake 原理詳解
    • 🧱 Snowflake 結構(64位拆解)
    • 💻 Java 實現(簡化版)
    • 🎯 業務使用建議
    • 🎯 特性總結
  • 3?? 時鐘回撥問題與應對
    • 🧩 常見解決策略:
      • 1.拒絕服務法(默認做法):
      • 2.時間等待法:
      • 3.標記法 + 修正位:
      • 4.雙保險機制:
      • 5.解決方案對比
    • 🧠 總結建議
  • 4?? 美團 Leaf:號段模式 ID
    • 🧱Segment 模式:
      • 關鍵組件說明??:
    • 🧱Snowflake 模式:
      • 關鍵組件說明??:
    • ?架構對比圖示
    • 📌 對比總結
    • 🧠 推薦選型建議
  • 5?? 基于 Redis 的 ID 生成
    • 通過 INCR 命令實現:
    • ?優點
    • ? 注意事項
  • 6?? UUID 與數據庫自增ID對比
    • 推薦做法:
  • 7?? 跨機房部署策略
    • 🧠 推薦策略:
  • 8?? 實戰落地建議
    • ? 部署建議:
  • 🧩 總結與互動

1?? 為什么需要分布式ID?

在微服務系統中,訂單號、日志追蹤ID、消息投遞ID,都必須具備以下特性:

全局唯一(避免沖突)

趨勢遞增(數據庫分頁友好)

高性能生成(高并發不掉鏈子)

? UUID 的問題

UUID.randomUUID().toString();
// 輸出:550e8400-e29b-41d4-a716-446655440000
  • 無序,不適合做數據庫主鍵;
  • 太長(36位字符),不利于存儲和傳輸;
  • 不可讀,不利于排查和追蹤。

? 數據庫自增ID的局限

  • 依賴單點,存在性能瓶頸與擴展困難;
  • 分庫分表難協調;
  • 難以保障全局唯一。

? 傳統方案對比

方案優點缺點適用場景
UUID簡單,無中心化無序,索引效率低小規模系統
數據庫自增簡單,有序擴展性差,有單點風險單機系統
Redis自增性能好持久化風險,成本高緩存層ID補充

性能對比??(單機每秒生成ID數):

數據庫自增:約5,000    
UUID:約100,000      
Snowflake:約1,000,000+

? 引出主角:Snowflake 算法!

2?? Snowflake 原理詳解

Snowflake 是 Twitter 開源的分布式高性能ID生成器,生成的是 64位長整型 ID,支持高并發下毫秒級唯一ID生成。

🧱 Snowflake 結構(64位拆解)

位數含義位寬描述
1符號位1固定為 0
2時間戳41與自定義 epoch 相差的毫秒數
3數據中心 ID5可部署 32 個數據中心
4機器 ID5每個數據中心支持 32 臺機器
5序列號12每毫秒可生成 4096 個 ID
0 | 41 bits timestamp | 5 bits dataCenterId | 5 bits machineId | 12 bits sequence

💻 Java 實現(簡化版)

public class SnowflakeIdGenerator {private final long epoch = 1609459200000L; // 自定義起始時間戳private final long dataCenterIdBits = 5L;private final long workerIdBits = 5L;private final long sequenceBits = 12L;private final long dataCenterIdShift = sequenceBits + workerIdBits;private final long timestampShift = sequenceBits + workerIdBits + dataCenterIdBits;private final long maxSequence = -1L ^ (-1L << sequenceBits);private long dataCenterId;private long workerId;private long lastTimestamp = -1L;private long sequence = 0L;public synchronized long nextId() {long current = System.currentTimeMillis();if (current == lastTimestamp) {sequence = (sequence + 1) & maxSequence;if (sequence == 0) {// 等待下一毫秒while (current <= lastTimestamp) {current = System.currentTimeMillis();}}} else {sequence = 0;}lastTimestamp = current;return ((current - epoch) << timestampShift)| (dataCenterId << dataCenterIdShift)| (workerId << sequenceBits)| sequence;}
}

🎯 業務使用建議

  1. 趨勢遞增??:ID在業務中按時間排序,利于分頁
  2. 索引友好??:64位整數比UUID更節省空間
  3. ??雪崩風險??:避免在整點時刻集中觸發ID生成
  4. 業務編碼??:可在ID中嵌入業務類型前綴

🎯 特性總結

  • 高性能:單機每毫秒可生成 4096 個 ID;
  • 趨勢遞增:可用于索引、分表;
  • 分布式無中心化。

3?? 時鐘回撥問題與應對

什么是時鐘回撥?
假設當前時間是 13:00,系統突然因為 NTP 同步變成 12:59,如果 Snowflake 用的是系統時間,那么后續生成的 ID 可能重復或異常遞減。

🧩 常見解決策略:

1.拒絕服務法(默認做法):

if (current < lastTimestamp) throw new RuntimeException("Clock moved backwards");

2.時間等待法:

while (current < lastTimestamp) {current = System.currentTimeMillis();
}

3.標記法 + 修正位:

增加標記字段表示回撥狀態,優先寫入緩存防止使用。

4.雙保險機制:

  • 使用本地時鐘偏移記錄;
  • 配合外部 NTP 校時同步;
  • 多 ID 實現(Snowflake + Redis 組合備用)。

5.解決方案對比

方案原理概述優點缺點適用場景
? 拒絕服務法一旦發現當前時間小于上一次生成 ID 的時間,則直接拋異常簡單暴力,避免產生錯誤 ID影響服務可用性,強依賴時間準確性非核心服務、穩定時間環境
? 時間等待法檢測到回撥則 sleep() 等待系統時間恢復保證 ID 單調遞增,不拋錯線程阻塞、吞吐下降;等待時間難以控制容忍輕微等待場景,如異步寫單、批處理
? 標記法 + 修正位檢測回撥后增加特殊標識位或偏移位標記異常時間段保留生成能力,且可追蹤異常 IDID 結構更復雜,客戶端需識別異常時間段高并發高可用服務,需自行處理異常標記
? 雙保險機制除本地時間外,結合外部 NTP 同步/Redis記錄最大時間戳等機制精度高、靈活、安全性強系統復雜度增加,外部依賴(如 ZooKeeper/NTP)核心 ID 服務、訂單中心、支付系統

🧠 總結建議

項目類型推薦方案
核心金融/支付系統雙保險 + 標記機制
秒殺、日志等強一致時間等待法 + 限流
弱一致服務標記位/拒絕服務法
內部服務、低并發拒絕服務法或 Redis校時

? 類比比喻:時鐘回撥就像員工誤調鬧鐘提前上班,記錄的工時會亂套。

4?? 美團 Leaf:號段模式 ID

Leaf 提供兩種模式:Segment 模式(數據庫號段) 和 Snowflake 模式。

🧱Segment 模式:

在這里插入圖片描述

關鍵組件說明??:

  1. 號段緩存管理器??:管理兩個Buffer的切換
  2. ??當前號段Buffer??:正在使用的ID段
  3. ??預備號段Buffer??:預加載的備用ID段
  4. ??號段表??:存儲各業務的最大ID值
  5. ??業務標記表??:記錄各業務的號段配置
  6. ??ID分配器??:從當前Buffer分配ID

🧱Snowflake 模式:

在這里插入圖片描述

關鍵組件說明??:

  1. ??時間戳生成??:精確到毫秒的當前時間
  2. ????數據中心ID??:區分不同機房/區域
  3. ??機器ID??:區分同一機房的不同機器
  4. ??序列號??:解決同一毫秒內的并發沖突
  5. ????ID組合??:將四部分組合成64位整數

?架構對比圖示

在這里插入圖片描述

📌 對比總結

維度Segment 模式Snowflake 模式
中心化依賴? 依賴 DB / Leaf Server? 去中心化,節點自生成
可用性(宕機影響)? Leaf Server 掛掉無法分配號段? 節點獨立運行
時鐘安全性? 不依賴系統時間? 時鐘回撥將導致重復 ID
ID 有序性? 單調遞增? 趨勢遞增,但可能存在跳躍
實現難度? 簡單,易擴展? 需要位運算、時鐘安全等細節處理
跨語言支持? Leaf 提供 HTTP 接口? 需每種語言自行實現或提供 SDK
最佳使用場景單據號、訂單號、分頁要求有序的數據日志鏈路、消息唯一標識、非強排序業務

🧠 推薦選型建議

業務場景推薦方案
支付訂單、發票號等需單調遞增? Segment 模式
日志追蹤ID、MQ消息ID等? Snowflake 模式
全局 ID 服務、集群穩定性高? Snowflake 模式
分布式系統中異地雙中心部署? Segment + Redis

5?? 基于 Redis 的 ID 生成

通過 INCR 命令實現:

String key = "order:20230715";
Long id = redisTemplate.opsForValue().increment(key);
String fullId = "ORD" + LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE) + id;

?優點

  • 實現簡單;
  • 自帶原子性;
  • 支持 Redis 集群高可用。

? 注意事項

  • Redis 持久化(AOF + RDB)開啟;
  • 主從同步時 ID 不一致可能造成問題;
  • 可以搭配 UUID/時間戳前綴降低沖突概率。

6?? UUID 與數據庫自增ID對比

特性UUID自增ID
唯一性本地唯一
可讀性差(無語義)
排序性無序有序
分布式支持天生支持不支持
索引性能差(隨機分布)好(遞增)
應用場景分布式服務標識、業務追蹤小型單體服務主鍵

推薦做法:

  • 主鍵用分布式 Snowflake ID;
  • 業務追蹤用 UUID;
  • 索引字段避免用 UUID!

7?? 跨機房部署策略

在多 IDC、多區域部署時,應考慮 ID 生成器的:

  • 數據中心ID 配置是否沖突;
  • 時間戳是否同步;
  • 網絡分區是否影響寫入。

🧠 推薦策略:

  • 手動劃分 dataCenterId 區段;
  • 使用 ZooKeeper 分配 workerId;
  • Leaf 主數據中心提供服務,其他副本可降級使用 Redis 方案;
  • ID 服務盡量內嵌 SDK 本地生成,減少跨機房通信。

8?? 實戰落地建議

場景推薦方案
訂單、支付、日志鏈路Snowflake
業務唯一編碼(人可讀)Leaf + 前綴規則
用戶ID/設備IDRedis + ID段緩存
高一致性服務下 ID數據庫號段/Leaf

? 部署建議:

  • 單獨部署 ID 生成服務(Leaf/ID Center);
  • 對外以 RPC 接口形式暴露;
  • 接入方 SDK 本地緩存 ID;
  • 加入監控 + 限流機制防雪崩。

🧩 總結與互動

一個優秀的分布式 ID 方案,應滿足:

? 高可用,穩定生成;
? 趨勢遞增,適配數據庫;
? 跨服務、跨機房、跨時區都不重;
? 不受時鐘回撥影響;

💬 你在項目中用的是什么分布式 ID 方案?踩過哪些坑?歡迎評論區留言討論交流!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/89181.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/89181.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/89181.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

蘋果的機器學習框架將支持英偉達的CUDA平臺

蘋果專為Apple Silicon設計的MLX機器學習框架即將迎來CUDA后端支持&#xff0c;這意義重大。原因如下。 這項開發工作由GitHub開發者zcbenz主導&#xff08;據AppleInsider報道&#xff09;&#xff0c;他于數月前開始構建CUDA支持的原型。此后他將項目拆分為多個模塊&#xff…

golang語法-----變量、常量

變量1、聲明與初始化&#xff08;1&#xff09;標準聲明 (先聲明&#xff0c;后賦值)var age int // 聲明一個 int 類型的變量 age&#xff0c;此時 age 的值是 0 fmt.Println(age) // 輸出: 0age 30 // 給 age 賦值 fmt.Println(age) // 輸出: 30//int 的零…

Jenkins+Docker(docker-compose、Dockerfile)+Gitee實現自動化部署

項目目錄結構 project-root/ ├── pom.xml ├── docker │ ├── copy.sh │ ├── file │ │ ├── jar │ │ │ └── 存放執行copy.sh以后jar包的位置 │ │ └── Dockerfile │ └── docker-compose.yml ├── docker-only-test │ ├─…

TASK01【datawhale組隊學習】地瓜機器人具身智能概述

https://github.com/datawhalechina/ai-hardware-robotics 參考資料地址 具身智能&#xff08;Embodied AI&#xff09; 具身智能 智能的大腦 行動的身體。 比例&#xff08;Proportional&#xff09;、積分&#xff08;Integral&#xff09;、微分&#xff08;Derivative&a…

uni-app 配置華為離線推送流程

1、首先需要創建一個華為開發者賬號&#xff0c;我這個是個人開發賬號 申請開發者賬號 2、去AppGallery Connect登陸我們剛剛創建好的賬號&#xff0c;點擊頁面的APP進入到如下3 AppGallery Connect ????? ?3、在AppGallery Connect 網站中創建一個 Android應用、點擊…

當下主流攝像頭及其核心參數詳解

&#x1f4d6; 推薦閱讀&#xff1a;《Yocto項目實戰教程:高效定制嵌入式Linux系統》 &#x1f3a5; 更多學習視頻請關注 B 站&#xff1a;嵌入式Jerry 當下主流攝像頭及其核心參數詳解 一、攝像頭發展概述 攝像頭作為現代智能設備&#xff08;如手機、安防、車載、工業等&am…

下載了docker但是VirtualBox突然啟動不了了

今天下docker后發現 eNSP 路由器&#xff0c;防火墻啟動不了了去virtualbox檢查的時候發現無法啟動&#xff1a;報錯&#xff1a;不能為虛擬電腦 AR_Base 打開一個新任務.Raw-mode is unavailable courtesy of Hyper-V. (VERR_SUPDRV_NO_RAW_MODE_HYPER_V_ROOT).返回代碼: E_F…

C++11之lambda表達式與包裝器

lambda與包裝器lambda語法捕捉列表lambda的應用lambda的原理包裝器functionbindlambda語法 lambda 表達式本質是?個匿名函數對象&#xff0c;跟普通函數不同的是他可以定義在函數內部。 lambda 表達式語法使?層??沒有類型&#xff0c;所以我們?般是?auto或者模板參數定義…

有痛呻吟!!!

XiTuJueJin:YYDS 分盤 有些平臺吃相太難看&#xff0c;同樣的文章&#xff0c;我還先選擇現在這里發布&#xff0c;TMD. 莫名其妙將我的文章設置為僅VIP可見&#xff0c;還是今天才發現&#xff0c;之前只是將一兩篇設置為僅VIP可見&#xff0c;今天突然發現這種標識的都自動…

2025年7-9月高含金量數學建模競賽清單

2025年7-9月高含金量數學建模競賽 ——“高教社杯”國賽 & “華為杯”研賽作為過來人&#xff0c;真心覺得參加數學建模比賽是我本科階段做的最值的事之一。 它鍛煉的那種把實際問題轉化成模型求解的思維&#xff0c;對做研究、寫論文甚至以后工作都幫助很大。我當時就是靠…

SpringBoot為什么使用new RuntimeException() 來獲取調用棧?

為什么不直接使用 Thread.currentThread().getStackTrace()&#xff1f;這確實看起來有點“奇怪”或者“繞”&#xff0c;但其實這是 Java 中一種非常常見、巧妙且合法的技巧&#xff0c;用于在運行時動態獲取當前代碼的調用棧信息。Spring 選擇用 new RuntimeException().getS…

小白成長之路-haproxy負載均衡

文章目錄一、概述1、HAProxy簡介2、HAProxy特點和優點&#xff1a;3、HAProxy保持會話的三種解決方法4、HAProxy的balance 8種負載均衡算法1&#xff09;RR&#xff08;Round Robin&#xff09;2&#xff09;LC&#xff08;Least Connections&#xff09;3&#xff09;SH&#…

Kafka 與 RocketMQ 消息確認機制對比分析

目錄 生產者消息確認機制 Kafka 生產者 ACK 機制 RocketMQ 生產者確認機制 消費者消息確認機制 Kafka 消費者確認機制 RocketMQ 消費者確認機制 核心差異對比 選型建議 消息確認機制是分布式消息中間件的核心功能之一&#xff0c;它直接關系到消息傳遞的可靠性和系統性能…

C/C++---rdbuf()函數

在C中&#xff0c;rdbuf() 是I/O流庫中的一個核心成員函數&#xff0c;主要用于訪問和操作流對象的緩沖區。這個函數在底層數據處理、流重定向以及自定義流操作等場景中應用廣泛。下面將從多個方面詳細解析 rdbuf() 函數。 基本概念與函數原型 rdbuf() 是 std::basic_ios 類的成…

【LLM】從零到一構建一個小型LLM--MiniGPT

從零到一構建一個小型LLM (Small Language Model)暫時起名為MiniGPT。這個模型將專注于因果語言建模 (Causal Language Modeling)&#xff0c;這是許多現代LLM&#xff08;如GPT系列&#xff09;的核心預訓練任務。模型設計&#xff1a; 我們設計的模型是一個僅包含解碼器 (Dec…

網絡安全威脅下的企業困境與破局技術實踐

前言&#xff1a;網絡安全威脅下的企業困境 在數字化轉型的浪潮中&#xff0c;企業對信息技術的依賴程度日益加深&#xff0c;但隨之而來的網絡安全威脅也愈發嚴峻。據統計&#xff0c;全球每年因網絡安全事件造成的經濟損失高達數萬億美元&#xff0c;其中中小企業更是成為了網…

[RAG system] 信息檢索器 | BM25 Vector | Pickle格式 | HybridRetriever重排序

第六章&#xff1a;信息檢索器 在上一章中&#xff0c;我們成功完成了知識庫攝入流程。這是巨大的進步~ 我們精心準備了文檔"塊"&#xff08;類似獨立的索引卡&#xff09;&#xff0c;并將其存儲在兩套智能歸檔系統中&#xff1a;向量數據庫&#xff08;用于基于含…

Android 高通平臺修改音頻參數效果文件-優化音頻效果

Android 高通平臺如何音頻效果 修改音頻參數效果文件-優化音頻效果 按如下方式修改。 開發云 - 一站式云服務平臺 diff --git a/vendor/qcom/proprietary/mm-audio/audcal/family-b/acdbdata//MTP/workspaceFile.qwsp b/vendor/qcom/proprietary/mm-audio/audcal/family-b/acdb…

Install Docker Engine on UbuntuMySQL

Install Docker Engine on Ubuntu&&MySQL安裝docker安裝mysql客戶端連接數據庫我真氣鼠了&#xff0c;今天得到一個血淚的教訓&#xff0c;以后一定看官方文檔&#xff01;&#xff01;&#xff01;學的課用的centos&#xff0c;指令全是yum&#xff0c;我這邊不通用&a…

智能人體感應模塊HC-SR501應用指南---使用esp32

人體熱釋電探頭紅外感應模塊 人體感應開關HC-SR501藍板新款 綠板-淘寶網 HC-SR501 人體紅外感應電子模塊傳感器熱釋電探頭感應開關RD-624-tmall.com天貓 模塊信息 HC-SR501人體感應開關是一種基于紅外線技術的自動控制模塊&#xff0c;廣泛應用于安防、智能家居和自動控制等領…