【Java后端】Spring Boot 集成雪花算法唯一 ID

Spring Boot 實現基于雪花算法的分布式唯一 ID 生成器

在分布式系統中,我們經常需要生成 全局唯一 ID,比如用戶 ID、訂單號、消息 ID 等。常見的方式有:數據庫自增主鍵、UUID、Redis/Zookeeper 分布式 ID 服務、百度 UidGenerator、美團 Leaf 等。

其中,Twitter 的雪花算法(Snowflake) 是一種輕量級、高性能的分布式唯一 ID 解決方案,被廣泛使用。本文將帶你在 Spring Boot 中實現并集成雪花算法。


一、為什么需要雪花算法?

  1. 數據庫自增 ID

    • 簡單,但在分庫分表和分布式場景下會產生沖突。

  2. UUID

    • 全球唯一,但字符串太長(36 位),不適合做數據庫索引。

  3. 雪花算法(Snowflake)

    • 生成 64 位 long 型 ID,趨勢遞增,性能高,適合分布式環境。


二、雪花算法原理

Snowflake 算法會生成一個 64 bit 的 long 型整數,格式如下:

| 1位符號位(始終為0) | 41位時間戳 | 5位數據中心ID | 5位機器ID | 12位序列號 |
  • 符號位:始終為 0,保證 ID 為正數。

  • 時間戳:當前毫秒時間戳 - 起始時間戳,可用約 69 年。

  • 數據中心 ID:范圍 0~31,可支持 32 個數據中心。

  • 機器 ID:范圍 0~31,每個數據中心支持 32 臺機器。

  • 序列號:范圍 0~4095,每毫秒可生成 4096 個唯一 ID。


三、Spring Boot 實現雪花算法

1. 創建工具類 SnowflakeIdGenerator

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;/*** 雪花算法ID生成器* * 雪花算法生成的ID結構:* 0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000* 1位符號位 + 41位時間戳 + 5位數據中心ID + 5位機器ID + 12位序列號 = 64位* * 特點:* - 生成的ID趨勢遞增* - 整個分布式系統內不會產生重復ID* - 能夠根據時間戳排序* - 每毫秒能夠生成4096個ID*/
@Component
public class SnowflakeIdGenerator {/*** 起始時間戳 (2024-01-01 00:00:00)* 可以使用約69年*/private static final long START_TIMESTAMP = 1704067200000L;/*** 數據中心ID位數*/private static final long DATACENTER_ID_BITS = 5L;/*** 機器ID位數*/private static final long MACHINE_ID_BITS = 5L;/*** 序列號位數*/private static final long SEQUENCE_BITS = 12L;/*** 數據中心ID最大值 (2^5 - 1 = 31)*/private static final long MAX_DATACENTER_ID = ~(-1L << DATACENTER_ID_BITS);/*** 機器ID最大值 (2^5 - 1 = 31)*/private static final long MAX_MACHINE_ID = ~(-1L << MACHINE_ID_BITS);/*** 序列號最大值 (2^12 - 1 = 4095)*/private static final long MAX_SEQUENCE = ~(-1L << SEQUENCE_BITS);/*** 機器ID左移位數*/private static final long MACHINE_ID_SHIFT = SEQUENCE_BITS;/*** 數據中心ID左移位數*/private static final long DATACENTER_ID_SHIFT = SEQUENCE_BITS + MACHINE_ID_BITS;/*** 時間戳左移位數*/private static final long TIMESTAMP_SHIFT = SEQUENCE_BITS + MACHINE_ID_BITS + DATACENTER_ID_BITS;/*** 數據中心ID*/private final long datacenterId;/*** 機器ID*/private final long machineId;/*** 序列號*/private long sequence = 0L;/*** 上次生成ID的時間戳*/private long lastTimestamp = -1L;/*** 構造函數*/public SnowflakeIdGenerator(@Value("${snowflake.datacenter-id:1}") long datacenterId,@Value("${snowflake.machine-id:1}") long machineId) {if (datacenterId > MAX_DATACENTER_ID || datacenterId < 0) {throw new IllegalArgumentException(String.format("數據中心ID必須在0-%d之間", MAX_DATACENTER_ID));}if (machineId > MAX_MACHINE_ID || machineId < 0) {throw new IllegalArgumentException(String.format("機器ID必須在0-%d之間", MAX_MACHINE_ID));}this.datacenterId = datacenterId;this.machineId = machineId;}/*** 生成下一個ID* * @return 唯一ID*/public synchronized long nextId() {long timestamp = getCurrentTimestamp();// 如果當前時間小于上一次ID生成的時間戳,說明系統時鐘回退過,拋出異常if (timestamp < lastTimestamp) {throw new RuntimeException(String.format("系統時鐘回退,拒絕生成ID。時鐘回退了%d毫秒", lastTimestamp - timestamp));}// 如果是同一時間生成的,則進行毫秒內序列if (lastTimestamp == timestamp) {sequence = (sequence + 1) & MAX_SEQUENCE;// 毫秒內序列溢出,等待下一毫秒if (sequence == 0) {timestamp = getNextTimestamp(lastTimestamp);}} else {// 時間戳改變,毫秒內序列重置sequence = 0L;}// 上次生成ID的時間戳lastTimestamp = timestamp;// 移位并通過或運算拼到一起組成64位的IDreturn ((timestamp - START_TIMESTAMP) << TIMESTAMP_SHIFT)| (datacenterId << DATACENTER_ID_SHIFT)| (machineId << MACHINE_ID_SHIFT)| sequence;}/*** 生成字符串格式的ID* * @return 字符串ID*/public String nextIdStr() {return String.valueOf(nextId());}/*** 解析ID獲取生成時間* * @param id 雪花ID* @return 生成時間戳*/public long parseTimestamp(long id) {return (id >> TIMESTAMP_SHIFT) + START_TIMESTAMP;}/*** 解析ID獲取數據中心ID* * @param id 雪花ID* @return 數據中心ID*/public long parseDatacenterId(long id) {return (id >> DATACENTER_ID_SHIFT) & MAX_DATACENTER_ID;}/*** 解析ID獲取機器ID* * @param id 雪花ID* @return 機器ID*/public long parseMachineId(long id) {return (id >> MACHINE_ID_SHIFT) & MAX_MACHINE_ID;}/*** 解析ID獲取序列號* * @param id 雪花ID* @return 序列號*/public long parseSequence(long id) {return id & MAX_SEQUENCE;}/*** 獲取當前時間戳* * @return 當前時間戳*/private long getCurrentTimestamp() {return System.currentTimeMillis();}/*** 獲取下一毫秒時間戳* * @param lastTimestamp 上次時間戳* @return 下一毫秒時間戳*/private long getNextTimestamp(long lastTimestamp) {long timestamp = getCurrentTimestamp();while (timestamp <= lastTimestamp) {timestamp = getCurrentTimestamp();}return timestamp;}/*** 獲取生成器信息* * @return 生成器信息*/public String getGeneratorInfo() {return String.format("SnowflakeIdGenerator[datacenterId=%d, machineId=%d]", datacenterId, machineId);}
}

2. 在 Spring Boot 中配置 Bean


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import javax.annotation.PostConstruct;/*** ID生成工具類* 提供靜態方法方便調用*/
@Component
public class IdUtils {@Autowiredprivate SnowflakeIdGenerator snowflakeIdGenerator;private static SnowflakeIdGenerator staticSnowflakeIdGenerator;// 靜態初始化,確保在沒有Spring容器時也能工作static {if (staticSnowflakeIdGenerator == null) {staticSnowflakeIdGenerator = new SnowflakeIdGenerator(1, 1);}}@PostConstructpublic void init() {if (snowflakeIdGenerator != null) {staticSnowflakeIdGenerator = snowflakeIdGenerator;}}/*** 生成雪花算法ID* * @return 唯一ID*/public static long generateId() {return staticSnowflakeIdGenerator.nextId();}/*** 生成雪花算法ID字符串* * @return 唯一ID字符串*/public static String generateIdStr() {return staticSnowflakeIdGenerator.nextIdStr();}/*** 解析ID獲取生成時間* * @param id 雪花ID* @return 生成時間戳*/public static long parseTimestamp(long id) {return staticSnowflakeIdGenerator.parseTimestamp(id);}/*** 解析ID獲取數據中心ID* * @param id 雪花ID* @return 數據中心ID*/public static long parseDatacenterId(long id) {return staticSnowflakeIdGenerator.parseDatacenterId(id);}/*** 解析ID獲取機器ID* * @param id 雪花ID* @return 機器ID*/public static long parseMachineId(long id) {return staticSnowflakeIdGenerator.parseMachineId(id);}/*** 解析ID獲取序列號* * @param id 雪花ID* @return 序列號*/public static long parseSequence(long id) {return staticSnowflakeIdGenerator.parseSequence(id);}/*** 獲取生成器信息* * @return 生成器信息*/public static String getGeneratorInfo() {return staticSnowflakeIdGenerator.getGeneratorInfo();}
}

3. 測試工具類

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;/*** 簡單的雪花算法測試工具* 獨立運行,不依賴Spring容器*/
public class SimpleSnowflakeTest {private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");public static void main(String[] args) {System.out.println("=== 雪花算法ID生成器簡單測試 ===\n");// 創建生成器實例SnowflakeIdGenerator generator = new SnowflakeIdGenerator(1, 1);// 顯示配置信息showInfo(generator);// 基礎功能測試testBasicGeneration(generator);// 批量生成測試testBatchGeneration(generator);// 性能測試testPerformance(generator);// 唯一性測試testUniqueness(generator);// 遞增性測試testIncrement(generator);System.out.println("\n=== 測試完成 ===");}/*** 顯示配置信息*/private static void showInfo(SnowflakeIdGenerator generator) {System.out.println("📋 配置信息:");System.out.println("  數據中心ID: 1");System.out.println("  機器ID: 1");System.out.println("  當前時間: " + LocalDateTime.now().format(FORMATTER));System.out.println();}/*** 基礎ID生成測試*/private static void testBasicGeneration(SnowflakeIdGenerator generator) {System.out.println("🔧 基礎ID生成測試:");// 生成單個IDlong id1 = generator.nextId();System.out.println("  單個ID: " + id1);// 連續生成幾個IDSystem.out.println("  連續生成5個ID:");for (int i = 0; i < 5; i++) {long id = generator.nextId();System.out.println("    ID " + (i + 1) + ": " + id);}System.out.println();}/*** 批量生成測試*/private static void testBatchGeneration(SnowflakeIdGenerator generator) {System.out.println("📦 批量生成測試:");int count = 10;List<Long> ids = new ArrayList<>();long startTime = System.currentTimeMillis();for (int i = 0; i < count; i++) {ids.add(generator.nextId());}long endTime = System.currentTimeMillis();System.out.println("  生成 " + count + " 個ID耗時: " + (endTime - startTime) + "ms");System.out.println("  生成的ID:");for (int i = 0; i < ids.size(); i++) {System.out.println("    " + (i + 1) + ": " + ids.get(i));}System.out.println();}/*** 性能測試*/private static void testPerformance(SnowflakeIdGenerator generator) {System.out.println("? 性能測試:");int testCount = 100000;System.out.println("  單線程性能測試 (" + testCount + " 個ID):");long startTime = System.currentTimeMillis();for (int i = 0; i < testCount; i++) {generator.nextId();}long endTime = System.currentTimeMillis();long duration = endTime - startTime;double avgTimePerId = (double) duration / testCount;double idsPerSecond = testCount * 1000.0 / duration;System.out.println("    總耗時: " + duration + "ms");System.out.println("    平均每個ID: " + String.format("%.4f", avgTimePerId) + "ms");System.out.println("    每秒生成: " + String.format("%.0f", idsPerSecond) + " 個ID");System.out.println();}/*** 唯一性測試*/private static void testUniqueness(SnowflakeIdGenerator generator) {System.out.println("🔑 唯一性測試:");int testCount = 100000;Set<Long> ids = ConcurrentHashMap.newKeySet();long startTime = System.currentTimeMillis();for (int i = 0; i < testCount; i++) {Long id = generator.nextId();ids.add(id);}long endTime = System.currentTimeMillis();System.out.println("  生成ID數量: " + testCount);System.out.println("  唯一ID數量: " + ids.size());System.out.println("  唯一性測試: " + (ids.size() == testCount ? "? 通過" : "? 失敗"));System.out.println("  測試耗時: " + (endTime - startTime) + "ms");System.out.println();}/*** 遞增性測試*/private static void testIncrement(SnowflakeIdGenerator generator) {System.out.println("📈 遞增性測試:");int testCount = 100;List<Long> ids = new ArrayList<>();// 生成測試IDfor (int i = 0; i < testCount; i++) {ids.add(generator.nextId());}// 檢查遞增性boolean isIncreasing = true;int nonIncreasingCount = 0;for (int i = 1; i < ids.size(); i++) {if (ids.get(i) <= ids.get(i - 1)) {isIncreasing = false;nonIncreasingCount++;}}System.out.println("  測試ID數量: " + testCount);System.out.println("  遞增性測試: " + (isIncreasing ? "? 通過" : "? 失敗"));if (!isIncreasing) {System.out.println("  非遞增數量: " + nonIncreasingCount);}// 顯示前幾個和后幾個IDSystem.out.println("  前5個ID:");for (int i = 0; i < Math.min(5, ids.size()); i++) {System.out.println("    " + (i + 1) + ": " + ids.get(i));}if (ids.size() > 5) {System.out.println("  后5個ID:");for (int i = ids.size() - 5; i < ids.size(); i++) {System.out.println("    " + (i + 1) + ": " + ids.get(i));}}System.out.println();}/*** 演示ID解析功能*/private static void testIdParsing() {System.out.println("🔍 ID解析測試:");// 創建生成器SnowflakeIdGenerator generator = new SnowflakeIdGenerator(1, 1);Long testId = generator.nextId();System.out.println("  測試ID: " + testId);// 解析ID的各個部分long timestamp = IdUtils.parseTimestamp(testId);long datacenterId = IdUtils.parseDatacenterId(testId);long machineId = IdUtils.parseMachineId(testId);long sequence = IdUtils.parseSequence(testId);LocalDateTime generatedTime = LocalDateTime.ofInstant(java.time.Instant.ofEpochMilli(timestamp), java.time.ZoneId.systemDefault());System.out.println("  解析結果:");System.out.println("    時間戳: " + timestamp);System.out.println("    生成時間: " + generatedTime.format(FORMATTER));System.out.println("    數據中心ID: " + datacenterId);System.out.println("    機器ID: " + machineId);System.out.println("    序列號: " + sequence);// 計算ID生成到現在的時間差long age = System.currentTimeMillis() - timestamp;System.out.println("    ID年齡: " + age + "ms");System.out.println();}/*** 演示不同配置的生成器*/private static void testDifferentConfigurations() {System.out.println("??  不同配置測試:");// 創建不同配置的生成器SnowflakeIdGenerator generator1 = new SnowflakeIdGenerator(1, 1);SnowflakeIdGenerator generator2 = new SnowflakeIdGenerator(1, 2);SnowflakeIdGenerator generator3 = new SnowflakeIdGenerator(2, 1);System.out.println("  數據中心1-機器1: " + generator1.nextId());System.out.println("  數據中心1-機器2: " + generator2.nextId());System.out.println("  數據中心2-機器1: " + generator3.nextId());System.out.println();}
}

直接運行

4. 在業務中使用


import com.example.common.util.IdUtils;
import com.example.common.util.SnowflakeIdGenerator;
import com.example.common.web.ApiResponse;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** ID生成控制器* 提供雪花算法ID的生成和解析服務*/
@RestController
@RequestMapping("/common/id")
@Api(tags = "ID生成服務")
public class IdController {@Autowiredprivate SnowflakeIdGenerator snowflakeIdGenerator;/*** 生成單個雪花算法ID*/@GetMapping("/generate")@ApiOperation("生成單個雪花算法ID")public ApiResponse<Map<String, Object>> generateId() {long id = IdUtils.generateId();Map<String, Object> result = new HashMap<>();result.put("id", id);result.put("idStr", String.valueOf(id));result.put("timestamp", System.currentTimeMillis());result.put("generatedAt", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));return ApiResponse.success(result);}/*** 生成字符串格式的雪花算法ID*/@GetMapping("/generate/string")@ApiOperation("生成字符串格式的雪花算法ID")public ApiResponse<Map<String, Object>> generateIdString() {String idStr = IdUtils.generateIdStr();Map<String, Object> result = new HashMap<>();result.put("idStr", idStr);result.put("id", Long.parseLong(idStr));result.put("timestamp", System.currentTimeMillis());result.put("generatedAt", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));return ApiResponse.success(result);}/*** 批量生成雪花算法ID*/@GetMapping("/generate/batch")@ApiOperation("批量生成雪花算法ID")public ApiResponse<Map<String, Object>> generateBatchIds(@ApiParam("生成數量,最大100") @RequestParam(defaultValue = "10") int count) {if (count <= 0 || count > 100) {return ApiResponse.error(400, "生成數量必須在1-100之間");}List<Long> ids = new ArrayList<>();List<String> idStrs = new ArrayList<>();for (int i = 0; i < count; i++) {long id = IdUtils.generateId();ids.add(id);idStrs.add(String.valueOf(id));}Map<String, Object> result = new HashMap<>();result.put("count", count);result.put("ids", ids);result.put("idStrs", idStrs);result.put("timestamp", System.currentTimeMillis());result.put("generatedAt", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));return ApiResponse.success(result);}/*** 解析雪花算法ID*/@GetMapping("/parse/{id}")@ApiOperation("解析雪花算法ID")public ApiResponse<Map<String, Object>> parseId(@ApiParam("要解析的雪花算法ID") @PathVariable Long id) {try {long timestamp = IdUtils.parseTimestamp(id);long datacenterId = IdUtils.parseDatacenterId(id);long machineId = IdUtils.parseMachineId(id);long sequence = IdUtils.parseSequence(id);LocalDateTime generatedTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), ZoneId.systemDefault());Map<String, Object> result = new HashMap<>();result.put("originalId", id);result.put("originalIdStr", String.valueOf(id));result.put("timestamp", timestamp);result.put("generatedTime", generatedTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));result.put("datacenterId", datacenterId);result.put("machineId", machineId);result.put("sequence", sequence);// 計算ID生成到現在的時間差long timeDiff = System.currentTimeMillis() - timestamp;result.put("ageMs", timeDiff);result.put("ageSeconds", timeDiff / 1000);result.put("ageMinutes", timeDiff / (1000 * 60));return ApiResponse.success(result);} catch (Exception e) {return ApiResponse.error(400, "無效的雪花算法ID: " + e.getMessage());}}/*** 批量解析雪花算法ID*/@PostMapping("/parse/batch")@ApiOperation("批量解析雪花算法ID")public ApiResponse<Map<String, Object>> parseBatchIds(@ApiParam("要解析的ID列表") @RequestBody List<Long> ids) {if (ids == null || ids.isEmpty()) {return ApiResponse.error(400, "ID列表不能為空");}if (ids.size() > 50) {return ApiResponse.error(400, "一次最多解析50個ID");}List<Map<String, Object>> results = new ArrayList<>();List<String> errors = new ArrayList<>();for (Long id : ids) {try {long timestamp = IdUtils.parseTimestamp(id);long datacenterId = IdUtils.parseDatacenterId(id);long machineId = IdUtils.parseMachineId(id);long sequence = IdUtils.parseSequence(id);LocalDateTime generatedTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), ZoneId.systemDefault());Map<String, Object> result = new HashMap<>();result.put("originalId", id);result.put("timestamp", timestamp);result.put("generatedTime", generatedTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));result.put("datacenterId", datacenterId);result.put("machineId", machineId);result.put("sequence", sequence);results.add(result);} catch (Exception e) {errors.add("ID " + id + " 解析失敗: " + e.getMessage());}}Map<String, Object> response = new HashMap<>();response.put("totalCount", ids.size());response.put("successCount", results.size());response.put("errorCount", errors.size());response.put("results", results);if (!errors.isEmpty()) {response.put("errors", errors);}return ApiResponse.success(response);}/*** 獲取ID生成器信息*/@GetMapping("/info")@ApiOperation("獲取ID生成器信息")public ApiResponse<Map<String, Object>> getGeneratorInfo() {String generatorInfo = IdUtils.getGeneratorInfo();// 生成一個示例ID用于展示long sampleId = IdUtils.generateId();Map<String, Object> result = new HashMap<>();result.put("generatorInfo", generatorInfo);result.put("sampleId", sampleId);result.put("sampleIdStr", String.valueOf(sampleId));result.put("currentTimestamp", System.currentTimeMillis());result.put("currentTime", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));// 添加雪花算法的基本信息Map<String, Object> algorithmInfo = new HashMap<>();algorithmInfo.put("name", "Snowflake Algorithm");algorithmInfo.put("totalBits", 64);algorithmInfo.put("timestampBits", 41);algorithmInfo.put("datacenterIdBits", 5);algorithmInfo.put("machineIdBits", 5);algorithmInfo.put("sequenceBits", 12);algorithmInfo.put("maxDatacenterId", 31);algorithmInfo.put("maxMachineId", 31);algorithmInfo.put("maxSequence", 4095);algorithmInfo.put("maxIdsPerMs", 4096);algorithmInfo.put("maxIdsPerSecond", 4096000);result.put("algorithmInfo", algorithmInfo);return ApiResponse.success(result);}/*** 健康檢查 - 測試ID生成性能*/@GetMapping("/health")@ApiOperation("ID生成器健康檢查")public ApiResponse<Map<String, Object>> healthCheck() {try {long startTime = System.currentTimeMillis();// 生成100個ID測試性能List<Long> testIds = new ArrayList<>();for (int i = 0; i < 100; i++) {testIds.add(IdUtils.generateId());}long endTime = System.currentTimeMillis();long duration = endTime - startTime;// 驗證ID的唯一性long distinctCount = testIds.stream().distinct().count();boolean isUnique = distinctCount == testIds.size();// 驗證ID的遞增性boolean isIncreasing = true;for (int i = 1; i < testIds.size(); i++) {if (testIds.get(i) <= testIds.get(i - 1)) {isIncreasing = false;break;}}Map<String, Object> result = new HashMap<>();result.put("status", "healthy");result.put("testCount", 100);result.put("durationMs", duration);result.put("avgTimePerIdMs", duration / 100.0);result.put("idsPerSecond", Math.round(100000.0 / duration));result.put("uniqueIds", isUnique);result.put("increasingOrder", isIncreasing);result.put("firstId", testIds.get(0));result.put("lastId", testIds.get(testIds.size() - 1));result.put("checkTime", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));return ApiResponse.success(result);} catch (Exception e) {Map<String, Object> result = new HashMap<>();result.put("status", "unhealthy");result.put("error", e.getMessage());result.put("checkTime", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));return ApiResponse.error(500, "ID生成器健康檢查失敗", result);}}
}

啟動項目后,訪問:

http://localhost:8080/common/id/generate

{"code": 200,"message": "操作成功","data": {"idStr": "225614442879127552","generatedAt": "2025-09-14 21:51:14","id": 225614442879127550,"timestamp": 1757857874896},"timestamp": 1757857874896
}

就能得到一個 分布式唯一 ID


四、雪花算法的優缺點

? 優點

  • 本地生成 ID,高性能、低延遲。

  • 64 位 long 型,適合數據庫主鍵,索引效率高。

  • 趨勢遞增,分庫分表更友好。

?? 缺點

  • 時間回撥問題:如果系統時間被調回,可能導致 ID 重復。

  • workerId 配置:需要保證每臺機器的 workerId 唯一,否則會沖突。

  • 單機生成上限:每毫秒 4096 個 ID,極端場景可能不夠。


五、適用場景

  • 用戶 ID、訂單號、消息 ID 等需要分布式唯一 ID 的場景。

  • 高并發系統中需要性能高、趨勢遞增的 ID。

  • 分庫分表需要按 ID 范圍路由的系統。


六、分布式唯一 ID 生成方案對比

在分布式系統中,唯一 ID 是最基礎的需求。常見的實現方式有以下幾類:

1. 數據庫自增 ID

  • 原理:依賴數據庫主鍵自增特性(AUTO_INCREMENT / Sequence)。

  • 優點

    • 實現簡單,無需額外服務。

    • ID 有序,方便分頁與索引。

  • 缺點

    • 單庫有性能瓶頸,QPS 不高。

    • 擴展到分布式場景需要分庫分表,增加復雜性。

  • 適用場景:小型項目、單體應用。


2. UUID / GUID

  • 原理:基于隨機數、MAC 地址和時間戳生成 128 位 ID。

  • 優點

    • 本地生成,無需依賴第三方服務。

    • 全球唯一,沖突概率極低。

  • 缺點

    • 長度過長(16 字節 / 36 字符),存儲和索引性能差。

    • 無序,不利于數據庫分頁與索引。

  • 適用場景:日志追蹤、分布式追蹤、無需排序的業務。


3. Redis INCR

  • 原理:利用 Redis 的原子自增操作生成 ID。

  • 優點

    • 高并發下性能優秀。

    • 簡單易用,支持多節點共享。

  • 缺點

    • 依賴 Redis,高可用需額外維護。

    • 擴展性依賴 Redis 集群。

  • 適用場景:電商訂單號、消息序列號。


4. Twitter Snowflake

  • 原理:使用 64 位二進制結構(時間戳 + 數據中心 ID + 機器 ID + 序列號)。

  • 優點

    • 高性能,本地生成,不依賴數據庫。

    • 數字型,長度適中,遞增趨勢。

  • 缺點

    • 需要合理分配數據中心和機器 ID。

    • 對系統時鐘依賴強,時鐘回撥會導致重復 ID。

  • 適用場景:高并發系統(訂單 ID、日志 ID、分布式唯一標識)。


5. Zookeeper 分布式 ID

  • 原理:利用 Zookeeper 順序節點特性生成 ID。

  • 優點

    • 強一致性,保證全局唯一遞增。

  • 缺點

    • 性能一般,QPS 不高。

    • 依賴 Zookeeper 集群,運維成本高。

  • 適用場景:金融業務、分布式鎖、強一致性場景。


6. 百度 UidGenerator

  • 原理:基于 Snowflake 改造,支持時間回撥處理,依賴數據庫分配 WorkerID。

  • 優點

    • 高性能,單機 QPS 可達 600 萬。

    • 支持秒級、分級、時級時間單位,靈活。

  • 缺點

    • 依賴數據庫分配 WorkerID。

    • 社區活躍度一般,維護較少。

  • 適用場景:高并發業務(訂單、交易流水、日志 ID)。


7. 美團 Leaf

  • 原理:提供兩種模式:

    1. Segment 模式:基于數據庫號段。

    2. Snowflake 模式:本地生成。

  • 優點

    • 雙模式保證高可用(DB + Snowflake)。

    • 經過美團生產驗證,穩定可靠。

    • Leaf-Snowflake 支持 ZooKeeper 進行 WorkerID 分配,避免沖突。

  • 缺點

    • 系統復雜度較高。

    • 部署依賴 ZooKeeper 或數據庫。

  • 適用場景:大規模分布式系統(訂單 ID、交易號、日志流水號)。


總結對比表

方案長度順序性依賴組件性能 (QPS)復雜度適用場景
數據庫自增 ID有序數據庫小型項目
UUID / GUID無序日志追蹤
Redis INCR有序Redis電商訂單
Snowflake趨勢有序高并發系統
Zookeeper 順序 ID有序ZK金融業務
百度 UidGenerator有序DB極高高并發場景
美團 Leaf有序DB/ZK極高分布式系統

👉 總結:

  • 小型項目:用數據庫自增即可。

  • 日志、追蹤:UUID 最方便。

  • 高并發但輕依賴:Twitter Snowflake / 百度 UidGenerator。

  • 大規模分布式系統:美團 Leaf 最優(生產驗證,雙模式保障)。


七、總結

本文介紹了 雪花算法的原理,并結合 Spring Boot 實現了一個 分布式唯一 ID 生成器
相比 UUID,雪花算法生成的 ID 更短、更高效,適合作為數據庫主鍵。

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

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

相關文章

C語言初嘗試——洛谷

一、C數組&#xff1a;C 語言支持數組數據結構&#xff0c;它可以存儲一個固定大小的相同類型元素的順序集合。數組是用來存儲一系列數據&#xff0c;但它往往被認為是一系列相同類型的變量。聲明數組在 C 中要聲明一個數組&#xff0c;需要指定元素的類型和元素的數量&#xf…

C++八大排序

C排序算法一、概覽二、代碼實現1.冒泡排序2.插入排序3.希爾排序4.堆排序5.選擇排序6.快速排序7.歸并排序三、排序時間、空間復雜度總結排序&#xff0c;是C各大算法當中非常常見的一個步驟&#xff08;過程&#xff09;&#xff0c;通常我們使用便捷的algorithmalgorithmalgori…

每天五分鐘深度學習:深層神經網絡的優勢

本文重點 在人工智能領域,深層神經網絡(DNN)的崛起標志著技術范式的根本性轉變。相較于傳統淺層神經網絡(如單層感知機、線性回歸模型),深層網絡通過引入多層隱藏層,實現了對復雜數據模式的深度解析與高效建模。 深層神經網絡 神經網絡中輸入層表示神經網絡的第0層,…

相機幾何 空間點到像素平面轉換

一個空間中點到像素平面轉換&#xff0c;需要經過1. 空間坐標系轉換到相機坐標系2. 相機坐標系下3D點到相機平面轉換3. 相機平面到像素平面轉換相機三維空間到像素平面轉換1. 3D點到相機平面轉換2. 相機平面到像素平面轉換涉及到單位的轉換&#xff0c;和像素原點到相機平面原點…

webpack5 vue3同一倉庫,不同命令切換項目

技術方案&#xff1a;手動輸入不同的命令&#xff0c;啟動不同項目。實現這種能力本篇文章是通過不同路由劃分&#xff0c;進而實現不同項目的劃分。所以簡單來說就是通過輸入不同命令行在webpack中找到不同項目的路由&#xff0c;進而打不同項目的包&#xff0c;實現項目隔離。…

PowerBI實戰-制作帶有同比及趨勢線的雙柱狀圖

一、引言 今天的PowerBI報表的制作相對有一點復雜&#xff0c;我們直接根據最終展示圖來講解&#xff1a; 可以看到&#xff0c;我們今天要制作的圖像需要包括以下幾點&#xff1a;時間維度的趨勢、兩種不同維度的數據對比、不同數據標簽的展示、不同年份間環比的標簽展示以及…

物聯網智能網關配置教程:實現注塑機數據經基恩士PLC上傳至云平臺

一、項目背景隨著制造業向智能化、信息化方向快速發展&#xff0c;注塑車間作為塑料制品制造的核心環節&#xff0c;面臨著設備協議多樣、數據孤島嚴重、系統集成困難等問題。某大型注塑企業計劃對其老舊車間進行數字化改造&#xff0c;實現設備數據采集、遠程監控與MES系統對接…

【實戰】預警算法--噪聲添加機制

1. 背景 在多變量自聯想預測或異常檢測場景中&#xff0c;我們常使用帶噪自編碼器&#xff08;Denoising AutoEncoder&#xff0c;DAE&#xff09;來訓練模型&#xff0c;使模型能夠從帶噪輸入中重構原始數據。噪聲的添加方式對訓練效果、穩定性以及模型用途有顯著影響。 2. 兩…

ChromaDB探索

關于 ChromaDB、向量與 RAG 系統的核心知識問答總結 ??Q1: ChromaDB 是什么&#xff1f;它在數據庫領域中扮演什么角色&#xff1f;????A:?? ChromaDB 是一款開源的??向量數據庫??。它的核心角色是專門為 AI 應用&#xff08;如語義搜索、推薦系統、RAG&#xff09…

C# 基于halcon的視覺工作流-章33-矩狀測量

C# 基于halcon的視覺工作流-章33-矩狀測量 本章目標&#xff1a; 一、gen_measure_rectangle2準備提取垂直于矩形的直邊&#xff1b; 二、measure_pos 提取垂直于矩形或環形弧的直線邊緣&#xff1b; 三、measure_pairs提取垂直于矩形或環形弧長軸的直邊對&#xff1b; 四、匹配…

Day05_蒼穹外賣——Redis店鋪營業狀態設置

目錄1.1 Redis簡介1.2 Redis下載與安裝1.2.1 Redis下載1.2.2 Redis安裝1.3 Redis服務啟動與停止1.3.1 服務啟動命令1.3.2 客戶端連接命令1.3.3 修改Redis配置文件1.3.4 Redis客戶端圖形工具2. Redis數據類型2.1 五種常用數據類型介紹2.2 各種數據類型特點3. Redis常用命令3.1 字…

雙指針:字符串

題目&#xff1a;字符串 題目概述&#xff1a;找包含所有小寫字母的最短字符串。 重點思路&#xff1a; right是 < len-1字符 - ‘26’轉換成整形再判斷&#xff08;寫字符a也可以&#xff0c;更準確&#xff09;。 #include <iostream> #include <algorithm>…

HarmonyOS 應用開發深度實踐:精通 Stage 模型與 UIAbility 生命周期

好的&#xff0c;請看這篇關于 HarmonyOS Stage 模型與 UIAbility 深度實踐的技術文章。 HarmonyOS 應用開發深度實踐&#xff1a;精通 Stage 模型與 UIAbility 生命周期 引言 隨著 HarmonyOS 4、5 的廣泛部署和 HarmonyOS NEXT (API 12) 的發布&#xff0c;華為的分布式操作系…

DEDECMS 小程序插件簡介 2.0全新上線

網上有很多的dedecms的小程序插件&#xff0c;但是有的依賴他們第三方、有的需要一定php或sql基礎、有的插件免費但是小程序源碼價格昂貴&#xff0c;這也是促使我開發dedecms小程序插件的一大原因。2025年9月4日 dedecms小程序插件2.0版本正式上線&#xff0c;由于使用人數減少…

Flink 1.17.2 集群安裝部署

Flink集群的安裝 1. 集群規劃 Ip host Server Note 192.168.10.101 node01 jobManager、TaskManagerRunner 老大和小弟服務 192.168.10.102 node02 TaskManagerRunner 小弟 192.168.10.103 node03 TaskManagerRunner 小弟 注意&#xff1a;本次使用jdk-1.8.0…

[vue.js] 樹形結點多選框選擇

vue.js前端代碼&#xff1a; <template><div><el-tree:data"treeData"node-key"id"show-checkboxref"tree"check-change"handleCheckChange"/><el-button click"getSelectedNodes">獲取選中的節點&…

Web 服務器基本工作流程

這是一個關于 ??Web 服務器基本工作流程?? 的全面解釋。我們以最經典的 ??客戶端-服務器-后端?? 三層架構為例&#xff0c;并結合你之前遇到的 Nginx 場景進行說明。??核心角色????客戶端 (Client)??&#xff1a; 通常是 ??Web 瀏覽器?? (Chrome, Firefox)…

IDEA 連接MySQL數據庫

一、 連接數據庫1、打開連接2、建立連接3、輸入用戶名和密碼二、操作數據庫1、選擇數據庫2、New| Query Console 查詢控制臺3、寫查詢語句4、New| SQL Script| sql Generator 生成這個數據庫表的SQL結構New | SQL Script | Generate DDL to Query Console 在查詢控制臺生成…

江協科技STM32課程筆記(二)—外部中斷EXTI

二、外部中斷EXTI中斷&#xff1a;在主程序運行過程中&#xff0c;出現了特定的中斷觸發條件&#xff08;中斷源&#xff09;&#xff0c;使得CPU暫停當前正在運行的程序&#xff0c;轉而去處理中斷程序&#xff0c;處理完成后又返回原來被暫停的位置繼續運行。1、stm32中斷簡介…

Java常見排序算法實現

以下是Java中幾種常見排序算法的實現&#xff0c;包括冒泡排序、選擇排序、插入排序、快速排序和歸并排序。 各排序算法特點說明&#xff1a;冒泡排序&#xff1a; 原理&#xff1a;重復比較相鄰元素&#xff0c;將大的元素逐步"冒泡"到數組末尾特點&#xff1a;穩定…